MergeDateLogHandle

Merge a date range into an existing date log with conflict resolution

Overview

MergeDateLogHandle merges a source date range into a destination date log, with support for conflict resolution based on specified flags. This is a high-level wrapper that manages synchronization, file I/O, and recovery operations for date log merge operations.

Purpose

This function enables consolidation of multiple date logs or date ranges into a single authoritative date log. It supports two merge strategies:

Key Features

Function Signature


            HRESULT _Must_inspect_result_ _Success_(SUCCEEDED(return)) MergeDateLogHandle(
                    _Inout_ _Pre_valid_  DATE_LOG_HANDLE hDestDateLog,
                    _In_  __readonly _Pre_valid_  DATE_RANGE_HANDLE hSourceDateLog,
                    _In_ DWORD dwFlags
            );
            

Calling Convention

Standard C calling convention with SAL annotations for parameter validation and return value inspection.

Parameters

hDestDateLog

[In, Out] DATE_LOG_HANDLE

Handle to the destination date log that will be modified with merged data.

  • Must be a valid DATE_LOG_HANDLE obtained from NewDateLogHandle()
  • Must have a valid context and associated holidays handle
  • Will be updated with merged date items on success
  • Precondition: Must be pre-validated and not NULL
hSourceDateLog

[In] DATE_RANGE_HANDLE

Read-only handle to the source date range to merge into the destination.

  • Must be a valid DATE_RANGE_HANDLE (immutable during operation)
  • Can represent a subset or complete date range
  • Must have a valid context with populated date items
  • Precondition: Must be pre-validated and not NULL
dwFlags

[In] DWORD

Flags controlling merge behavior and options. Exactly one conflict resolution flag is required:

Flag Value Description
DATE_RANGE_MERGE_FAVOR_DEST 0x04 Keep destination GUIDs in overlapping date range. When the same dates exist in both logs, the destination's UUID is preserved. This is useful when the destination is the authoritative source.
DATE_RANGE_MERGE_FAVOR_SOURCE 0x08 Replace destination GUIDs with source values in overlapping range. When the same dates exist in both logs, the source's UUID is used. This is useful when the source has more recent or preferred data.
DATE_RANGE_MERGE_RESTORE_ON_FAILURE 0x10 (Optional) Enable automatic recovery if merge fails. Requires destination file info to be present. Creates backup of original array and file regions before modifying. On failure, restores original state.
Flag Requirements:
  • Exactly one of DATE_RANGE_MERGE_FAVOR_DEST or DATE_RANGE_MERGE_FAVOR_SOURCE must be set
  • If neither flag is present, the function returns ERROR_INVALID_FLAGS
  • DATE_RANGE_MERGE_RESTORE_ON_FAILURE is optional and can be combined with either conflict resolution flag

Return Values

Success Cases

S_OK (0x00000000)

Merge operation completed successfully. Destination date log has been updated with merged data.

Error Cases

Validation Errors

ERR_INVALID_DATELOG_HANDLE

Either destination or source handle is invalid, not a date log/range, or context is NULL.

ERROR_INVALID_FLAGS (0x80070571)

Flags parameter is invalid. Neither DATE_RANGE_MERGE_FAVOR_DEST nor DATE_RANGE_MERGE_FAVOR_SOURCE was specified.

Synchronization Errors

ERR_DATE_LOG_PENDING_IO

Failed to acquire required mutex locks within 30-second timeout. Indicates another operation is holding locks or system is under resource contention.

HRESULT_FROM_WIN32(GetLastError())

Generic synchronization error from mutex or lock acquisition failure.

Memory and Resource Errors

ERROR_OUTOFMEMORY (0x80000002)

Failed to allocate memory for merge context or backup structures.

ERROR_INVALID_HANDLE (0x80070006)

Merge lock context allocation failed or internal handle validation failed.

Merge Operation Errors

See return codes from MergeDateLogCores() including:

ERROR_FILE_CORRUPT
ERR_DATELOG_ZERO_GAP
ERR_DATEITEM_NOT_FOUND
ERR_DATE_EARLIER_BASE
ERR_DATE_IS_FUTURE_DATE
ERR_MAX_DATELOG_REACHED

File I/O Errors

ERR_DATE_LOG_RESTORE_FAILED

Array or file restoration failed after merge failure. Destination context may be invalid.

ERR_DATE_FILE_RESTORE_FAILED

File region could not be restored from backup after failed merge.

Return Value Checking


            // Recommended error checking pattern
            HRESULT hr = MergeDateLogHandle(
                hDestLog, 
                hSourceLog, 
                DATE_RANGE_MERGE_FAVOR_SOURCE | DATE_RANGE_MERGE_RESTORE_ON_FAILURE
            );

            if (SUCCEEDED(hr)) {
                // Merge completed successfully
                printf("Merge successful\n");
            } else if (hr == ERR_DATE_LOG_PENDING_IO) {
                // Retry operation after delay
                printf("Merge in progress, retry later\n");
            } else {
                // Log error and handle gracefully
                printf("Merge failed: 0x%08X\n", hr);
            }

Behavior and Operations

Execution Flow

Validate Handles
Acquire Locks
Merge Cores
Update File
Release Locks

Lock Acquisition Strategy

The function uses consistent lock ordering to prevent deadlocks:

  1. Destination range mutex (30s timeout)
  2. Source range mutex (30s timeout)
  3. Destination context mutex (30s timeout)
  4. Source context mutex (30s timeout)
Deadlock Prevention: Locks are acquired in the same order and released in reverse order. This strict ordering prevents circular wait conditions between threads.

Merge Process

Once all locks are acquired:

  1. Allocate MERGE_LOCK_CONTEXT for tracking merge state
  2. Invoke MergeDateLogCores() to perform in-memory merge
  3. Update context state: set bHasChanged = TRUE
  4. If file info present: duplicate file handle and lock regions
  5. Update destination file with merged data via MergeDateLogFileInfo()
  6. Unlock file regions and clean up resources

File I/O Handling

If destination has associated file info (pDateRangeDest->pFileInfo is not NULL):

Recovery on Failure

If DATE_RANGE_MERGE_RESTORE_ON_FAILURE flag is set and merge/file update fails:

Resource Cleanup

In the __finally block: