LiteDB icon indicating copy to clipboard operation
LiteDB copied to clipboard

Recursive read lock acquisitions not allowed in this mode

Open animha opened this issue 4 years ago • 4 comments

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 avatar Jun 18 '20 10:06 animha

@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.

lbnascimento avatar Jun 18 '20 15:06 lbnascimento

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...

animha avatar Jun 18 '20 15:06 animha

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;
}

EqUiNoX-Labs avatar Aug 06 '23 23:08 EqUiNoX-Labs

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.

ElDuderinoBerlin avatar Sep 01 '23 18:09 ElDuderinoBerlin