// For Non-SQL9 SQL servers, we create a dependency based on an internal cached item. public SqlCacheDependency(string databaseEntryName, string tableName) :base(0, null, new string[1] {GetDependKey(databaseEntryName, tableName)}) { Debug.Trace("SqlCacheDependency", "Depend on key=" + GetDependKey(databaseEntryName, tableName) + "; value=" + HttpRuntime.CacheInternal[GetDependKey(databaseEntryName, tableName)]); // Permission checking is done in GetDependKey() _sql7DatabaseState = SqlCacheDependencyManager.AddRef(databaseEntryName); _sql7DepInfo._database = databaseEntryName; _sql7DepInfo._table = tableName; object o = HttpRuntime.CacheInternal[GetDependKey(databaseEntryName, tableName)]; if (o == null) { // If the cache entry can't be found, this cache dependency will be set to CHANGED already. _sql7ChangeId = -1; } else { // Note that if the value in the cache changed between the base ctor and here, even though // we get a wrong unqiue Id, but it's okay because that change will cause the CacheDependency's // state to become CHANGED and any cache operation using this CacheDependency will fail anyway. _sql7ChangeId = (int)o; } // The ctor of every class derived from CacheDependency must call this. FinishInit(); InitUniqueID(); }
internal static DatabaseNotifState AddRef(string database) { DatabaseNotifState state = (DatabaseNotifState)s_DatabaseNotifStates[database]; Interlocked.Increment(ref state._refCount); return(state); }
internal static void InitPolling(string database) { SqlCacheDependencySection sqlCacheDependency = RuntimeConfig.GetAppConfig().SqlCacheDependency; if (!sqlCacheDependency.Enabled) { throw new ConfigurationErrorsException(System.Web.SR.GetString("Polling_not_enabled_for_sql_cache"), sqlCacheDependency.ElementInformation.Properties["enabled"].Source, sqlCacheDependency.ElementInformation.Properties["enabled"].LineNumber); } SqlCacheDependencyDatabase databaseConfig = GetDatabaseConfig(database); if (databaseConfig.PollTime == 0) { throw new ConfigurationErrorsException(System.Web.SR.GetString("Polltime_zero_for_database_sql_cache", new object[] { database }), databaseConfig.ElementInformation.Properties["pollTime"].Source, databaseConfig.ElementInformation.Properties["pollTime"].LineNumber); } if (!s_DatabaseNotifStates.ContainsKey(database)) { string connection = SqlConnectionHelper.GetConnectionString(databaseConfig.ConnectionStringName, true, true); if ((connection == null) || (connection.Length < 1)) { throw new ConfigurationErrorsException(System.Web.SR.GetString("Connection_string_not_found", new object[] { databaseConfig.ConnectionStringName }), databaseConfig.ElementInformation.Properties["connectionStringName"].Source, databaseConfig.ElementInformation.Properties["connectionStringName"].LineNumber); } lock (s_DatabaseNotifStates) { if (!s_DatabaseNotifStates.ContainsKey(database)) { DatabaseNotifState state; state = new DatabaseNotifState(database, connection, databaseConfig.PollTime) { _timer = new Timer(s_timerCallback, state, 0, databaseConfig.PollTime) }; s_DatabaseNotifStates.Add(database, state); } } } }
internal static void UpdateAllDatabaseNotifState() { lock (s_DatabaseNotifStates) { foreach (DictionaryEntry entry in s_DatabaseNotifStates) { DatabaseNotifState state = (DatabaseNotifState)entry.Value; if (state._init) { UpdateDatabaseNotifState((string)entry.Key); } } } }
public SqlCacheDependency(string databaseEntryName, string tableName) : base(0, null, new string[] { GetDependKey(databaseEntryName, tableName) }) { this._sql7DatabaseState = SqlCacheDependencyManager.AddRef(databaseEntryName); this._sql7DepInfo._database = databaseEntryName; this._sql7DepInfo._table = tableName; object obj2 = HttpRuntime.CacheInternal[GetDependKey(databaseEntryName, tableName)]; if (obj2 == null) { this._sql7ChangeId = -1; } else { this._sql7ChangeId = (int) obj2; } base.FinishInit(); this.InitUniqueID(); }
public SqlCacheDependency(string databaseEntryName, string tableName) : base(0, null, new string[] { GetDependKey(databaseEntryName, tableName) }) { this._sql7DatabaseState = SqlCacheDependencyManager.AddRef(databaseEntryName); this._sql7DepInfo._database = databaseEntryName; this._sql7DepInfo._table = tableName; object obj2 = HttpRuntime.CacheInternal[GetDependKey(databaseEntryName, tableName)]; if (obj2 == null) { this._sql7ChangeId = -1; } else { this._sql7ChangeId = (int)obj2; } base.FinishInit(); this.InitUniqueID(); }
internal static void Release(DatabaseNotifState dbState) { Interlocked.Decrement(ref dbState._refCount); }
internal static void PollDatabaseForChanges(DatabaseNotifState dbState, bool fromTimer) { SqlDataReader reader = null; SqlConnection sqlConn = null; SqlCommand sqlCmd = null; CacheInternal cacheInternal = HttpRuntime.CacheInternal; bool flag = false; Exception exception = null; SqlException exception2 = null; if (s_shutdown) { return; } if (((dbState._refCount == 0) && fromTimer) && dbState._init) { return; } if (Interlocked.CompareExchange(ref dbState._rqInCallback, 1, 0) != 0) { int num2; if (fromTimer) { return; } HttpContext current = HttpContext.Current; if (current == null) { num2 = 30; } else { num2 = Math.Max(current.Timeout.Seconds / 3, 30); } DateTime time = DateTime.UtcNow.Add(new TimeSpan(0, 0, num2)); do { if (Interlocked.CompareExchange(ref dbState._rqInCallback, 1, 0) == 0) { goto Label_00EA; } Thread.Sleep(250); if (s_shutdown) { return; } } while (Debugger.IsAttached || (DateTime.UtcNow <= time)); throw new HttpException(System.Web.SR.GetString("Cant_connect_sql_cache_dep_database_polling", new object[] { dbState._database })); } Label_00EA: try { try { Interlocked.Increment(ref s_activePolling); dbState.GetConnection(out sqlConn, out sqlCmd); reader = sqlCmd.ExecuteReader(); if (!s_shutdown) { flag = true; Hashtable hashtable = (Hashtable) dbState._tables.Clone(); while (reader.Read()) { string table = reader.GetString(0); int num = reader.GetInt32(1); string moniterKey = GetMoniterKey(dbState._database, table); object obj2 = cacheInternal[moniterKey]; if (obj2 == null) { cacheInternal.UtcAdd(moniterKey, num, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); dbState._tables.Add(table, null); } else if (num != ((int) obj2)) { cacheInternal.UtcInsert(moniterKey, num, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); } hashtable.Remove(table); } foreach (object obj3 in hashtable.Keys) { dbState._tables.Remove((string) obj3); cacheInternal.Remove(GetMoniterKey(dbState._database, (string) obj3)); } if (dbState._pollSqlError != 0) { dbState._pollSqlError = 0; } } } catch (Exception exception3) { exception = exception3; exception2 = exception3 as SqlException; if (exception2 != null) { dbState._pollSqlError = exception2.Number; } else { dbState._pollSqlError = 0; } } finally { try { if (reader != null) { reader.Close(); } dbState.ReleaseConnection(ref sqlConn, ref sqlCmd, exception != null); } catch { } lock (dbState) { dbState._pollExpt = exception; if ((dbState._notifEnabled && !flag) && ((exception != null) && (dbState._pollSqlError == 0xafc))) { foreach (object obj4 in dbState._tables.Keys) { try { cacheInternal.Remove(GetMoniterKey(dbState._database, (string) obj4)); } catch { } } dbState._tables.Clear(); } dbState._notifEnabled = flag; dbState._utcTablesUpdated = DateTime.UtcNow; } if (!dbState._init) { dbState._init = true; } Interlocked.Decrement(ref s_activePolling); Interlocked.Exchange(ref dbState._rqInCallback, 0); } } catch { throw; } }
internal static void InitPolling(string database) { SqlCacheDependencySection sqlCacheDependency = RuntimeConfig.GetAppConfig().SqlCacheDependency; if (!sqlCacheDependency.Enabled) { throw new ConfigurationErrorsException(System.Web.SR.GetString("Polling_not_enabled_for_sql_cache"), sqlCacheDependency.ElementInformation.Properties["enabled"].Source, sqlCacheDependency.ElementInformation.Properties["enabled"].LineNumber); } SqlCacheDependencyDatabase databaseConfig = GetDatabaseConfig(database); if (databaseConfig.PollTime == 0) { throw new ConfigurationErrorsException(System.Web.SR.GetString("Polltime_zero_for_database_sql_cache", new object[] { database }), databaseConfig.ElementInformation.Properties["pollTime"].Source, databaseConfig.ElementInformation.Properties["pollTime"].LineNumber); } if (!s_DatabaseNotifStates.ContainsKey(database)) { string connection = SqlConnectionHelper.GetConnectionString(databaseConfig.ConnectionStringName, true, true); if ((connection == null) || (connection.Length < 1)) { throw new ConfigurationErrorsException(System.Web.SR.GetString("Connection_string_not_found", new object[] { databaseConfig.ConnectionStringName }), databaseConfig.ElementInformation.Properties["connectionStringName"].Source, databaseConfig.ElementInformation.Properties["connectionStringName"].LineNumber); } lock (s_DatabaseNotifStates) { if (!s_DatabaseNotifStates.ContainsKey(database)) { DatabaseNotifState state; state = new DatabaseNotifState(database, connection, databaseConfig.PollTime) { _timer = new Timer(s_timerCallback, state, 0, databaseConfig.PollTime) }; s_DatabaseNotifStates.Add(database, state); } } } }
// Query all the entries from the AspNet_SqlCacheTablesForChangeNotification // table and update the values in the cache accordingly. // // This is mainly called by the timer callback. But will also be called by // UpdateDatabaseNotifState, which polls for changes on demand. internal static void PollDatabaseForChanges(DatabaseNotifState dbState, bool fromTimer) { SqlDataReader sqlReader = null; SqlConnection sqlConn = null; SqlCommand sqlCmd = null; int changeId; string tableName; CacheInternal cacheInternal = HttpRuntime.CacheInternal; string monitorKey; object obj; bool notifEnabled = false; Exception pollExpt = null; SqlException sqlExpt = null; Debug.Trace("SqlCacheDependencyManagerPolling", "PollCallback called; connection=" + dbState._connectionString); if (s_shutdown) { return; } // If this call is from a timer, and if the refcount for this database is zero, // we will ignore it. The exception is if dbState._init == false, // which means the timer is polling it for the first time. if (dbState._refCount == 0 && fromTimer && dbState._init ) { Debug.Trace("SqlCacheDependencyManagerPolling", "PollCallback ignored for " + dbState._database + " because refcount is 0"); return; } // Grab the lock, which allows only one thread to enter this method. if (Interlocked.CompareExchange(ref dbState._rqInCallback, 1, 0) != 0) { // We can't get the lock. if (!fromTimer) { // A non-timer caller will really want to make a call to SQL and // get the result. So if another thread is calling this, we'll // wait for it to be done. int timeout; HttpContext context = HttpContext.Current; if (context == null) { timeout = 30; } else { timeout = Math.Max(context.Timeout.Seconds / 3, 30); } DateTime waitLimit = DateTime.UtcNow.Add(new TimeSpan(0, 0, timeout)); for (;;) { if (Interlocked.CompareExchange(ref dbState._rqInCallback, 1, 0) == 0) { break; } Thread.Sleep(250); if (s_shutdown) { return; } // only apply timeout if a managed debugger is not attached if (!System.Diagnostics.Debugger.IsAttached && DateTime.UtcNow > waitLimit) { // We've waited and retried for 5 seconds. // Somehow PollCallback haven't finished its first call for this database // Assume we cannot connect to SQL. throw new HttpException( SR.GetString(SR.Cant_connect_sql_cache_dep_database_polling, dbState._database)); } } } else { // For a timer callback, if another thread is updating the data for // this database, this thread will just leave and let that thread // finish the update job. Debug.Trace("SqlCacheDependencyManagerPolling", "PollCallback returned because another thread is updating the data"); return; } } try { try { // Keep a count on how many threads are polling right now // This counter is used by Dispose() Interlocked.Increment(ref s_activePolling); // The below assert was commented out because this method is either // called by a timer thread, or thru the SqlCacheDependencyAdmin APIs. // In the latter case, the caller should have the permissions. //(new SqlClientPermission(PermissionState.Unrestricted)).Assert(); dbState.GetConnection(out sqlConn, out sqlCmd); sqlReader = sqlCmd.ExecuteReader(); // If we got stuck for a long time in the ExecuteReader above, // Dispose() may have given up already while waiting for this thread to finish if (s_shutdown) { return; } // ExecuteReader() succeeded, and that means we at least have found the notification table. notifEnabled = true; // Remember the original list of tables that are enabled Hashtable originalTables = (Hashtable)dbState._tables.Clone(); while(sqlReader.Read()) { tableName = sqlReader.GetString(0); changeId = sqlReader.GetInt32(1); Debug.Trace("SqlCacheDependencyManagerPolling", "Database=" + dbState._database+ "; tableName=" + tableName + "; changeId=" + changeId); monitorKey = GetMoniterKey(dbState._database, tableName); obj = cacheInternal[monitorKey]; if (obj == null) { Debug.Assert(!dbState._tables.ContainsKey(tableName), "DatabaseNotifStae._tables and internal cache keys should be in-[....]"); Debug.Trace("SqlCacheDependencyManagerPolling", "Add Database=" + dbState._database+ "; tableName=" + tableName + "; changeId=" + changeId); cacheInternal.UtcAdd(monitorKey, changeId, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); dbState._tables.Add(tableName, null); } else if (changeId != (int)obj) { Debug.Assert(dbState._tables.ContainsKey(tableName), "DatabaseNotifStae._tables and internal cache keys should be in-[....]"); Debug.Trace("SqlCacheDependencyManagerPolling", "Change Database=" + dbState._database+ "; tableName=" + tableName + "; old=" + (int)obj + "; new=" + changeId); // ChangeId is different. It means some table changes have happened. // Update local cache value cacheInternal.UtcInsert(monitorKey, changeId, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); } originalTables.Remove(tableName); } // What's left in originalTables are the ones that're no longer // contained in the AspNet_SqlCacheTablesForChangeNotification // table in the database. // Remove tables which are no longer enabled for notification foreach(object key in originalTables.Keys) { dbState._tables.Remove((string)key); cacheInternal.Remove(GetMoniterKey(dbState._database, (string)key)); Debug.Trace("SqlCacheDependencyManagerPolling", "Remove Database=" + dbState._database+ "; key=" + key); } // Clear old error, if any. if (dbState._pollSqlError != 0) { dbState._pollSqlError = 0; } } catch (Exception e) { pollExpt = e; sqlExpt = e as SqlException; if (sqlExpt != null) { Debug.Trace("SqlCacheDependencyManagerPolling", "Error reading rows. SqlException:"+ "\nMessage=" + sqlExpt.Message + "\nNumber=" + sqlExpt.Number); dbState._pollSqlError = sqlExpt.Number; } else { dbState._pollSqlError = 0; Debug.Trace("SqlCacheDependencyManagerPolling", "Error reading rows. Exception:"+ pollExpt); } } finally { try { if (sqlReader != null) { sqlReader.Close(); } dbState.ReleaseConnection(ref sqlConn, ref sqlCmd, pollExpt != null); } catch { } // Need locking because EnsureTableIsRegisteredAndPolled() assumes // the fields in a dbState are set atomically. lock(dbState) { dbState._pollExpt = pollExpt; // If we have changed from being enabled to disabled, and // it's because we cannot find the SP for polling, it means // the database is no longer enabled for sql cache dependency. // we should invalidate all cache items depending on any // table on this database if (dbState._notifEnabled && !notifEnabled && pollExpt != null && dbState._pollSqlError == SQL_EXCEPTION_SP_NOT_FOUND) { foreach(object key in dbState._tables.Keys) { try { cacheInternal.Remove(GetMoniterKey(dbState._database, (string)key)); } catch {} Debug.Trace("SqlCacheDependencyManagerPolling", "Changed to disabled. Remove Database=" + dbState._database+ "; key=" + key); } // Since we have removed all the cache items related to this database, // the _refCount of this database will drop to zero, and thus the timer // callback will not poll this database. // So we have to cleanup _tables now. dbState._tables.Clear(); } dbState._notifEnabled = notifEnabled; dbState._utcTablesUpdated = DateTime.UtcNow; Debug.Trace("SqlCacheDependencyManagerPolling", "dbState:_pollExpt="+ dbState._pollExpt + "; _pollSqlError=" + dbState._pollSqlError + "; _notifEnabled=" + dbState._notifEnabled + "; __utcTablesUpdated=" + dbState._utcTablesUpdated); } // Mark dbState as initialized by PollCallback for the first time. // EnsureTableIsRegisteredAndPolled() depends on this. if (dbState._init != true) { dbState._init = true; } Interlocked.Decrement(ref s_activePolling); // Release the lock Interlocked.Exchange(ref dbState._rqInCallback, 0); } } catch { throw; } // Prevent Exception Filter Security Issue (ASURT 122835) }
// Initialize polling for a database. It will: // 1. Create the DatabaseNotifState that holds the polling status about this database. // 2. Create the timer to poll. internal static void InitPolling(string database) { SqlCacheDependencySection config = RuntimeConfig.GetAppConfig().SqlCacheDependency;; SqlCacheDependencyDatabase sqlDepDB; string connectionString; Debug.Trace("SqlCacheDependencyManager", "InitPolling is called. Database=" + database); // Return if polling isn't even enabled. if (!config.Enabled) { throw new ConfigurationErrorsException( SR.GetString(SR.Polling_not_enabled_for_sql_cache), config.ElementInformation.Properties["enabled"].Source, config.ElementInformation.Properties["enabled"].LineNumber); } // Return if the polltime is zero. It means polling is disabled for this database. sqlDepDB = GetDatabaseConfig(database); if (sqlDepDB.PollTime == 0) { throw new ConfigurationErrorsException( SR.GetString(SR.Polltime_zero_for_database_sql_cache, database), sqlDepDB.ElementInformation.Properties["pollTime"].Source, sqlDepDB.ElementInformation.Properties["pollTime"].LineNumber); } if (s_DatabaseNotifStates.ContainsKey(database)) { // Someone has already started the timer for this database. Debug.Trace("SqlCacheDependencyManager", "InitPolling: Timer already started for " + database); return; } connectionString = SqlConnectionHelper.GetConnectionString(sqlDepDB.ConnectionStringName, true, true); if (connectionString == null || connectionString.Length < 1) { throw new ConfigurationErrorsException( SR.GetString(SR.Connection_string_not_found, sqlDepDB.ConnectionStringName), sqlDepDB.ElementInformation.Properties["connectionStringName"].Source, sqlDepDB.ElementInformation.Properties["connectionStringName"].LineNumber); } lock(s_DatabaseNotifStates) { DatabaseNotifState state; if (s_DatabaseNotifStates.ContainsKey(database)) { // Someone has already started the timer for this database. Debug.Trace("SqlCacheDependencyManager", "InitPolling: Timer already started for " + database); return; } Debug.Trace("SqlCacheDependencyManager", "InitPolling: Creating timer for " + database); state = new DatabaseNotifState(database, connectionString, sqlDepDB.PollTime); state._timer = new Timer(s_timerCallback, state, 0 /* dueTime */, sqlDepDB.PollTime /* period */); s_DatabaseNotifStates.Add(database, state); } }
internal static void Release(DatabaseNotifState dbState) { #if DBG int res = #endif Interlocked.Decrement(ref dbState._refCount); #if DBG Debug.Trace("SqlCacheDependencyManager", "Release called for " + dbState._database + "; res=" + res); Debug.Assert(res >= 0, "Release result for " + dbState._database + " must be >= 0"); #endif }
internal static void EnsureTableIsRegisteredAndPolled(string database, string table) { DateTime time2; bool flag2; Exception exception; int num2; bool flag = false; if (HttpRuntime.CacheInternal[GetMoniterKey(database, table)] != null) { return; } InitPolling(database); DatabaseNotifState state = (DatabaseNotifState)s_DatabaseNotifStates[database]; if (!state._init) { int num; HttpContext current = HttpContext.Current; if (current == null) { num = 30; } else { num = Math.Max(current.Timeout.Seconds / 3, 30); } DateTime time = DateTime.UtcNow.Add(new TimeSpan(0, 0, num)); do { if (state._init) { goto Label_00BD; } Thread.Sleep(250); }while (Debugger.IsAttached || (DateTime.UtcNow <= time)); throw new HttpException(System.Web.SR.GetString("Cant_connect_sql_cache_dep_database_polling", new object[] { database })); } Label_00BD: num2 = 0; lock (state) { exception = state._pollExpt; if (exception != null) { num2 = state._pollSqlError; } time2 = state._utcTablesUpdated; flag2 = state._notifEnabled; } if (((exception == null) && flag2) && state._tables.ContainsKey(table)) { return; } if (flag || ((DateTime.UtcNow - time2) < OneSec)) { string str; if (num2 == 0xafc) { exception = null; } if (exception == null) { if (!flag2) { throw new DatabaseNotEnabledForNotificationException(System.Web.SR.GetString("Database_not_enabled_for_notification", new object[] { database })); } throw new TableNotEnabledForNotificationException(System.Web.SR.GetString("Table_not_enabled_for_notification", new object[] { table, database })); } switch (num2) { case 0xe5: case 0x106: str = "Permission_denied_database_polling"; break; default: str = "Cant_connect_sql_cache_dep_database_polling"; break; } HttpException e = new HttpException(System.Web.SR.GetString(str, new object[] { database }), exception); e.SetFormatter(new UseLastUnhandledErrorFormatter(e)); throw e; } UpdateDatabaseNotifState(database); flag = true; goto Label_00BD; }
internal static void Release(DatabaseNotifState dbState) { Interlocked.Decrement(ref dbState._refCount); }
internal static void PollDatabaseForChanges(DatabaseNotifState dbState, bool fromTimer) { SqlDataReader reader = null; SqlConnection sqlConn = null; SqlCommand sqlCmd = null; CacheInternal cacheInternal = HttpRuntime.CacheInternal; bool flag = false; Exception exception = null; SqlException exception2 = null; if (s_shutdown) { return; } if (((dbState._refCount == 0) && fromTimer) && dbState._init) { return; } if (Interlocked.CompareExchange(ref dbState._rqInCallback, 1, 0) != 0) { int num2; if (fromTimer) { return; } HttpContext current = HttpContext.Current; if (current == null) { num2 = 30; } else { num2 = Math.Max(current.Timeout.Seconds / 3, 30); } DateTime time = DateTime.UtcNow.Add(new TimeSpan(0, 0, num2)); do { if (Interlocked.CompareExchange(ref dbState._rqInCallback, 1, 0) == 0) { goto Label_00EA; } Thread.Sleep(250); if (s_shutdown) { return; } }while (Debugger.IsAttached || (DateTime.UtcNow <= time)); throw new HttpException(System.Web.SR.GetString("Cant_connect_sql_cache_dep_database_polling", new object[] { dbState._database })); } Label_00EA: try { try { Interlocked.Increment(ref s_activePolling); dbState.GetConnection(out sqlConn, out sqlCmd); reader = sqlCmd.ExecuteReader(); if (!s_shutdown) { flag = true; Hashtable hashtable = (Hashtable)dbState._tables.Clone(); while (reader.Read()) { string table = reader.GetString(0); int num = reader.GetInt32(1); string moniterKey = GetMoniterKey(dbState._database, table); object obj2 = cacheInternal[moniterKey]; if (obj2 == null) { cacheInternal.UtcAdd(moniterKey, num, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); dbState._tables.Add(table, null); } else if (num != ((int)obj2)) { cacheInternal.UtcInsert(moniterKey, num, null, Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null); } hashtable.Remove(table); } foreach (object obj3 in hashtable.Keys) { dbState._tables.Remove((string)obj3); cacheInternal.Remove(GetMoniterKey(dbState._database, (string)obj3)); } if (dbState._pollSqlError != 0) { dbState._pollSqlError = 0; } } } catch (Exception exception3) { exception = exception3; exception2 = exception3 as SqlException; if (exception2 != null) { dbState._pollSqlError = exception2.Number; } else { dbState._pollSqlError = 0; } } finally { try { if (reader != null) { reader.Close(); } dbState.ReleaseConnection(ref sqlConn, ref sqlCmd, exception != null); } catch { } lock (dbState) { dbState._pollExpt = exception; if ((dbState._notifEnabled && !flag) && ((exception != null) && (dbState._pollSqlError == 0xafc))) { foreach (object obj4 in dbState._tables.Keys) { try { cacheInternal.Remove(GetMoniterKey(dbState._database, (string)obj4)); } catch { } } dbState._tables.Clear(); } dbState._notifEnabled = flag; dbState._utcTablesUpdated = DateTime.UtcNow; } if (!dbState._init) { dbState._init = true; } Interlocked.Decrement(ref s_activePolling); Interlocked.Exchange(ref dbState._rqInCallback, 0); } } catch { throw; } }