Index: System.Data.SQLite/SQLiteConnection.cs ================================================================== --- System.Data.SQLite/SQLiteConnection.cs +++ System.Data.SQLite/SQLiteConnection.cs @@ -194,11 +194,18 @@ /// N /// Y /// /// /// Pooling - /// True - Use connection pooling
False - Do not use connection pooling
+ /// + /// True - Use connection pooling.
+ /// False - Do not use connection pooling.

+ /// WARNING: Setting this property to True should be avoided by + /// applications that make use of WPF (either directly or indirectly) due + /// to possible deadlocks that can occur during the finalization of some + /// WPF objects. + ///
/// N /// False ///
/// /// FailIfMissing @@ -1165,11 +1172,18 @@ /// N /// Y /// /// /// Pooling - /// True - Use connection pooling
False - Do not use connection pooling
+ /// + /// True - Use connection pooling.
+ /// False - Do not use connection pooling.

+ /// WARNING: Setting this property to True should be avoided by + /// applications that make use of WPF (either directly or indirectly) due + /// to possible deadlocks that can occur during the finalization of some + /// WPF objects. + ///
/// N /// False ///
/// /// FailIfMissing Index: System.Data.SQLite/SQLiteConnectionPool.cs ================================================================== --- System.Data.SQLite/SQLiteConnectionPool.cs +++ System.Data.SQLite/SQLiteConnectionPool.cs @@ -1,45 +1,50 @@ -/******************************************************** - * ADO.NET 2.0 Data Provider for SQLite Version 3.X - * Written by Robert Simpson (robert@blackcastlesoft.com) - * - * Released to the public domain, use at your own risk! - ********************************************************/ - -namespace System.Data.SQLite -{ - using System; +/******************************************************** + * ADO.NET 2.0 Data Provider for SQLite Version 3.X + * Written by Robert Simpson (robert@blackcastlesoft.com) + * + * Released to the public domain, use at your own risk! + ********************************************************/ + +namespace System.Data.SQLite +{ + using System; using System.Collections.Generic; - using System.Threading; - - internal static class SQLiteConnectionPool - { - /// - /// Keeps track of connections made on a specified file. The PoolVersion dictates whether old objects get - /// returned to the pool or discarded when no longer in use. - /// - internal class Pool - { - internal readonly Queue Queue = new Queue(); - internal int PoolVersion; - internal int MaxPoolSize; - - internal Pool(int version, int maxSize) - { - PoolVersion = version; - MaxPoolSize = maxSize; - } - } - - /// - /// The connection pool object - /// - private static SortedList _connections = new SortedList(StringComparer.OrdinalIgnoreCase); - - /// - /// The default version number new pools will get - /// + using System.Threading; + + /// + /// This class should not be used by applications that make use of WPF + /// (either directly or indirectly) due to possible deadlocks that can occur + /// during finalization of some WPF objects. + /// + internal static class SQLiteConnectionPool + { + /// + /// Keeps track of connections made on a specified file. The PoolVersion dictates whether old objects get + /// returned to the pool or discarded when no longer in use. + /// + internal class Pool + { + internal readonly Queue Queue = new Queue(); + internal int PoolVersion; + internal int MaxPoolSize; + + internal Pool(int version, int maxSize) + { + PoolVersion = version; + MaxPoolSize = maxSize; + } + } + + /// + /// The connection pool object + /// + private static SortedList _connections = new SortedList(StringComparer.OrdinalIgnoreCase); + + /// + /// The default version number new pools will get + /// private static int _poolVersion = 1; /// /// The number of connections successfully opened from any pool. /// This value is incremented by the Remove method. @@ -48,73 +53,73 @@ /// /// The number of connections successfully closed from any pool. /// This value is incremented by the Add method. /// - private static int _poolClosed = 0; - - /// - /// Counts the number of pool entries matching the specified file name. - /// - /// The file name to match or null to match all files. + private static int _poolClosed = 0; + + /// + /// Counts the number of pool entries matching the specified file name. + /// + /// The file name to match or null to match all files. /// The pool entry counts for each matching file. /// The total number of connections successfully opened from any pool. - /// The total number of connections successfully closed from any pool. - /// The total number of pool entries for all matching files. - internal static void GetCounts( - string fileName, - ref Dictionary counts, - ref int openCount, - ref int closeCount, - ref int totalCount - ) - { - lock (_connections) + /// The total number of connections successfully closed from any pool. + /// The total number of pool entries for all matching files. + internal static void GetCounts( + string fileName, + ref Dictionary counts, + ref int openCount, + ref int closeCount, + ref int totalCount + ) + { + lock (_connections) { openCount = _poolOpened; - closeCount = _poolClosed; - - if (counts == null) - { - counts = new Dictionary( - StringComparer.OrdinalIgnoreCase); - } - - if (fileName != null) - { - Pool queue; - - if (_connections.TryGetValue(fileName, out queue)) - { - Queue poolQueue = queue.Queue; - int count = (poolQueue != null) ? poolQueue.Count : 0; - - counts.Add(fileName, count); - totalCount += count; - } - } - else - { - foreach (KeyValuePair pair in _connections) - { - if (pair.Value == null) - continue; - - Queue poolQueue = pair.Value.Queue; - int count = (poolQueue != null) ? poolQueue.Count : 0; - - counts.Add(pair.Key, count); - totalCount += count; - } - } - } - } - - /// - /// Attempt to pull a pooled connection out of the queue for active duty - /// - /// The filename for a desired connection + closeCount = _poolClosed; + + if (counts == null) + { + counts = new Dictionary( + StringComparer.OrdinalIgnoreCase); + } + + if (fileName != null) + { + Pool queue; + + if (_connections.TryGetValue(fileName, out queue)) + { + Queue poolQueue = queue.Queue; + int count = (poolQueue != null) ? poolQueue.Count : 0; + + counts.Add(fileName, count); + totalCount += count; + } + } + else + { + foreach (KeyValuePair pair in _connections) + { + if (pair.Value == null) + continue; + + Queue poolQueue = pair.Value.Queue; + int count = (poolQueue != null) ? poolQueue.Count : 0; + + counts.Add(pair.Key, count); + totalCount += count; + } + } + } + } + + /// + /// Attempt to pull a pooled connection out of the queue for active duty + /// + /// The filename for a desired connection /// The maximum size the connection pool for the filename can be /// The pool version the returned connection will belong to /// Returns NULL if no connections were available. Even if none are, the poolversion will still be a valid pool version internal static SQLiteConnectionHandle Remove(string fileName, int maxPoolSize, out int version) { @@ -270,141 +275,141 @@ _connections.Add(fileName, queue); } } return null; - } - - /// - /// Clears out all pooled connections and rev's up the default pool version to force all old active objects - /// not in the pool to get discarded rather than returned to their pools. - /// - internal static void ClearAllPools() - { - lock (_connections) - { - foreach (KeyValuePair pair in _connections) + } + + /// + /// Clears out all pooled connections and rev's up the default pool version to force all old active objects + /// not in the pool to get discarded rather than returned to their pools. + /// + internal static void ClearAllPools() + { + lock (_connections) + { + foreach (KeyValuePair pair in _connections) { if (pair.Value == null) continue; Queue poolQueue = pair.Value.Queue; - while (poolQueue.Count > 0) + while (poolQueue.Count > 0) { WeakReference cnn = poolQueue.Dequeue(); - if (cnn == null) continue; - SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; - if (hdl != null) - { - hdl.Dispose(); - } - GC.KeepAlive(hdl); - } - - // Keep track of the highest revision so we can go one higher when we're finished - if (_poolVersion <= pair.Value.PoolVersion) - _poolVersion = pair.Value.PoolVersion + 1; - } - // 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've pumped up the _poolVersion out of range of all active connections, so they - // will all get discarded when they try to put themselves back in their pool. - _connections.Clear(); - } - } - - /// - /// Clear a given pool for a given filename. Discards anything in the pool for the given file, and revs the pool - /// version so current active objects on the old version of the pool will get discarded rather than be returned to the pool. - /// - /// The filename of the pool to clear - internal static void ClearPool(string fileName) - { - lock (_connections) - { - Pool queue; - if (_connections.TryGetValue(fileName, out queue) == true) - { + if (cnn == null) continue; + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl != null) + { + hdl.Dispose(); + } + GC.KeepAlive(hdl); + } + + // Keep track of the highest revision so we can go one higher when we're finished + if (_poolVersion <= pair.Value.PoolVersion) + _poolVersion = pair.Value.PoolVersion + 1; + } + // 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've pumped up the _poolVersion out of range of all active connections, so they + // will all get discarded when they try to put themselves back in their pool. + _connections.Clear(); + } + } + + /// + /// Clear a given pool for a given filename. Discards anything in the pool for the given file, and revs the pool + /// version so current active objects on the old version of the pool will get discarded rather than be returned to the pool. + /// + /// The filename of the pool to clear + internal static void ClearPool(string fileName) + { + lock (_connections) + { + Pool queue; + if (_connections.TryGetValue(fileName, out queue) == true) + { queue.PoolVersion++; Queue poolQueue = queue.Queue; if (poolQueue == null) return; - while (poolQueue.Count > 0) + while (poolQueue.Count > 0) { WeakReference cnn = poolQueue.Dequeue(); - if (cnn == null) continue; - SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; - if (hdl != null) - { - hdl.Dispose(); - } - GC.KeepAlive(hdl); - } - } - } - } - - /// - /// Return a connection to the pool for someone else to use. - /// - /// The filename of the pool to use - /// The connection handle to pool - /// The pool version the handle was created under - /// - /// If the version numbers don't match between the connection and the pool, then the handle is discarded. - /// - internal static void Add(string fileName, SQLiteConnectionHandle hdl, int version) - { - lock (_connections) - { - // If the queue doesn't exist in the pool, then it must've been cleared sometime after the connection was created. - Pool queue; - if (_connections.TryGetValue(fileName, out queue) == true && version == queue.PoolVersion) - { + if (cnn == null) continue; + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl != null) + { + hdl.Dispose(); + } + GC.KeepAlive(hdl); + } + } + } + } + + /// + /// Return a connection to the pool for someone else to use. + /// + /// The filename of the pool to use + /// The connection handle to pool + /// The pool version the handle was created under + /// + /// If the version numbers don't match between the connection and the pool, then the handle is discarded. + /// + internal static void Add(string fileName, SQLiteConnectionHandle hdl, int version) + { + lock (_connections) + { + // If the queue doesn't exist in the pool, then it must've been cleared sometime after the connection was created. + Pool queue; + if (_connections.TryGetValue(fileName, out queue) == true && version == queue.PoolVersion) + { ResizePool(queue, true); Queue poolQueue = queue.Queue; if (poolQueue == null) return; poolQueue.Enqueue(new WeakReference(hdl, false)); - Interlocked.Increment(ref _poolClosed); - } - else - { - hdl.Close(); - } - GC.KeepAlive(hdl); - } - } - - /// - /// We don't have to thread-lock anything in this function, because it's only called by other functions above - /// which already have a thread-safe lock. - /// - /// The queue to resize - /// If a function intends to add to the pool, this is true, which forces the resize - /// to take one more than it needs from the pool - private static void ResizePool(Pool queue, bool forAdding) - { - int target = queue.MaxPoolSize; - + Interlocked.Increment(ref _poolClosed); + } + else + { + hdl.Close(); + } + GC.KeepAlive(hdl); + } + } + + /// + /// We don't have to thread-lock anything in this function, because it's only called by other functions above + /// which already have a thread-safe lock. + /// + /// The queue to resize + /// If a function intends to add to the pool, this is true, which forces the resize + /// to take one more than it needs from the pool + private static void ResizePool(Pool queue, bool forAdding) + { + int target = queue.MaxPoolSize; + if (forAdding && target > 0) target--; Queue poolQueue = queue.Queue; if (poolQueue == null) return; - while (poolQueue.Count > target) + while (poolQueue.Count > target) { WeakReference cnn = poolQueue.Dequeue(); - if (cnn == null) continue; - SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; - if (hdl != null) - { - hdl.Dispose(); - } - GC.KeepAlive(hdl); - } - } - } -} + if (cnn == null) continue; + SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle; + if (hdl != null) + { + hdl.Dispose(); + } + GC.KeepAlive(hdl); + } + } + } +}