public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath) { faultInjector?.OnNewConnection(); // Allocate dictionary before doing any sqlite work. That way if it throws // we don't have to do any additional cleanup. var queryToStatement = new Dictionary <string, SqlStatement>(); // Use SQLITE_OPEN_NOMUTEX to enable multi-thread mode, where multiple connections can be used provided each // one is only used from a single thread at a time. // see https://sqlite.org/threadsafe.html for more detail var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX; var handle = NativeMethods.sqlite3_open_v2(databasePath, (int)flags, vfs: null, out var result); if (result != Result.OK) { handle.Dispose(); throw new SqlException(result, $"Could not open database file: {databasePath} ({result})"); } try { NativeMethods.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds); return(new SqlConnection(handle, faultInjector, queryToStatement)); } catch { // If we failed to create connection, ensure that we still release the sqlite // handle. handle.Dispose(); throw; } }
public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath) { faultInjector?.OnNewConnection(); // Allocate dictionary before doing any sqlite work. That way if it throws // we don't have to do any additional cleanup. var queryToStatement = new Dictionary <string, SqlStatement>(); // Use SQLITE_OPEN_NOMUTEX to enable multi-thread mode, where multiple connections can // be used provided each one is only used from a single thread at a time. // // Use SHAREDCACHE so that we can have an in-memory DB that we dump our writes into. We // need SHAREDCACHE so that all connections see that same in-memory DB. This also // requires OPEN_URI since we need a `file::memory:` uri for them all to refer to. // // see https://sqlite.org/threadsafe.html for more detail var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX | OpenFlags.SQLITE_OPEN_SHAREDCACHE | OpenFlags.SQLITE_OPEN_URI; var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null); if (result != Result.OK) { throw new SqlException(result, $"Could not open database file: {databasePath} ({result})"); } Contract.ThrowIfNull(handle); try { raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds); var connection = new SqlConnection(handle, faultInjector, queryToStatement); // Attach (creating if necessary) a singleton in-memory write cache to this connection. // // From: https://www.sqlite.org/sharedcache.html Enabling shared-cache for an in-memory // database allows two or more database connections in the same process to have access // to the same in-memory database. An in-memory database in shared cache is // automatically deleted and memory is reclaimed when the last connection to that // database closes. // // Using `cache=shared as writecache` at the end ensures all connections see the same db // and the same data when reading and writing. i.e. if one connection writes data to // this, another connection will see that data when reading. Without this, each // connection would get their own private memory db independent of all other // connections. connection.ExecuteCommand($"attach database 'file::memory:?cache=shared' as {Database.WriteCache.GetName()};"); return(connection); } catch { // If we failed to create connection, ensure that we still release the sqlite // handle. raw.sqlite3_close(handle); throw; } }
public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath) { faultInjector?.OnNewConnection(); var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE; var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null); if (result != Result.OK) { throw new SqlException(result, $"Could not open database file: {databasePath} ({result})"); } Contract.ThrowIfNull(handle); raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds); return(new SqlConnection(faultInjector, handle)); }
public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath) { faultInjector?.OnNewConnection(); // Enable shared cache so that multiple connections inside of same process share cache // see https://sqlite.org/threadsafe.html for more detail var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX | OpenFlags.SQLITE_OPEN_SHAREDCACHE; var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null); if (result != Result.OK) { throw new SqlException(result, $"Could not open database file: {databasePath} ({result})"); } Contract.ThrowIfNull(handle); raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds); return(new SqlConnection(faultInjector, handle)); }
public static SqlConnection Create(IPersistentStorageFaultInjector faultInjector, string databasePath) { faultInjector?.OnNewConnection(); // Use SQLITE_OPEN_NOMUTEX to enable multi-thread mode, where multiple connections can be used provided each // one is only used from a single thread at a time. // see https://sqlite.org/threadsafe.html for more detail var flags = OpenFlags.SQLITE_OPEN_CREATE | OpenFlags.SQLITE_OPEN_READWRITE | OpenFlags.SQLITE_OPEN_NOMUTEX; var result = (Result)raw.sqlite3_open_v2(databasePath, out var handle, (int)flags, vfs: null); if (result != Result.OK) { throw new SqlException(result, $"Could not open database file: {databasePath} ({result})"); } Contract.ThrowIfNull(handle); raw.sqlite3_busy_timeout(handle, (int)TimeSpan.FromMinutes(1).TotalMilliseconds); return(new SqlConnection(faultInjector, handle)); }