diff --git a/Lite/Database/DuckDbInitializer.cs b/Lite/Database/DuckDbInitializer.cs index 953401fe..78b6a37f 100644 --- a/Lite/Database/DuckDbInitializer.cs +++ b/Lite/Database/DuckDbInitializer.cs @@ -27,10 +27,22 @@ public class DuckDbInitializer /// /// Acquires a read lock on the database. Multiple readers can hold this concurrently. /// Dispose the returned object to release the lock. + /// If the current thread already owns a read lock (e.g., leaked by an unhandled exception), + /// returns a no-op disposable to allow the operation to proceed. /// public IDisposable AcquireReadLock() { - s_dbLock.EnterReadLock(); + try + { + s_dbLock.EnterReadLock(); + } + catch (LockRecursionException) + { + /* The current thread already owns a read lock — likely leaked by an unhandled + exception that prevented Dispose(). Since we're already protected by a read lock, + return a no-op disposable so the caller can proceed normally. */ + return NoOpDisposable.Instance; + } return new LockReleaser(s_dbLock, write: false); } @@ -44,6 +56,12 @@ public IDisposable AcquireWriteLock() return new LockReleaser(s_dbLock, write: true); } + private sealed class NoOpDisposable : IDisposable + { + public static readonly NoOpDisposable Instance = new(); + public void Dispose() { } + } + private sealed class LockReleaser : IDisposable { private readonly ReaderWriterLockSlim _lock;