System.AccessViolationException when having parallel db writes using Devart.Data.SQLite.EFCore

System.AccessViolationException when having parallel db writes using Devart.Data.SQLite.EFCore

Hi,

I've observed and AccessViolationException  when running unit tests in parallel.
Investigating this I found out that creating multiple different databases, or even inserting new entities in a database, in parallel can cause this exception:

 Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

   at Devart.Data.SQLite.be.sqlite3_prepare_v2(IntPtr, IntPtr, Int32, IntPtr ByRef, IntPtr ByRef)
--------------------------------
   at Devart.Data.SQLite.br.a(System.String, UInt32, System.String ByRef)
   at Devart.Data.SQLite.bz.p()
   at Devart.Data.SQLite.bb.o()
   at Devart.Data.SQLite.bv.n()
   at Devart.Data.SQLite.bv.i()
   at Devart.Common.DbConnectionInternal.v()
   at Devart.Common.DbConnectionFactory.b(Devart.Common.DbConnectionBase)
   at Devart.Common.DbConnectionClosed.Open(Devart.Common.DbConnectionBase)
   at Devart.Common.DbConnectionBase.i()
   at Devart.Common.DbConnectionBase.Open()
   at Devart.Data.SQLite.SQLiteConnection.Open()
   at Devart.Common.Entity.cz.Open()
   at Devart.Data.SQLite.Entity.s.Open()
   at System.Data.Common.DbConnection.OpenAsync(System.Threading.CancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean, System.Threading.CancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection+<OpenInternalAsync>d__70.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Microsoft.EntityFrameworkCore.Storage.RelationalConnection+<OpenInternalAsync>d__70, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<OpenInternalAsync>d__70 ByRef)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[Microsoft.EntityFrameworkCore.Storage.RelationalConnection+<OpenInternalAsync>d__70, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<OpenInternalAsync>d__70 ByRef)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(Boolean, System.Threading.CancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection+<OpenAsync>d__66.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Microsoft.EntityFrameworkCore.Storage.RelationalConnection+<OpenAsync>d__66, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<OpenAsync>d__66 ByRef)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Boolean, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Start[[Microsoft.EntityFrameworkCore.Storage.RelationalConnection+<OpenAsync>d__66, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<OpenAsync>d__66 ByRef)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(System.Threading.CancellationToken, Boolean)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand+<ExecuteNonQueryAsync>d__14.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Microsoft.EntityFrameworkCore.Storage.RelationalCommand+<ExecuteNonQueryAsync>d__14, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<ExecuteNonQueryAsync>d__14 ByRef)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[[System.Int32, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].Start[[Microsoft.EntityFrameworkCore.Storage.RelationalCommand+<ExecuteNonQueryAsync>d__14, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<ExecuteNonQueryAsync>d__14 ByRef)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(Microsoft.EntityFrameworkCore.Storage.RelationalCommandParameterObject, System.Threading.CancellationToken)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator+<MigrateAsync>d__15.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator+<MigrateAsync>d__15, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<MigrateAsync>d__15 ByRef)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator+<MigrateAsync>d__15, Microsoft.EntityFrameworkCore.Relational, Version=8.0.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]](<MigrateAsync>d__15 ByRef)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(System.String, System.Threading.CancellationToken)
   at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.MigrateAsync(Microsoft.EntityFrameworkCore.Infrastructure.DatabaseFacade, System.Threading.CancellationToken)
   at Stratec.LiaisonXXL.Adapters.Database.Tests.SqliteFeaturesTests+<>c+<<MultipleDbMigrationOnMultipleThreadsTest>b__4_0>d.MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]](System.__Canon ByRef)
   at Stratec.LiaisonXXL.Adapters.Database.Tests.SqliteFeaturesTests+<>c.<MultipleDbMigrationOnMultipleThreadsTest>b__4_0(Stratec.LiaisonXXL.Adapters.Database.Tests.RealSqliteTestDbOptionsFactory, System.Threading.CancellationToken)
   at System.Threading.Tasks.Parallel+<>c__53`1+<<ForEachAsync>b__53_0>d[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
   at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[[System.Threading.Tasks.Parallel+<>c__53`1+<<ForEachAsync>b__53_0>d[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Threading.Tasks.Parallel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]](<<ForEachAsync>b__53_0>d<System.__Canon> ByRef)
   at System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[System.Threading.Tasks.Parallel+<>c__53`1+<<ForEachAsync>b__53_0>d[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Threading.Tasks.Parallel, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]](<<ForEachAsync>b__53_0>d<System.__Canon> ByRef)
   at System.Threading.Tasks.Parallel+<>c__53`1[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<ForEachAsync>b__53_0(System.Object)
   at System.Threading.Tasks.Parallel+ForEachAsyncState`1+<>c[[System.__Canon, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].<System.Threading.IThreadPoolWorkItem.Execute>b__18_0(System.Object)
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()
   at System.Threading.PortableThreadPool+WorkerThread.WorkerThreadStart()


A simple sample code to reproduce this looks like this:

await Parallel.ForEachAsync(
  entitiesToInsert,
  new ParallelOptions { MaxDegreeOfParallelism = 20},
  async (entityToInsert, ct) =>
  {
    using var dbContext = new DbContext(
      this.dbOptionsFactory.GetDbContextOptionsForTestDb<DbContext>());
    dbContext.Add(entityToInsert);
    await dbContext.SaveChangesAsync(ct);
  });

The db connection has Pooling enabled and JournalMode set to WAL. The exception doesn't always happen so it may be a concurrency issue.

Using the latest official sqlite.dll does not throw this exception but I have to use the dll provided with the dotconnect installation since I use the encryption functionality (as discussed here https://support.devart.com/portal/en/community/topic/sqlite-binaries-for-linux)


Cheers,
Paul