Skip to content

Commit

Permalink
Support exclusive lock under shared lock
Browse files Browse the repository at this point in the history
  • Loading branch information
mbdavid committed Jul 2, 2017
1 parent cb53709 commit 34e8a79
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 17 deletions.
31 changes: 28 additions & 3 deletions LiteDB/Engine/Disks/FileDiskService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,19 @@ public void Lock(LockState state, TimeSpan timeout)
var length = state == LockState.Shared ? 1 : LOCK_SHARED_LENGTH;

_log.Write(Logger.LOCK, "locking file in {0} mode (position: {1}, length: {2})", state.ToString().ToLower(), position, length);

_stream.TryLock(position, length, timeout);

if (state == LockState.Exclusive && _lockSharedPosition > 0)
{
var beforeLength = _lockSharedPosition - LOCK_POSITION;
var afterLength = LOCK_SHARED_LENGTH - beforeLength - 1;

_stream.TryLock(LOCK_POSITION, beforeLength, timeout);
_stream.TryLock(_lockSharedPosition + 1, afterLength, timeout);
}
else
{
_stream.TryLock(position, length, timeout);
}
#endif
}

Expand All @@ -270,7 +281,21 @@ public void Unlock(LockState state)

_log.Write(Logger.LOCK, "unlocking file in {0} mode (position: {1}, length: {2})", state.ToString().ToLower(), position, length);

_stream.TryUnlock(position, length);
// if unlock exclusive but contains position of shared lock, keep shared
if (state == LockState.Exclusive && _lockSharedPosition != 0)
{
var beforeLength = _lockSharedPosition - LOCK_POSITION;
var afterLength = LOCK_SHARED_LENGTH - beforeLength - 1;

_stream.TryUnlock(LOCK_POSITION, beforeLength);
_stream.TryUnlock(_lockSharedPosition + 1, afterLength);
}
else
{
_stream.TryUnlock(position, length);

_lockSharedPosition = 0;
}
#endif
}

Expand Down
13 changes: 3 additions & 10 deletions LiteDB/Engine/Engine/Find.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ public IEnumerable<BsonDocument> Find(string collection, Query query, int skip =
if (collection.IsNullOrWhiteSpace()) throw new ArgumentNullException("collection");
if (query == null) throw new ArgumentNullException("query");

var docs = new List<BsonDocument>(bufferSize);

using (_locker.Shared())
{
// get my collection page
Expand Down Expand Up @@ -48,15 +46,10 @@ public IEnumerable<BsonDocument> Find(string collection, Query query, int skip =
buffer = _data.Read(node.DataBlock);
doc = BsonSerializer.Deserialize(buffer).AsDocument;

docs.Add(doc);
}
}
yield return doc;

foreach(var doc in docs)
{
yield return doc;

_trans.CheckPoint();
_trans.CheckPoint();
}
}
}

Expand Down
25 changes: 21 additions & 4 deletions LiteDB/Engine/Services/LockService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,11 @@ public LockControl Exclusive()
return new LockControl(() => { });
}

// if are locked in shared, exit read to enter in write
if (_state == LockState.Shared) throw new NotSupportedException("Lock are in exclusive mode");
// test if came from a shared lock (to restore after unlock)
var shared = _state == LockState.Shared;

// if came, need exit read lock
if (shared) _thread.ExitReadLock();

// try enter in write mode (thread)
if (!_thread.TryEnterWriteLock(_timeout))
Expand All @@ -111,7 +114,11 @@ public LockControl Exclusive()

_log.Write(Logger.LOCK, "entered in exclusive lock mode");

this.AvoidDirtyRead();
// call avoid dirty only if not came from a shared mode
if (!shared)
{
this.AvoidDirtyRead();
}

_state = LockState.Exclusive;

Expand All @@ -120,10 +127,20 @@ public LockControl Exclusive()
// release thread write
_thread.ExitWriteLock();

//
if (shared)
{
_thread.TryEnterReadLock(_timeout);
_state = LockState.Shared;
}

// release disk exclusive
_disk.Unlock(LockState.Exclusive);

_state = LockState.Unlocked;
if (!shared)
{
_state = LockState.Unlocked;
}
});
}
}
Expand Down
4 changes: 4 additions & 0 deletions LiteDB/Utils/Extensions/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public static void CopyTo(this Stream input, Stream output)
/// </summary>
public static bool TryUnlock(this FileStream stream, long position, long length)
{
if (length == 0) return true;

try
{
#if NET35
Expand All @@ -53,6 +55,8 @@ public static bool TryUnlock(this FileStream stream, long position, long length)
/// </summary>
public static void TryLock(this FileStream stream, long position, long length, TimeSpan timeout)
{
if (length == 0) return;

FileHelper.TryExec(() =>
{
#if NET35
Expand Down
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
# TODO - next major version

- Remove transactions
- Remove auto-create index
- Add full scan when no index
- think about how/when create indexes defined by [Attributes] of FluentApi
- cache results in query
- findAndModify



# LiteDB - A .NET NoSQL Document Store in a single data file

[![Join the chat at https://gitter.im/mbdavid/LiteDB](https://badges.gitter.im/mbdavid/LiteDB.svg)](https://gitter.im/mbdavid/LiteDB?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build status](https://ci.appveyor.com/api/projects/status/sfe8he0vik18m033?svg=true)](https://ci.appveyor.com/project/mbdavid/litedb) [![Build Status](https://travis-ci.org/mbdavid/LiteDB.svg?branch=master)](https://travis-ci.org/mbdavid/LiteDB)
Expand Down

0 comments on commit 34e8a79

Please sign in to comment.