DuplicateDateLogHandle

Create an independent reference to an existing date log handle for concurrent thread access

Overview

DuplicateDateLogHandle creates a new DATE_LOG_HANDLE that references the same shared context as the source handle. This enables multiple threads to independently query and cache the last accessed date item without mutex contention. Each duplicated handle maintains its own cache but shares the underlying date collection, providing thread-safe concurrent access with minimal lock contention.

Purpose

This function is essential for multi-threaded applications that need concurrent read access to the same date collection. Rather than forcing all threads to compete for a single handle's resources, DuplicateDateLogHandle allows each thread to have its own handle with independent caches while sharing the underlying date data.

Key Features

Function Signature


                HRESULT  _Must_inspect_result_ _Success_(SUCCEEDED(return))DuplicateDateLogHandle(
                    _In_  DATE_LOG_HANDLE hSourceHandle,
                    _Out_ DATE_LOG_HANDLE * lpTargetHandle
                );
            

Calling Convention

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

Parameters

hSourceHandle

[In] DATE_LOG_HANDLE

The source date log handle to duplicate. Creates a new reference to the same underlying context.

  • Must be a valid handle created by InitializeDateLogHandle()
  • Can be any handle type: DateLog, DateRange, or Holidays
  • Source handle remains valid and unchanged
  • Can be from any thread that has valid access
  • Will be validated internally before duplication
lpTargetHandle

[Out] DATE_LOG_HANDLE*

Pointer to receive the newly created duplicate handle on success.

  • Must not be NULL
  • On success: receives new independent handle
  • On failure: receives NULL
  • Must be freed via FreeDateCollectionHandle()
  • New handle is completely independent (separate cache, own mutex)

Return Values

Success

S_OK (0x00000000)

Duplicate handle created successfully. lpTargetHandle contains the new handle pointer.

Validation Errors

ERROR_INVALID_HANDLE (0x80070006)

Source handle is invalid, corrupted, or being freed by another thread.

ERROR_INVALID_PARAMETER (0x80070057)

lpTargetHandle is NULL.

Resource Allocation Errors

ERROR_OUTOFMEMORY (0x80000002)

Insufficient memory to allocate new DATE_LOG structure or mutex.

GetLastError()

System error from mutex creation or file duplication. Wrapped as HRESULT.

Behavior and Operations

Duplication Process

  1. Validate source handle is valid and accessible
  2. Acquire source handle's mutex
  3. Allocate new DATE_LOG structure
  4. If file info attached: duplicate file info
  5. Copy context pointer (shared, not duplicated)
  6. Create independent mutex for new handle
  7. Increment reference count on shared context
  8. Release source handle's mutex
  9. Return new independent handle

Shared vs. Independent Resources

Shared Between Original and Duplicate

Independent Per Handle

Reference Counting

The duplication process increments the shared context's reference count:

Usage Examples

Example 1: Multi-threaded Date Queries

                    // Main thread: create and load date log
                    DATE_LOG_HANDLE hMainDateLog = NULL;
                    InitializeDateLogHandle(NULL, 0, hHolidays, &hMainDateLog, HandleIsForDatelog);
                    LoadDateLogHandle(pFile, NULL, NULL, hMainDateLog, NULL, 0);

                    // Worker threads can now duplicate the handle
                    for (int i = 0; i < 4; i++) {
                        DATE_LOG_HANDLE hDuplicate = NULL;
                        if (SUCCEEDED(DuplicateDateLogHandle(hMainDateLog, &hDuplicate))) {
                             // Each thread gets its own independent handle
                             CreateThread(NULL, 0, WorkerThreadProc, hDuplicate, 0, NULL);
                        }
                    }

                    // Worker thread function
                    DWORD WINAPI WorkerThreadProc(LPVOID lpParam) {
                    DATE_LOG_HANDLE hDateLog = (DATE_LOG_HANDLE)lpParam;

                    // Query dates without contending with other threads
                    for (int i = 0; i < 1000; i++) {
                        DATE_ITEM_HANDLE hDate = FindDateItemByGuid(hDateLog, &dateId);
                    }

                    // Each thread frees its own handle
                    FreeDateCollectionHandle(hDateLog);
                    return 0;
                    

                    FreeDateCollectionHandle(hMainDateLog);
                
Example 2: Error Handling

                    DATE_LOG_HANDLE hOriginal = /* valid handle */;
                    DATE_LOG_HANDLE hDuplicate = NULL;

                    HRESULT hr = DuplicateDateLogHandle(hOriginal, &hDuplicate);
                    if (hr == HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE)) {
                        printf("Source handle is invalid or being freed\n");
                    }
                    else if (hr == HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY)) {
                         printf("Insufficient memory to create duplicate\n");
                    }
                    else if (SUCCEEDED(hr)) {
                        printf("Duplicate handle created successfully\n");
                        FreeDateCollectionHandle(hDuplicate);
                    }

                    FreeDateCollectionHandle(hOriginal);
               

Performance Considerations

Benefits

Scalability

Important Notes

Reference Counting: The source handle remains valid after duplication. Both original and duplicate must be freed individually. Context is only freed when all handles are freed.
Mutual Exclusion During Freeing: If the source handle is being freed by another thread when duplication is attempted, ERROR_INVALID_HANDLE is returned.
Thread Affinity: Duplicated handles can be used across thread boundaries. It is safe to create a duplicate in one thread and pass it to another thread.
File Info Duplication: If the source handle has associated file info, it is also duplicated for the new handle, allowing independent file operations if needed.

Related Functions