Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ReaderWriterLockSlim to lock #2553

Open
wants to merge 1 commit into
base: v4
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 27 additions & 66 deletions LiteDB/Engine/Services/LockService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand All @@ -18,7 +18,7 @@ public class LockService
private IDiskService _disk;
private CacheService _cache;
private Logger _log;
private ReaderWriterLockSlim _thread = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
private readonly object thisLock = new object();

internal LockService(IDiskService disk, CacheService cache, TimeSpan timeout, Logger log)
{
Expand All @@ -28,18 +28,6 @@ internal LockService(IDiskService disk, CacheService cache, TimeSpan timeout, Lo
_timeout = timeout;
}

/// <summary>
/// Get current datafile lock state defined by thread only (do not check if datafile is locked)
/// </summary>
public LockState ThreadState
{
get
{
return _thread.IsWriteLockHeld ? LockState.Write :
_thread.CurrentReadCount > 0 ? LockState.Read : LockState.Unlocked;
}
}

/// <summary>
/// Get current thread id
/// </summary>
Expand All @@ -64,75 +52,48 @@ public int ThreadId
/// </summary>
public LockControl Read()
{
// if read or write
if (_thread.IsReadLockHeld || _thread.IsWriteLockHeld)
{
return new LockControl(false, () => { });
}

// try enter in read mode
if (!_thread.TryEnterReadLock(_timeout))
lock (thisLock)
{
throw LiteException.LockTimeout(_timeout);
}
_log.Write(Logger.LOCK, "entered in read lock mode in thread #{0}", this.ThreadId);

_log.Write(Logger.LOCK, "entered in read lock mode in thread #{0}", this.ThreadId);
// lock disk in shared mode
var position = _disk.Lock(LockState.Read, _timeout);

// lock disk in shared mode
var position = _disk.Lock(LockState.Read, _timeout);
var changed = this.DetectDatabaseChanges();

var changed = this.DetectDatabaseChanges();
return new LockControl(changed, () =>
{
// exit disk lock mode
_disk.Unlock(LockState.Read, position);

return new LockControl(changed, () =>
{
// exit disk lock mode
_disk.Unlock(LockState.Read, position);

// exit thread lock mode
_thread.ExitReadLock();

_log.Write(Logger.LOCK, "exited read lock mode in thread #{0}", this.ThreadId);
});
_log.Write(Logger.LOCK, "exited read lock mode in thread #{0}", this.ThreadId);
});
}
}

/// <summary>
/// Enter in Exclusive lock mode
/// </summary>
public LockControl Write()
{
// if already in exclusive, do nothing
if (_thread.IsWriteLockHeld)
{
return new LockControl(false, () => { });
}

// let's test if is not in read lock
if (_thread.IsReadLockHeld) throw new NotSupportedException("Not support Write lock inside a Read lock");

// try enter in write mode (thread)
if (!_thread.TryEnterWriteLock(_timeout))
lock (thisLock)
{
throw LiteException.LockTimeout(_timeout);
}

_log.Write(Logger.LOCK, "entered in write lock mode in thread #{0}", this.ThreadId);
_log.Write(Logger.LOCK, "entered in write lock mode in thread #{0}", this.ThreadId);

// try enter in exclusive mode in disk
var position = _disk.Lock(LockState.Write, _timeout);
// try enter in exclusive mode in disk
var position = _disk.Lock(LockState.Write, _timeout);

// call avoid dirty only if not came from a shared mode
var changed = this.DetectDatabaseChanges();
// call avoid dirty only if not came from a shared mode
var changed = this.DetectDatabaseChanges();

return new LockControl(changed, () =>
{
// release disk write
_disk.Unlock(LockState.Write, position);

// release thread write
_thread.ExitWriteLock();
return new LockControl(changed, () =>
{
// release disk write
_disk.Unlock(LockState.Write, position);

_log.Write(Logger.LOCK, "exited write lock mode in thread #{0}", this.ThreadId);
});
_log.Write(Logger.LOCK, "exited write lock mode in thread #{0}", this.ThreadId);
});
}
}

#endregion
Expand Down