Base de datos bloqueada en modo WAL con solo lectores

Usando System.Data.Sqlite 1.0.86.0 (incluyendo SQLite 3.7.17) enRegistro de escritura anticipada En este modo, estoy experimentando bloqueos en la base de datos mientras leo simultáneamente, lo cual no debería ser el caso si entiendo WAL correctamente. No estoy escribiendo ni cometiendo nada y laReadCommitted el modo de aislamiento de transacciones se utiliza correctamente para evitar la serialización de lecturas.

SQLite DB (con WAL) bloqueado al preparar una declaración "select": ¿por qué? Es un problema similar. La única respuesta habla de llamarsqlite3_reset después de cadasqlite3_step, que se realiza correctamente por System.Data.Sqlite hasta donde vi en el código fuente.

Reproducción completa:

internal static class Program {

    private const string DbFileName = "test.sqlite";
    private static readonly string _connectionString = BuildConnectionString(DbFileName);

    internal static void Main() {
        File.Delete(DbFileName);
        ExecuteSql("CREATE TABLE Test (Id INT NOT NULL, Name TEXT);", true);
        for (int i = 0; i < 10; i++)
            Task.Run(() => ExecuteSql("SELECT Id, Name FROM Test;", false));
        Console.ReadKey();
    }

    private static string BuildConnectionString(string fileName) {
        var builder = new SQLiteConnectionStringBuilder {
            DataSource = fileName,
            DateTimeFormat = SQLiteDateFormats.ISO8601,
            DefaultIsolationLevel = IsolationLevel.ReadCommitted,
            ForeignKeys = true,
            JournalMode = SQLiteJournalModeEnum.Wal,
            SyncMode = SynchronizationModes.Full
        };
        return builder.ToString();
    }

    private static void ExecuteSql(string sql, bool commit) {
        Stopwatch stopwatch = Stopwatch.StartNew();
        using (var connection = new SQLiteConnection(_connectionString)) {
            connection.Open();
            using (SQLiteTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted)) {
                using (SQLiteCommand command = connection.CreateCommand()) {
                    command.CommandText = sql;
                    command.ExecuteNonQuery();
                }
                if (commit)
                    transaction.Commit();
            }
        }
        stopwatch.Stop();
        Console.WriteLine("{0}: {1}", stopwatch.Elapsed, sql);
    }

}

Salida:

00:00:00.1927492: CREATE TABLE Test (Id INT NOT NULL, Name TEXT);
00:00:00.0054247: SELECT Id, Name FROM Test;
00:00:00.0055334: SELECT Id, Name FROM Test;
00:00:00.0056022: SELECT Id, Name FROM Test;
00:00:00.0054860: SELECT Id, Name FROM Test;
00:00:00.0053894: SELECT Id, Name FROM Test;
00:00:00.0056843: SELECT Id, Name FROM Test;
00:00:00.0006604: SELECT Id, Name FROM Test;
00:00:00.0006758: SELECT Id, Name FROM Test;
00:00:00.0097950: SELECT Id, Name FROM Test;
00:00:00.0980008: SELECT Id, Name FROM Test;

Puedes ver que el último es un orden de magnitud más lento. Si se ejecuta en modo de depuración, se registra lo siguiente en la ventana de salida una o más veces, dependiendo de la ejecución:

Error de SQLite (261): la base de datos está bloqueada

¿Tienes alguna idea de cómo evitar este bloqueo? Por supuesto, en esta muestra, WAL simplemente se puede desactivar, pero en un proyecto real no puedo: necesito escrituras potenciales para tener éxito inmediatamente, incluso si se está realizando una transacción de lectura larga.

Respuestas a la pregunta(1)

Su respuesta a la pregunta