CompareDateLogHandle

Compare two date log handles for underlying collection equality

Overview

CompareDateLogHandle determines whether two date log handles refer to equal underlying date log collections. It locks both handles (in a consistent pointer-value order to avoid deadlocks), compares their holidays handles (if applicable), compares file info, and compares the underlying DATE_LOG_CORE content.

Purpose

Lets callers verify that two handles (for example, one loaded from a file and one generated or merged in memory) describe the same date collection before deciding whether to rewrite, replace, or synchronize a backing store.

Key Features

Function Signature


BOOL _Check_return_ CompareDateLogHandle(
    _In_ DATE_LOG_HANDLE hDateLogHandle1,
    _In_ DATE_LOG_HANDLE hDateLogHandle2
);

Parameters

hDateLogHandle1

[In] DATE_LOG_HANDLE

The first handle to compare.

  • NULL: a NULL handle makes the function return FALSE
  • Type: handles with different magic numbers (for example a date log versus a range) never compare equal
  • Ownership: not retained or closed; the caller keeps ownership and must close it with CloseDateLogHandle
  • Lifetime: must remain valid, and must not be closed by another thread, for the duration of the call
hDateLogHandle2

[In] DATE_LOG_HANDLE

The second handle to compare.

  • NULL: a NULL handle makes the function return FALSE
  • Ownership/lifetime/type: same rules as hDateLogHandle1

Return Values

The function returns a BOOL. Because the function is marked _Check_return_, always use the result.

TRUE

Both handles refer to equal date log collections (same magic, same holidays, same file info, same core).

FALSE

The collections are not equal, an argument is NULL, the handles have different magic numbers, or a lock could not be acquired.

A FALSE result does not distinguish “not equal” from a lock or validation failure. If you need to know whether a handle is usable, validate it first with IsValidDateLogHandle.

Remarks

Thread Safety

Both handles are locked for the duration of the comparison. Locks are always acquired in ascending pointer-value order of the two handles to prevent deadlocks when the function is called concurrently with swapped arguments (for example, CompareDateLogHandle(a, b) on one thread and CompareDateLogHandle(b, a) on another).

Locks are always acquired in ascending pointer-value order of the two handles to prevent deadlocks when called concurrently with swapped arguments.

Handle Lifetime and Reference Counting

The function does not change reference counts. Handles created with DuplicateDateLogHandle share a single context with their source; each must still be released with CloseDateLogHandle.

Return Convention

The result is a BOOL (TRUE/FALSE), not an ordering. Unlike CompareDateItem and CompareFiletime, there is no negative/positive result, and the function cannot be used to sort date logs.

Sample Code

The example builds two date logs over the same range with a small helper, duplicates one of them, compares the combinations, and closes every handle it created.


#include <stdio.h>
#include "datelog.h"

/* BuildSampleDateLog is shown below; it creates a date log covering
   2024-01-02 through 2024-01-31. */

static HRESULT BuildSampleDateLog(HOLIDAYS_HANDLE hHolidays, DATE_LOG_HANDLE *phDateLog)
{
    DATE_LOG_HANDLE  hDateLog = NULL;
    DATE_ITEM_HANDLE hStart   = NULL;
    DATE_ITEM_HANDLE hEnd     = NULL;
    SYSTEMTIME       stStart  = { 0 };
    SYSTEMTIME       stEnd    = { 0 };
    FILETIME         ftStart  = { 0 };
    FILETIME         ftEnd    = { 0 };
    HRESULT          hr       = E_FAIL;

    *phDateLog = NULL;

    /* Tuesday 2 January 2024 through Wednesday 31 January 2024 (both market days). */
    stStart.wYear = 2024; stStart.wMonth = 1; stStart.wDay = 2;
    stEnd.wYear   = 2024; stEnd.wMonth   = 1; stEnd.wDay   = 31;
    if (!SystemTimeToFileTime(&stStart, &ftStart) || !SystemTimeToFileTime(&stEnd, &ftEnd)) {
        return HRESULT_FROM_WIN32(GetLastError());
    }

    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, hHolidays, &hDateLog, HandleIsForDatelog);
    if (FAILED(hr)) {
        return hr;
    }

    hr = InitializeDateItem(hDateLog, &ftStart, NULL, &hStart);
    if (SUCCEEDED(hr)) {
        hr = InitializeDateItem(hDateLog, &ftEnd, NULL, &hEnd);
    }
    if (SUCCEEDED(hr)) {
        /* No file context: generate the contiguous range between hStart and hEnd. */
        hr = LoadDateLogHandle(NULL, hStart, hEnd, hDateLog, NULL, 0);
    }

    FreeDateItem(hEnd);
    FreeDateItem(hStart);

    if (FAILED(hr)) {
        CloseDateLogHandle(hDateLog);
        return hr;
    }

    *phDateLog = hDateLog;
    return S_OK;
}

int main(void)
{
    HOLIDAYS_HANDLE hHolidays = NULL;
    DATE_LOG_HANDLE hLogA     = NULL;
    DATE_LOG_HANDLE hLogB     = NULL;
    DATE_LOG_HANDLE hLogDup   = NULL;
    HRESULT         hr        = E_FAIL;
    int             rc        = 1;

    /* Holidays handle. Populate it with your market holiday data (see
       LoadDateLogHandle) before building date logs; that step is application specific. */
    hr = InitializeDateLogHandle(NULL, DATE_LOG_MAX, NULL, &hHolidays, HandleIsForHolidays);
    if (FAILED(hr)) {
        printf("InitializeDateLogHandle failed for holidays: 0x%08lX\n", (unsigned long)hr);
        return 1;
    }

    hr = BuildSampleDateLog(hHolidays, &hLogA);
    if (FAILED(hr)) {
        printf("BuildSampleDateLog failed for A: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    hr = BuildSampleDateLog(hHolidays, &hLogB);
    if (FAILED(hr)) {
        printf("BuildSampleDateLog failed for B: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    hr = DuplicateDateLogHandle(hLogA, &hLogDup);
    if (FAILED(hr)) {
        printf("DuplicateDateLogHandle failed: 0x%08lX\n", (unsigned long)hr);
        goto cleanup;
    }

    /* Two logs built independently from the same range. The result also reflects
       the other compared properties (file info, core content). */
    if (CompareDateLogHandle(hLogA, hLogB)) {
        printf("A and B hold equal date log collections.\n");
    }
    else {
        printf("A and B are not equal (or could not be locked).\n");
    }

    /* A duplicate shares the same context as its source. */
    if (CompareDateLogHandle(hLogA, hLogDup)) {
        printf("A and its duplicate are equal.\n");
    }
    else {
        printf("A and its duplicate are not equal (or could not be locked).\n");
    }

    /* NULL arguments are not an error: the function simply returns FALSE. */
    if (!CompareDateLogHandle(hLogA, NULL)) {
        printf("Comparison with NULL returned FALSE as documented.\n");
    }

    rc = 0;

cleanup:
    if (hLogDup != NULL && FAILED(CloseDateLogHandle(hLogDup))) {
        rc = 1;
    }
    if (hLogB != NULL && FAILED(CloseDateLogHandle(hLogB))) {
        rc = 1;
    }
    if (hLogA != NULL && FAILED(CloseDateLogHandle(hLogA))) {
        rc = 1;
    }
    if (FAILED(CloseDateLogHandle(hHolidays))) {
        rc = 1;
    }
    return rc;
}

See Also