Reputation: 13521
Using SQLite, System.Data.SQLite and Dapper (in a Console Application; later Windows Service; high throughput); why "database is locked" is there anyway?
I even abstracted all calling to SQLite db in this method:
public static void LocalDbScope(Action<IDbConnection> action)
{
try
{
lock (DbLock)
{
using (var connection = Open(LocalStorageConnectionString))
{
action(connection);
}
}
}
catch (Exception xux)
{
ErrLog.Error(xux);
throw;
}
}
Turning on the memory-mapped option did not help either:
connection.Execute("PRAGMA wal_autocheckpoint=32; PRAGMA journal_size_limit = 2048;");
connection.Execute("PRAGMA mmap_size=" + GB);
And this is connection string:
var builder = new SQLiteConnectionStringBuilder
{
DataSource = storageDbFilePath,
FailIfMissing = false,
PageSize = 32 * KB,
CacheSize = 10 * MB,
ForeignKeys = false,
UseUTF16Encoding = false,
Pooling = true,
JournalMode = SQLiteJournalModeEnum.Wal,
SyncMode = SynchronizationModes.Normal,
DateTimeKind = DateTimeKind.Utc,
DateTimeFormat = SQLiteDateFormats.ISO8601,
DefaultIsolationLevel = IsolationLevel.ReadCommitted,
DefaultTimeout = (int)TimeSpan.FromMinutes(1).TotalMilliseconds
};
LocalStorageConnectionString = builder.ToString();
What am I missing here?
Note: When you google for "database is locked", all the top results (and whole first page) is about this problem in different programming languages and platforms. It seems there is something else about SQLite that I can not filter out of this picture.
Upvotes: 0
Views: 2031
Reputation: 8394
As stated in my comment, I have NO idea what-so-ever, is going on without seeing more of your code.
Still, if you are not willing to change Dapper to Sqlite-net, below is a small non-blocking example, using your abstraction, which is not throwing any exceptions. Hope it helps you figure it out.
using System;
using System.Data;
using System.Data.SQLite;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Dapper;
namespace MyConsoleApplication
{
public class Program
{
static void Main(string[] args)
{
var test = new TestSQLite();
test.GoForIt();
}
}
public class Entity
{
public int Id { get; set; }
public string Content { get; set; }
}
public class TestSQLite
{
private const string ConnectionString = "Data Source=sqlitetest.sqlite";
private static readonly object DbLock = new object();
public void GoForIt()
{
CreateTable();
var random = new Random();
for (int i = 0; i < 100; i++)
{
if ( i % 2 != 0)
{
Task.Factory.StartNew(() => Thread.Sleep(random.Next(0, 200))).ContinueWith(other =>
LocalDbScope(action =>
{
var entity = new Entity {Content = "hoax"};
entity.Id = action.Query<int>(
@"insert into entity (content) values (@Content); select last_insert_rowid()",
entity).First();
var ids = action.Query<int>(@"select id from entity").ToList();
Console.WriteLine("Inserted id:{0}, all ids:[{1}]", entity.Id, string.Join(",", ids));
}));
}
else
{
Task.Factory.StartNew(() => Thread.Sleep(random.Next(200, 500))).ContinueWith(other =>
LocalDbScope(action =>
{
action.Execute(@"delete from entity");
Console.WriteLine("Deleted all entities");
}));
}
}
Console.ReadLine();
}
public static void LocalDbScope(Action<IDbConnection> action)
{
lock (DbLock)
{
using (var connection = new SQLiteConnection(ConnectionString))
action(connection);
}
}
private static void CreateTable()
{
using (IDbConnection c = new SQLiteConnection(ConnectionString))
{
c.Execute(@"drop table if exists entity");
c.Execute(@"create table entity (id integer primary key autoincrement, content varchar(100))");
}
}
}
}
Upvotes: 1