I am using System.Data.SQLite in .NET and encountering "database is locked" 
with wal using multiple threads from the same process running simple select 
statements with (separate) read-only connections. Please see the link below and 
note the Visual Studio output window when it runs.

https://drive.google.com/open?id=0By9M2uwoQgnKUnN6Z2NoWDZLS2s

Here is the bulk of the code in case more helpful than the download:

    class Program
    {
        /// <summary>
        /// Configure for x64 and hit F5 in Visual Studio
        /// Check the output window and note "database is locked"
        /// </summary>
        /// <param name="args"></param>
        static void Main(string[] args)
        {
            // the db file was copied to bin
            // note: the db was last opened with wal
            var dbPath = new 
FileInfo(Assembly.GetExecutingAssembly().Location).Directory.FullName;
            var dbFile = Path.Combine(dbPath, "Simple.db3");

            var csb = new SQLiteConnectionStringBuilder();
            csb.DataSource = dbFile;
            csb.ReadOnly = true;
            var connStr = csb.ConnectionString;

            RunTest(connStr);
        }

        private static void RunTest(string connStr)
        {
            var f1 = Task.Factory.StartNew(() => DoReadTest(connStr), 
TaskCreationOptions.LongRunning);
            var f2 = Task.Factory.StartNew(() => DoReadTest(connStr), 
TaskCreationOptions.LongRunning);
            var f3 = Task.Factory.StartNew(() => DoReadTest(connStr), 
TaskCreationOptions.LongRunning);
            var f4 = Task.Factory.StartNew(() => DoReadTest(connStr), 
TaskCreationOptions.LongRunning);
            Task.WaitAll(new List<Task> { f1, f2, f3, f4 }.ToArray());
        }

        private static void DoReadTest(string connStr)
        {
            var untilTime = DateTime.UtcNow.AddSeconds(10);

            int numRuns = 0;
            long totalMS = 0;

            // hammer the db with reads
            do
            {
                var sw = new Stopwatch();
                sw.Start();

                ReadTestWorker(connStr);

                numRuns++;
                totalMS += sw.ElapsedMilliseconds;

            } while (DateTime.UtcNow < untilTime);

            Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId} 
avg ms: { totalMS / numRuns }, Total runs {numRuns }");
        }

        private static void ReadTestWorker(string connStr)
        {
            const string sql = "SELECT MAX(Id) AS MaxId FROM TestTable;";

            using (var connection = new SQLiteConnection(connStr))
            {
                connection.Open();

                using (var cmd = connection.CreateCommand())
                {
                    cmd.CommandText = sql;
                    using (var reader = cmd.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            var msg = $"Thread 
{Thread.CurrentThread.ManagedThreadId} says max id is : {reader[0]}";
                            //Console.WriteLine(msg);
                        }
                    }
                }
            }
        }

    }

Thank you,

Vince

Reply via email to