Skip to content

DuckDB ReaderWriterLockSlim not resilient to unhandled exceptions #423

@erikdarlingdata

Description

@erikdarlingdata

Problem

The ReaderWriterLockSlim in DuckDbInitializer.cs uses LockRecursionPolicy.NoRecursion. If an unhandled exception on the UI thread interrupts code that holds a read lock (preventing Dispose() / ExitReadLock() from running), the thread permanently owns a leaked read lock. Every subsequent EnterReadLock() on that thread throws LockRecursionException:

Recursive read lock acquisitions not allowed in this mode.

This manifests as the Overview tab failing to load server summaries every 30 seconds, permanently, until the app is restarted.

Root Cause

The ReaderWriterLockSlim is thread-affine and configured with NoRecursion. When an unhandled WPF crash (see #422) fires on the UI thread while a read lock is held, the lock is never released. The UI thread then permanently "owns" a phantom read lock, and any new EnterReadLock() on that thread throws.

Fix

Add resilience to AcquireReadLock():

  • Use TryEnterReadLock() with a timeout instead of EnterReadLock()
  • Catch LockRecursionException — if the thread already owns a read lock, proceed without acquiring another (the lock is already held, so the protection is already in place)
  • This makes the lock self-healing: even if a previous crash leaked the lock, subsequent operations recover gracefully

Why not switch to SemaphoreSlim?

The ReaderWriterLockSlim has been working correctly since PR #218 (Feb 21). The locking design is sound — the only failure mode is leaked locks from unhandled exceptions. Adding resilience to the existing mechanism is lower risk than replacing the synchronization primitive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions