/// <summary> /// Call to lock box increases lock /// </summary> /// <param name="wrappedConnection"></param> public SQLiteLockBox(LockableSQLiteConnection wrappedConnection) { this.m_connection = wrappedConnection; Monitor.Enter(this.m_connection.m_lockObject); #if DEBUG this.m_connection.m_claimedBy = Thread.CurrentThread.ManagedThreadId; #endif this.m_connection.m_lockCount++; this.m_connection.m_availableEvent.Reset(); }
/// <summary> /// Register connection /// </summary> private void RegisterConnection(LockableSQLiteConnection conn) { List <LockableSQLiteConnection> connections = this.GetOrRegisterConnections(conn.ConnectionString); lock (s_lockObject) { connections.Add(conn); this.m_connectionPool.Remove(conn); // Just in-case // Lock this connection so I know if I can bypass later Monitor.Enter(conn); this.m_tracer.TraceVerbose("++ {0} ({1})", conn.DatabasePath, connections.Count); } }
/// <summary> /// Get the specified connection from the pool or create one /// </summary> private LockableSQLiteConnection GetOrCreatePooledConnection(ConnectionString dataSource, bool isReadonly) { // Pool exists? var connectionPool = this.GetConnectionPool(dataSource.Name); // Get the platform ISQLitePlatform platform = ApplicationServiceContext.Current.GetService <ISQLitePlatform>(); // Try to lock global (make sure another process isn't hogging it) LockableSQLiteConnection retVal = null; if (isReadonly) // Readonly we can use any connection we like { retVal = connectionPool.GetEntered() ?? connectionPool.GetFree(); if (retVal == null) // Create a connection { retVal = new LockableSQLiteConnection(platform, dataSource, SQLiteOpenFlags.ReadOnly | SQLiteOpenFlags.FullMutex); retVal.Execute("PRAGMA synchronous = 1"); connectionPool.Add(retVal); //retVal.Wait(); } else { retVal.Wait(); // Wait for connection to become available } } else // We want write { retVal = connectionPool.GetWritable(); // Might be writable connection available if (retVal == null) { retVal = new LockableSQLiteConnection(platform, dataSource, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.FullMutex | SQLiteOpenFlags.Create); retVal.Execute("PRAGMA synchronous = 1"); retVal = connectionPool.AddUnique(retVal, o => !o.IsReadonly); retVal.Wait(); } else // Wait for the connection to become available { retVal.Wait(); } } return(retVal); }
/// <summary> /// Unregister connection /// </summary> private void UnregisterConnection(LockableSQLiteConnection conn) { List <LockableSQLiteConnection> connections = this.GetOrRegisterConnections(conn.ConnectionString); lock (s_lockObject) { Monitor.Exit(conn); connections.Remove(conn); // Add connection back onto the pool if (conn.Persistent) { this.m_connectionPool.Add(conn); } this.m_tracer.TraceVerbose("-- {0} ({1})", conn.DatabasePath, connections.Count); } }
/// <summary> /// Gets or sets the reset event for the particular database /// </summary> private ManualResetEventSlim GetOrRegisterResetEvent(LockableSQLiteConnection connection) { ManualResetEventSlim retVal = null; if (!this.m_connections.TryGetValue(connection.ConnectionString.Name, out retVal)) { retVal = new ManualResetEventSlim(true); lock (s_lockObject) if (!this.m_connections.ContainsKey(connection.ConnectionString.Name)) { this.m_connections.Add(connection.ConnectionString.Name, retVal); } else { retVal = this.m_connections[connection.ConnectionString.Name]; } } return(retVal); }
/// <summary> /// Get or create a pooled connection /// </summary> private LockableSQLiteConnection GetOrCreatePooledConnection(ConnectionString dataSource, bool isReadonly) { // First is there a connection already? var connections = this.GetOrRegisterConnections(dataSource); WriteableSQLiteConnection writeConnection = null; lock (s_lockObject) { if (this.m_writeConnections.TryGetValue(dataSource.Name, out writeConnection)) { if (Monitor.IsEntered(writeConnection)) { return(writeConnection); } } var conn = connections.FirstOrDefault(o => Monitor.IsEntered(o)); if (conn != null) { return(conn); } } ISQLitePlatform platform = ApplicationContext.Current.GetService <ISQLitePlatform>(); lock (s_lockObject) { LockableSQLiteConnection retVal = null; if (isReadonly) { retVal = this.m_connectionPool.OfType <ReadonlySQLiteConnection>().FirstOrDefault(o => o.ConnectionString.Name == dataSource.Name); } else { if (!this.m_writeConnections.TryGetValue(dataSource.Name, out writeConnection)) // Writeable connection can only have one in the pool so if it isn't there make sure it isn't in the current { writeConnection = new WriteableSQLiteConnection(platform, dataSource, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.FullMutex | SQLiteOpenFlags.Create) { Persistent = true }; writeConnection.Execute("PRAGMA synchronous = 1"); //writeConnection.Execute("PRAGMA automatic_index = true"); //writeConnection.Execute("PRAGMA journal_mode = WAL"); this.m_writeConnections.Add(dataSource.Name, writeConnection); } retVal = writeConnection; } // Remove return value if (retVal != null) { this.m_connectionPool.Remove(retVal); } else if (isReadonly) { retVal = new ReadonlySQLiteConnection(platform, dataSource, SQLiteOpenFlags.ReadOnly | SQLiteOpenFlags.FullMutex) { Persistent = true }; //retVal.Execute("PRAGMA threads = 2"); } else { throw new InvalidOperationException("Should not be here"); } return(retVal); } }