LiteDB
LiteDB copied to clipboard
Recursive read lock acquisitions not allowed in this mode
Hello, I'm developing an application in Xamarin.Forms and I started using LiteDb in substitution to SqlLite, and I really love it!
There is still something that is not clear to me when we speak about thread-safe.
As suggested I'm using a unique static instance of DbLite in my application for all requests.
I have the main thread that presents the interface where the user can Insert and Update items that I store in the local db. In a background task (that runs in a System.Threading.Timer) I launch a syncronization that sends the data to the remote server. It reads from local db, sends to remote, then changes a boolean property "Sent" in the item and Upsert the item in the local db.
Of course I could have a concurrent access to the db by both the main and the background tasks.
I'm getting random errors of type: ":"System.Threading.LockRecursionException","Message":"Recursive read lock acquisitions not allowed in this mode." They are caused by: System.Threading.ReaderWriterLockSlim.TryEnterReadLock Which is called by: LiteDB.Engine.LockService.EnterTransaction()
The only static instance of LiteDb is created like this: var db = new LiteDbExt($"Filename={path}")
Did I, by chance, misunderstand something in how I must manage concurrency in LiteDb? Your help would be really appreciated.
Animha
PS: you really made a good good job with LiteDb!!
@animha There was an issue (#1712) opened recently regarding the same problem. I have not been able to reproduce the issue, and I don't know why it's happening. It should not happen, given that LiteDB does not use recursive locks.
I believe the author of that issue worked around the problem by retrying whenever an operation threw a LockRecursionException
.
I tried to create a basic application with several timers that do cross-thread operations on the same DB, like I do in my real application. I was not able to reproduce the issue in Windows Forms. I suppose it is somehow linked to Xamarin.Forms platform, or maybe even an Android specific issue...
I am able to reproduce if i have a method using parallel for to insert items into a collection.
at System.Threading.ReaderWriterLockSlim.TryEnterReadLock(TimeSpan timeout)
at LiteDB.Engine.LockService.EnterTransaction()
at LiteDB.Engine.TransactionMonitor.GetTransaction(Boolean create, Boolean queryOnly, Boolean& isNew)
at LiteDB.Engine.QueryExecutor.ExecuteQuery(Boolean executionPlan)
at LiteDB.Engine.QueryExecutor.ExecuteQuery()
at LiteDB.Engine.LiteEngine.Query(String collection, Query query)
at LiteDB.LiteQueryable`1.ToDocuments()+MoveNext()
at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
at LiteDB.LiteCollection`1.FindOne(BsonExpression predicate)
at LiteDB.LiteCollection`1.FindOne(Expression`1 predicate)
at NetISOServerRedux.ContentManager.<>c__DisplayClass11_0.<ScanContent>b__1(String file) in D:\Git\NetISOServer\NetISOServerRedux\ContentManager.cs:line 68
The offending line in my code is...
if (Database.GetInstance().GetContentItems().FindOne(x => x.Path.Equals(file)) != null)
{
return;
}
When using collections/enumerables just use a ToList() circumventing the problem by making a full copy. Looks like there is a thread synchronisation problem with the enumerator.