internal static void Add(string fileName, SQLiteConnectionHandle handle, int version) { SQLiteConnectionPool.PoolQueue poolQueue; ISQLiteConnectionPool connectionPool = SQLiteConnectionPool.GetConnectionPool(); if (connectionPool != null) { connectionPool.Add(fileName, handle, version); return; } lock (SQLiteConnectionPool._syncRoot) { if (!SQLiteConnectionPool._queueList.TryGetValue(fileName, out poolQueue) || version != poolQueue.PoolVersion) { handle.Close(); } else { SQLiteConnectionPool.ResizePool(poolQueue, true); Queue <WeakReference> queue = poolQueue.Queue; if (queue != null) { queue.Enqueue(new WeakReference(handle, false)); Interlocked.Increment(ref SQLiteConnectionPool._poolClosed); } else { return; } } GC.KeepAlive(handle); } }
internal static void SetConnectionPool(ISQLiteConnectionPool connectionPool) { lock (SQLiteConnectionPool._syncRoot) { SQLiteConnectionPool._connectionPool = connectionPool; } }
static SQLiteConnectionPool() { SQLiteConnectionPool._syncRoot = new object(); SQLiteConnectionPool._connectionPool = null; SQLiteConnectionPool._queueList = new SortedList <string, SQLiteConnectionPool.PoolQueue>(StringComparer.OrdinalIgnoreCase); SQLiteConnectionPool._poolVersion = 1; SQLiteConnectionPool._poolOpened = 0; SQLiteConnectionPool._poolClosed = 0; }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Disposes of all pooled connections associated with the specified /// database file name. /// </summary> /// <param name="fileName"> /// The database file name. /// </param> internal static void ClearPool(string fileName) { ISQLiteConnectionPool connectionPool = GetConnectionPool(); if (connectionPool != null) { connectionPool.ClearPool(fileName); } else { lock (_syncRoot) { PoolQueue queue; if (_queueList.TryGetValue(fileName, out queue)) { queue.PoolVersion++; Queue <WeakReference> poolQueue = queue.Queue; if (poolQueue == null) { return; } while (poolQueue.Count > 0) { WeakReference connection = poolQueue.Dequeue(); if (connection == null) { continue; } SQLiteConnectionHandle handle = connection.Target as SQLiteConnectionHandle; if (handle != null) { handle.Dispose(); } GC.KeepAlive(handle); } } } } }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Adds a connection to the pool of those associated with the /// specified database file name. /// </summary> /// <param name="fileName"> /// The database file name. /// </param> /// <param name="handle"> /// The database connection handle. /// </param> /// <param name="version"> /// The connection pool version at the point the database connection /// handle was received from the connection pool. This is also the /// connection pool version that the database connection handle was /// created under. /// </param> internal static void Add( string fileName, SQLiteConnectionHandle handle, int version ) { ISQLiteConnectionPool connectionPool = GetConnectionPool(); if (connectionPool != null) { connectionPool.Add(fileName, handle, version); } else { lock (_syncRoot) { // // NOTE: If the queue does not exist in the pool, then it // must have been cleared sometime after the // connection was created. // PoolQueue queue; if (_queueList.TryGetValue(fileName, out queue) && (version == queue.PoolVersion)) { ResizePool(queue, true); Queue <WeakReference> poolQueue = queue.Queue; if (poolQueue == null) { return; } poolQueue.Enqueue(new WeakReference(handle, false)); Interlocked.Increment(ref _poolClosed); } else { handle.Close(); } GC.KeepAlive(handle); } } }
internal static void ClearAllPools() { ISQLiteConnectionPool connectionPool = SQLiteConnectionPool.GetConnectionPool(); if (connectionPool != null) { connectionPool.ClearAllPools(); return; } lock (SQLiteConnectionPool._syncRoot) { foreach (KeyValuePair <string, SQLiteConnectionPool.PoolQueue> keyValuePair in SQLiteConnectionPool._queueList) { if (keyValuePair.Value == null) { continue; } Queue <WeakReference> queue = keyValuePair.Value.Queue; while (queue.Count > 0) { WeakReference weakReference = queue.Dequeue(); if (weakReference == null) { continue; } SQLiteConnectionHandle target = weakReference.Target as SQLiteConnectionHandle; if (target != null) { target.Dispose(); } GC.KeepAlive(target); } if (SQLiteConnectionPool._poolVersion > keyValuePair.Value.PoolVersion) { continue; } SQLiteConnectionPool._poolVersion = keyValuePair.Value.PoolVersion + 1; } SQLiteConnectionPool._queueList.Clear(); } }
internal static void GetCounts(string fileName, ref Dictionary <string, int> counts, ref int openCount, ref int closeCount, ref int totalCount) { SQLiteConnectionPool.PoolQueue poolQueue; ISQLiteConnectionPool connectionPool = SQLiteConnectionPool.GetConnectionPool(); if (connectionPool != null) { connectionPool.GetCounts(fileName, ref counts, ref openCount, ref closeCount, ref totalCount); return; } lock (SQLiteConnectionPool._syncRoot) { openCount = SQLiteConnectionPool._poolOpened; closeCount = SQLiteConnectionPool._poolClosed; if (counts == null) { counts = new Dictionary <string, int>(StringComparer.OrdinalIgnoreCase); } if (fileName == null) { foreach (KeyValuePair <string, SQLiteConnectionPool.PoolQueue> keyValuePair in SQLiteConnectionPool._queueList) { if (keyValuePair.Value == null) { continue; } Queue <WeakReference> queue = keyValuePair.Value.Queue; int num = (queue != null ? queue.Count : 0); counts.Add(keyValuePair.Key, num); totalCount += num; } } else if (SQLiteConnectionPool._queueList.TryGetValue(fileName, out poolQueue)) { Queue <WeakReference> weakReferences = poolQueue.Queue; int num1 = (weakReferences != null ? weakReferences.Count : 0); counts.Add(fileName, num1); totalCount += num1; } } }
internal static void ClearPool(string fileName) { SQLiteConnectionPool.PoolQueue poolQueue; ISQLiteConnectionPool connectionPool = SQLiteConnectionPool.GetConnectionPool(); if (connectionPool != null) { connectionPool.ClearPool(fileName); return; } lock (SQLiteConnectionPool._syncRoot) { if (SQLiteConnectionPool._queueList.TryGetValue(fileName, out poolQueue)) { poolQueue.PoolVersion++; Queue <WeakReference> queue = poolQueue.Queue; if (queue != null) { while (queue.Count > 0) { WeakReference weakReference = queue.Dequeue(); if (weakReference == null) { continue; } SQLiteConnectionHandle target = weakReference.Target as SQLiteConnectionHandle; if (target != null) { target.Dispose(); } GC.KeepAlive(target); } } else { return; } } } }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Removes a connection from the pool of those associated with the /// specified database file name with the intent of using it to /// interact with the database. /// </summary> /// <param name="fileName"> /// The database file name. /// </param> /// <param name="maxPoolSize"> /// The new maximum size of the connection pool for the specified /// database file name. /// </param> /// <param name="version"> /// The connection pool version associated with the returned database /// connection handle, if any. /// </param> /// <returns> /// The database connection handle associated with the specified /// database file name or null if it cannot be obtained. /// </returns> internal static SQLiteConnectionHandle Remove( string fileName, int maxPoolSize, out int version ) { ISQLiteConnectionPool connectionPool = GetConnectionPool(); if (connectionPool != null) { return(connectionPool.Remove(fileName, maxPoolSize, out version) as SQLiteConnectionHandle); } else { int localVersion; Queue <WeakReference> poolQueue; // // NOTE: This lock cannot be held while checking the queue for // available connections because other methods of this // class are called from the GC finalizer thread and we // use the WaitForPendingFinalizers method (below). // Holding this lock while calling that method would // therefore result in a deadlock. Instead, this lock // is held only while a temporary copy of the queue is // created, and if necessary, when committing changes // back to that original queue prior to returning from // this method. // lock (_syncRoot) { PoolQueue queue; // // NOTE: Default to the highest pool version. // version = _poolVersion; // // NOTE: If we didn't find a pool for this file, create one // even though it will be empty. We have to do this // here because otherwise calling ClearPool() on the // file will not work for active connections that have // never seen the pool yet. // if (!_queueList.TryGetValue(fileName, out queue)) { queue = new PoolQueue(_poolVersion, maxPoolSize); _queueList.Add(fileName, queue); return(null); } // // NOTE: We found a pool for this file, so use its version // number. // version = localVersion = queue.PoolVersion; queue.MaxPoolSize = maxPoolSize; // // NOTE: Now, resize the pool to the new maximum size, if // necessary. // ResizePool(queue, false); // // NOTE: Try and get a pooled connection from the queue. // poolQueue = queue.Queue; if (poolQueue == null) { return(null); } // // NOTE: Temporarily tranfer the queue for this file into // a local variable. The queue for this file will // be modified and then committed back to the real // pool list (below) prior to returning from this // method. // _queueList.Remove(fileName); poolQueue = new Queue <WeakReference>(poolQueue); } try { while (poolQueue.Count > 0) { WeakReference connection = poolQueue.Dequeue(); if (connection == null) { continue; } SQLiteConnectionHandle handle = connection.Target as SQLiteConnectionHandle; if (handle == null) { continue; } // // BUGFIX: For ticket [996d13cd87], step #1. After // this point, make sure that the finalizer for // the connection handle just obtained from the // queue cannot START running (i.e. it may // still be pending but it will no longer start // after this point). // GC.SuppressFinalize(handle); try { // // BUGFIX: For ticket [996d13cd87], step #2. Now, // we must wait for all pending finalizers // which have STARTED running and have not // yet COMPLETED. This must be done just // in case the finalizer for the connection // handle just obtained from the queue has // STARTED running at some point before // SuppressFinalize was called on it. // // After this point, checking properties of // the connection handle (e.g. IsClosed) // should work reliably without having to // worry that they will (due to the // finalizer) change out from under us. // GC.WaitForPendingFinalizers(); // // BUGFIX: For ticket [996d13cd87], step #3. Next, // verify that the connection handle is // actually valid and [still?] not closed // prior to actually returning it to our // caller. // if (!handle.IsInvalid && !handle.IsClosed) { Interlocked.Increment(ref _poolOpened); return(handle); } } finally { // // BUGFIX: For ticket [996d13cd87], step #4. Next, // we must re-register the connection // handle for finalization now that we have // a strong reference to it (i.e. the // finalizer will not run at least until // the connection is subsequently closed). // GC.ReRegisterForFinalize(handle); } GC.KeepAlive(handle); } } finally { // // BUGFIX: For ticket [996d13cd87], step #5. Finally, // commit any changes to the pool/queue for this // database file. // lock (_syncRoot) { // // NOTE: We must check [again] if a pool exists for // this file because one may have been added // while the search for an available connection // was in progress (above). // PoolQueue queue; Queue <WeakReference> newPoolQueue; bool addPool; if (_queueList.TryGetValue(fileName, out queue)) { addPool = false; } else { addPool = true; queue = new PoolQueue(localVersion, maxPoolSize); } newPoolQueue = queue.Queue; while (poolQueue.Count > 0) { newPoolQueue.Enqueue(poolQueue.Dequeue()); } ResizePool(queue, false); if (addPool) { _queueList.Add(fileName, queue); } } } return(null); } }
/////////////////////////////////////////////////////////////////////// /// <summary> /// Disposes of all pooled connections. /// </summary> internal static void ClearAllPools() { ISQLiteConnectionPool connectionPool = GetConnectionPool(); if (connectionPool != null) { connectionPool.ClearAllPools(); } else { lock (_syncRoot) { foreach (KeyValuePair <string, PoolQueue> pair in _queueList) { if (pair.Value == null) { continue; } Queue <WeakReference> poolQueue = pair.Value.Queue; while (poolQueue.Count > 0) { WeakReference connection = poolQueue.Dequeue(); if (connection == null) { continue; } SQLiteConnectionHandle handle = connection.Target as SQLiteConnectionHandle; if (handle != null) { handle.Dispose(); } GC.KeepAlive(handle); } // // NOTE: Keep track of the highest revision so we can // go one higher when we are finished. // if (_poolVersion <= pair.Value.PoolVersion) { _poolVersion = pair.Value.PoolVersion + 1; } } // // NOTE: All pools are cleared and we have a new highest // version number to force all old version active // items to get discarded instead of going back to // the queue when they are closed. We can get away // with this because we have pumped up the pool // version out of range of all active connections, // so they will all get discarded when they try to // put themselves back into their pools. // _queueList.Clear(); } } }
/////////////////////////////////////////////////////////////////////// #region ISQLiteConnectionPool Members (Static, Non-Formal) /// <summary> /// Counts the number of pool entries matching the specified file name. /// </summary> /// <param name="fileName"> /// The file name to match or null to match all files. /// </param> /// <param name="counts"> /// The pool entry counts for each matching file. /// </param> /// <param name="openCount"> /// The total number of connections successfully opened from any pool. /// </param> /// <param name="closeCount"> /// The total number of connections successfully closed from any pool. /// </param> /// <param name="totalCount"> /// The total number of pool entries for all matching files. /// </param> internal static void GetCounts( string fileName, ref Dictionary <string, int> counts, ref int openCount, ref int closeCount, ref int totalCount ) { ISQLiteConnectionPool connectionPool = GetConnectionPool(); if (connectionPool != null) { connectionPool.GetCounts( fileName, ref counts, ref openCount, ref closeCount, ref totalCount); } else { lock (_syncRoot) { openCount = _poolOpened; closeCount = _poolClosed; if (counts == null) { counts = new Dictionary <string, int>( StringComparer.OrdinalIgnoreCase); } if (fileName != null) { PoolQueue queue; if (_queueList.TryGetValue(fileName, out queue)) { Queue <WeakReference> poolQueue = queue.Queue; int count = (poolQueue != null) ? poolQueue.Count : 0; counts.Add(fileName, count); totalCount += count; } } else { foreach (KeyValuePair <string, PoolQueue> pair in _queueList) { if (pair.Value == null) { continue; } Queue <WeakReference> poolQueue = pair.Value.Queue; int count = (poolQueue != null) ? poolQueue.Count : 0; counts.Add(pair.Key, count); totalCount += count; } } } } }
internal static SQLiteConnectionHandle Remove(string fileName, int maxPoolSize, out int version) { int num; Queue <WeakReference> queue; SQLiteConnectionPool.PoolQueue poolQueue; SQLiteConnectionPool.PoolQueue poolQueue1; bool flag; SQLiteConnectionHandle sQLiteConnectionHandle; ISQLiteConnectionPool connectionPool = SQLiteConnectionPool.GetConnectionPool(); if (connectionPool != null) { return(connectionPool.Remove(fileName, maxPoolSize, out version) as SQLiteConnectionHandle); } lock (SQLiteConnectionPool._syncRoot) { version = SQLiteConnectionPool._poolVersion; if (SQLiteConnectionPool._queueList.TryGetValue(fileName, out poolQueue)) { int poolVersion = poolQueue.PoolVersion; num = poolVersion; version = poolVersion; poolQueue.MaxPoolSize = maxPoolSize; SQLiteConnectionPool.ResizePool(poolQueue, false); queue = poolQueue.Queue; if (queue != null) { SQLiteConnectionPool._queueList.Remove(fileName); queue = new Queue <WeakReference>(queue); goto Label0; } else { sQLiteConnectionHandle = null; } } else { poolQueue = new SQLiteConnectionPool.PoolQueue(SQLiteConnectionPool._poolVersion, maxPoolSize); SQLiteConnectionPool._queueList.Add(fileName, poolQueue); sQLiteConnectionHandle = null; } } return(sQLiteConnectionHandle); Label0: try { while (queue.Count > 0) { WeakReference weakReference = queue.Dequeue(); if (weakReference == null) { continue; } SQLiteConnectionHandle target = weakReference.Target as SQLiteConnectionHandle; if (target == null) { continue; } GC.SuppressFinalize(target); try { GC.WaitForPendingFinalizers(); if (!target.IsInvalid && !target.IsClosed) { Interlocked.Increment(ref SQLiteConnectionPool._poolOpened); sQLiteConnectionHandle = target; return(sQLiteConnectionHandle); } } finally { GC.ReRegisterForFinalize(target); } GC.KeepAlive(target); } } finally { lock (SQLiteConnectionPool._syncRoot) { if (!SQLiteConnectionPool._queueList.TryGetValue(fileName, out poolQueue1)) { flag = true; poolQueue1 = new SQLiteConnectionPool.PoolQueue(num, maxPoolSize); } else { flag = false; } Queue <WeakReference> weakReferences = poolQueue1.Queue; while (queue.Count > 0) { weakReferences.Enqueue(queue.Dequeue()); } SQLiteConnectionPool.ResizePool(poolQueue1, false); if (flag) { SQLiteConnectionPool._queueList.Add(fileName, poolQueue1); } } } return(null); }
/////////////////////////////////////////////////////////////////////// /// <summary> /// This method is used to set the reference to the custom connection /// pool implementation to use, if any. /// </summary> /// <param name="connectionPool"> /// The custom connection pool implementation to use or null if the /// default connection pool implementation should be used. /// </param> internal static void SetConnectionPool( ISQLiteConnectionPool connectionPool ) { lock (_syncRoot) { _connectionPool = connectionPool; } }