Convert and verify a DATE_RANGE_HANDLE back to a DATE_LOG_HANDLE
ConvertToDateLogHandle verifies and converts a DATE_RANGE_HANDLE back to a DATE_LOG_HANDLE by performing comprehensive validation of the backing file and its contents. This function is typically called as the final step of a merge operation to ensure data integrity before the handle is ready for production use.
After merging date ranges into a date log using MergeDateLogHandle(), the destination handle remains in the "range" state (with magic __RANGE_LOG_MAGIC__) until this function successfully converts it to the "log" state (__DATE_LOG_MAGIC__). The conversion involves:
HRESULT _Must_inspect_result_ _Success_(SUCCEEDED(return)) ConvertToDateLogHandle(
_Inout_ _Pre_valid_ DATE_RANGE_HANDLE hDateRangeHandle,
_In_opt_ DATE_ITEM_HANDLE hLastDate
);
Standard C calling convention with SAL annotations indicating the function requires result inspection and modifies the handle in-place on success.
[In, Out] DATE_RANGE_HANDLE
Handle to a DATE_RANGE that will be converted to a DATE_LOG_HANDLE.
HandleIsForRange type[In, Optional] DATE_ITEM_HANDLE
Optional reference date item that must be present in the re-parsed file contents.
The DATE_RANGE_HANDLE was successfully converted to a DATE_LOG_HANDLE. The magic number has been updated to __DATE_LOG_MAGIC__ and the handle is now ready for use as a date log. All verification checks passed, including the optional last date verification if hLastDate was provided.
The provided handle is not a valid DATE_RANGE_HANDLE or the file information is invalid. The handle magic number is incorrect for this operation.
Multiple failure scenarios:
System error from mutex acquisition. May indicate deadlock or resource exhaustion.
See return codes from ParseDateLogFiles() and InitializeDateLogHandle() including:
// Recommended error checking pattern
HRESULT hr = ConvertToDateLogHandle(hDateRange, hLastDate);
if (SUCCEEDED(hr)) {
// Conversion successful - handle is now a DATE_LOG_HANDLE
printf("Range successfully converted to log\n");
// Now safe to use as DATE_LOG_HANDLE
} else if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE)) {
// Last date verification failed or handle invalid
printf("Conversion failed: handle or date verification failed\n");
// Handle remains as DATE_RANGE_HANDLE
} else {
// Other error - investigate
printf("Conversion failed: 0x%08X\n", hr);
}
IsValidDateRangeHandle()IsValidFileInfo()Acquires two mutexes in this order:
pDateLog->hMutex with INFINITE timeoutpDateLog->pContext->hMutex with INFINITE timeoutInitializeDateLogHandle() with same configurationParseDateLogFiles() with PARSE_VERIFY_ENABLE_FLAGSearchDateItem()pDateLog->pContext->dwMagic = __DATE_LOG_MAGIC__CloseDateLogHandle()
The function uses structured exception handling (__try/__finally) to ensure mutexes are released even if verification fails:
BOOL bHandleMutex = FALSE;
BOOL bContextMutex = FALSE;
// Acquire handle mutex first
dwWaitResult = WaitForSingleObject(pDateLog->hMutex, INFINITE);
if (dwWaitResult != WAIT_OBJECT_0) {
return HRESULT_FROM_WIN32(GetLastError());
}
bHandleMutex = TRUE;
__try {
// Acquire context mutex
dwWaitResult = WaitForSingleObject(pDateLog->pContext->hMutex, INFINITE);
if (dwWaitResult != WAIT_OBJECT_0) {
hr = HRESULT_FROM_WIN32(GetLastError());
__leave;
}
bContextMutex = TRUE;
// ... perform verification ...
} __finally {
// Always release in reverse order
if (bContextMutex) {
ReleaseMutex(pDateLog->pContext->hMutex);
}
if (bHandleMutex) {
ReleaseMutex(pDateLog->hMutex);
}
}
| Strategy | Implementation |
|---|---|
| Consistent Lock Ordering | Always acquire handle mutex before context mutex |
| Reverse Release Order | Release context mutex before handle mutex |
| Exception Safety | Use __finally to ensure release even on error |
| Single Lock Timeout | INFINITE timeout allows completion without false timeouts |
The temporary handle created during verification is completely isolated from the original range handle:
// Merge source range into destination log
DATE_LOG_HANDLE hDestLog = NULL;
DATE_RANGE_HANDLE hSourceRange = NULL;
// ... initialize and populate handles ...
// Perform merge operation
HRESULT hr = MergeDateLogHandle(
hDestLog,
hSourceRange,
DATE_RANGE_MERGE_FAVOR_DEST
);
if (SUCCEEDED(hr)) {
// After merge, destination is still in RANGE state
// Get the last date to verify
DATE_ITEM_HANDLE hLastDate = GetDateLogLastDate(hDestLog);
// Convert to LOG state with verification
hr = ConvertToDateLogHandle(
(DATE_RANGE_HANDLE)hDestLog,
hLastDate
);
if (SUCCEEDED(hr)) {
// Now safe to use as DATE_LOG_HANDLE for database insertion
printf("Merge complete and verified\n");
} else {
printf("Verification failed, data integrity issue\n");
}
if (hLastDate) {
FreeDateItem(hLastDate);
}
}
// Convert range to log without verifying a specific date
// This skips the SearchDateItem verification step
HRESULT hr = ConvertToDateLogHandle(
hDateRange,
NULL // No specific date to verify
);
if (SUCCEEDED(hr)) {
// File was re-parsed successfully
// Range is now converted to LOG state
} else {
// File parsing failed
// Range remains unconverted
}
DATE_RANGE_HANDLE hRange = NULL;
HRESULT hr = S_OK;
int retryCount = 0;
const int MAX_RETRIES = 3;
while (retryCount < MAX_RETRIES) {
DATE_ITEM_HANDLE hLastDate = GetDateLogLastDate(hRange);
hr = ConvertToDateLogHandle(hRange, hLastDate);
if (SUCCEEDED(hr)) {
printf("Conversion successful on attempt %d\n", retryCount + 1);
break;
}
if (hLastDate) {
FreeDateItem(hLastDate);
}
retryCount++;
if (retryCount < MAX_RETRIES) {
printf("Conversion failed, retrying (%d/%d)...\n", retryCount, MAX_RETRIES);
Sleep(100); // Brief delay before retry
}
}
if (FAILED(hr)) {
printf("Conversion failed after %d attempts\n", MAX_RETRIES);
}
The re-parsing of the backing file serves two purposes:
The temporary handle created during verification is automatically cleaned up via CloseDateLogHandle(). If cleanup fails:
Provide the hLastDate parameter in these scenarios:
Set hLastDate to NULL when:
| Before Conversion | After Successful Conversion | After Failed Conversion |
|---|---|---|
| Magic: __RANGE_LOG_MAGIC__ | Magic: __DATE_LOG_MAGIC__ | Magic: __RANGE_LOG_MAGIC__ (unchanged) |
| Can only use with MergeDateLogHandle | Can use as DATE_LOG_HANDLE | Must retry or free the handle |