/// roll back the transaction public void Rollback() { string TransactionIdentifier = null; bool TransactionValid = false; IsolationLevel TransactionIsolationLevel = IsolationLevel.Unspecified; // Attempt to roll back the DB Transaction. try { // 'Sanity Check': Check that TheTransaction hasn't been committed or rolled back yet. if (!Valid) { var Exc1 = new EDBAttemptingToUseTransactionThatIsInvalidException( "TDataBase.RollbackTransaction called on DB Transaction that isn't valid", ThreadingHelper.GetThreadIdentifier(ThreadThatTransactionWasStartedOn), ThreadingHelper.GetCurrentThreadIdentifier()); TLogging.Log(Exc1.ToString()); throw Exc1; } if (TLogging.DL >= DBAccess.DB_DEBUGLEVEL_TRANSACTION_DETAIL) { // Gather information for logging TransactionIdentifier = GetDBTransactionIdentifier(); TransactionValid = Valid; TransactionIsolationLevel = IsolationLevel; } WrappedTransaction.Rollback(); TLogging.LogAtLevel(DBAccess.DB_DEBUGLEVEL_TRANSACTION, " Transaction " + FTransactionName + " in Connection " + FTDataBaseInstanceThatTransactionBelongsTo.ConnectionName + " rolled back"); // Rollback was OK, now clean up. Dispose(); TLogging.LogAtLevel(DBAccess.DB_DEBUGLEVEL_TRANSACTION_DETAIL, String.Format( "DB Transaction{0} got rolled back. Before that, its DB Transaction Properties were: Valid: {1}, " + "IsolationLevel: {2} (it got started on Thread {3} in AppDomain '{4}').", TransactionIdentifier, TransactionValid, TransactionIsolationLevel, ThreadThatTransactionWasStartedOn, AppDomainNameThatTransactionWasStartedIn) ); } catch (Exception Exc) { // This catch block will handle any errors that may have occurred // on the server that would cause the rollback to fail, such as // a closed connection. // // MSDN says: "Try/Catch exception handling should always be used when rolling back a // transaction. A Rollback generates an InvalidOperationException if the connection is // terminated or if the transaction has already been rolled back on the server." TLogging.Log("Exception while attempting Transaction rollback: " + Exc.ToString()); } }
/// <summary> /// Performs an unlimited number of retries to (re-)establish the Server's DB Polling Connection. /// Finishes only when the Server's DB Polling Connection is restored. /// </summary> /// <remarks>This Method must only be run in a Thread as otherwise it would blocks the server /// completely!</remarks> public void PerformDBReconnection() { const int WAITING_TIME_BETWEEN_RETRIES = 2000; // 2000 Milliseconds string StrOpenDBConn = Catalog.GetString("open the Server's DB Polling Connection..."); string StrReestablishDBConn = Catalog.GetString("re-establish the Server's broken DB Polling Connection..."); string StrEstablished = Catalog.GetString("got successfully established"); string StrRestored = Catalog.GetString("got successfully restored"); bool DBConnectionRestored = false; FTheServerManager.DBReconnectionAttemptsCounter = 0; TLogging.LogAtLevel(1, String.Format( "ExceptionHandling_DBConnectionBrokenCallback: Starting handling of broken database connection (on Thread {0})...!", ThreadingHelper.GetThreadIdentifier(Thread.CurrentThread))); while (!DBConnectionRestored) { try { FTheServerManager.DBReconnectionAttemptsCounter++; TLogging.Log(String.Format("Attempt {0} to ", FTheServerManager.DBReconnectionAttemptsCounter) + (FDBConnectionEstablishmentAtStartup ? StrOpenDBConn : StrReestablishDBConn)); FTheServerManager.EstablishDBPollingConnection(); DBConnectionRestored = true; } catch (SocketException Exc) { TLogging.LogAtLevel(1, Exc.Message); // Getting a SocketException here *is what can be expected* until the DB connection can be successfully // established - hence we are 'swallowing' this particular Exception here on purpose! Thread.Sleep(WAITING_TIME_BETWEEN_RETRIES); } catch (NpgsqlException Exc) { TLogging.LogAtLevel(1, Exc.Message); // Getting a NpgsqlException here *is what can be expected* until the DB connection can be successfully // established - hence we are 'swallowing' this particular Exception here on purpose! Thread.Sleep(WAITING_TIME_BETWEEN_RETRIES); } catch (EDBConnectionNotEstablishedException Exc) { TLogging.LogAtLevel(1, Exc.Message); // Getting an EDBConnectionNotEstablishedException here *is what can be expected* until the DB connection // can be successfully established - hence we are 'swallowing' this particular Exception here on purpose! Thread.Sleep(WAITING_TIME_BETWEEN_RETRIES); } catch (Exception Exc) { TLogging.Log(Exc.Message); TLogging.LogStackTrace(TLoggingType.ToLogfile); throw; } } if (FCallbackAtEndOfThread != null) { FCallbackAtEndOfThread(false, 0); } else { throw new EOPException("Delegate 'FCallbackAtEndOfThread' was not set up, but it must be set up " + "for the ability of the 'PerformDBReconnection' Method to signalise that it has re-established the " + "Server's DB Polling Connection"); } // Log that we are done once the Callback Method has finished running if (TLogging.DebugLevel == 0) { TLogging.Log(String.Format(" --> The Server's DB Polling Connection {0}!", FDBConnectionEstablishmentAtStartup ? StrEstablished : StrRestored)); } else { TLogging.Log( String.Format("FINISHED with the handling of a broken database " + "connection (on Thread {0}) - the Server's DB Polling Connection {1}!", ThreadingHelper.GetThreadIdentifier(Thread.CurrentThread), FDBConnectionEstablishmentAtStartup ? StrEstablished : StrRestored)); } }