Beispiel #1
0
        /// <summary>
        // Call from WC in response to a client's abort
        /// </summary>
        /// <param name="context"></param>
        public void Abort(TP.Transaction context)
        {
            // Get the list of names of the resource manager involved in this transaction
            List <string> rmNameList = GetRMListForTransaction(context);

            if (null == rmNameList)
            {
                System.Console.WriteLine(string.Format("Transaction {0} unknown", context.Id));
            }

            // Get the list of resource managers involved in this transaction
            List <RM> rmList = new List <RM>();

            lock (this.resourceManagers)
            {
                foreach (string name in rmNameList)
                {
                    RM manager = GetResourceMananger(name);
                    if (null == manager)
                    {
                        continue;
                    }

                    rmList.Add(manager);
                }

                // Write transaction id and list of RM to outstanding transaction list before aborting the transaction
                // Flush the entry to the outstanding transaction file immediately
                OutstandingTransactions.OutstandingTransactionsValue abortedTransactionValue = new OutstandingTransactions.OutstandingTransactionsValue(
                    OutstandingTransactions.OutstandingTransactionsValue.TransactionType.Abort,
                    rmNameList);

                lock (OutstandingTransactions)
                {
                    OutstandingTransactions.UpdateAndFlush(context.Id.ToString(), abortedTransactionValue);

                    System.Console.WriteLine(string.Format("Transaction {0} aborting...", context.Id));
                    for (int i = 0; i < rmList.Count; ++i)
                    {
                        ExecuteActionWithTimeout exec = new ExecuteActionWithTimeout(rmList[i].GetName(), () => rmList[i].Abort(context));
                        try
                        {
                            exec.Run();
                        }
                        catch (TimeoutException)
                        {
                            System.Console.WriteLine(string.Format("Transaction {0} timed out while waiting for RM {1} to abort...", context.Id, rmList[i].GetName()));
                        }
                    }

                    // PRESUMED ABORT: Once the TM sends out the abort, it forgets about the transaction immediately.
                    // So we write transaction id and an _empty_ list of unacknowledged RMs to the outstanding transaction list.
                    // This will cancel out the entry we logged earlier about the transaction and all its RMs.
                    // Flush the entry to the outstanding transaction file immediately
                    abortedTransactionValue.nackRMList.Clear();
                    OutstandingTransactions.UpdateAndFlush(context.Id.ToString(), abortedTransactionValue);
                    if (abortedTransactionValue.nackRMList.Count == 0)
                    {
                        System.Console.WriteLine(string.Format("Transaction {0} aborted", context.Id));
                    }
                    else
                    {
                        System.Console.WriteLine(string.Format("Transaction {0} aborted with some timeouts", context.Id));
                    }
                }
            }
        }
Beispiel #2
0
        // This function reviews all outstanding transaction and reissues Commit() or Abort() to the
        // unackowledged RMs
        public void recovery()
        {
            Console.Out.WriteLine("Recovery started...");
            List <string> deleteTransactionList = new List <string>(); // Keep track of transactions that are fully acknowledged by all its RMs

            lock (OutstandingTransactions)
            {
                if (OutstandingTransactions.transactionList.Keys.Count == 0)
                {
                    Console.WriteLine("Recovery: No outstanding transactions to recover. Recovery completed.");
                    return;
                }

                foreach (string transactionId in OutstandingTransactions.transactionList.Keys)
                {
                    // For each outstanding transaction, get its transaction id and its OutstandingTransactions value
                    OutstandingTransactions.OutstandingTransactionsValue entry = OutstandingTransactions.transactionList[transactionId];
                    Transaction context = new Transaction();
                    context.Id = new Guid(transactionId);

                    Console.Out.WriteLine(string.Format("Recovery: Recovering transaction {0}...", transactionId));

                    // For each of the remaining NACK RMs, reissue the Commit or Abort
                    for (int i = 0; i < entry.nackRMList.Count; ++i)
                    {
                        string rmName = entry.nackRMList[i];
                        RM     rm     = GetResourceMananger(rmName);
                        if (rm == null)
                        {
                            Console.Out.WriteLine(string.Format("Recovery: Failed to find resource manager {0}", rmName));
                        }
                        else
                        {
                            ExecuteActionWithTimeout exec;

                            if (entry.transactionType == OutstandingTransactions.OutstandingTransactionsValue.TransactionType.Commit)
                            {
                                Console.Out.WriteLine(string.Format("Recovery: Re-committing resource manager {0}...", rmName));
                                exec = new ExecuteActionWithTimeout(rmName, () => rm.Commit(context));
                            }
                            else
                            {
                                Console.Out.WriteLine(string.Format("Recovery: Re-aborting resource manager {0}...", rmName));
                                exec = new ExecuteActionWithTimeout(rmName, () => rm.Abort(context));
                            }

                            // Execute the commit or abort
                            try
                            {
                                exec.Run();
                                Console.Out.WriteLine("Recovery: Successful!");

                                // Remove RM from the current transaction since we received the Done message (ie the call didn't time out)
                                OutstandingTransactions.transactionList[transactionId].nackRMList.RemoveAt(i);
                                --i;
                            }
                            catch (TimeoutException)
                            {
                                System.Console.WriteLine("Recovery: Failed!");
                            }
                        }
                    }

                    // PRESUMED ABORT: If the transaction is Abort, we don't care about the Done message and we forget about
                    // the transaction immediately.
                    // For commit transactions, mark transaction for removal if we received Done from all RMs
                    if (entry.transactionType == OutstandingTransactions.OutstandingTransactionsValue.TransactionType.Abort ||
                        entry.nackRMList.Count == 0)
                    {
                        deleteTransactionList.Add(transactionId);
                    }
                }

                // Delete transaction marked for removal from the outstanding transaction list
                foreach (string s in deleteTransactionList)
                {
                    OutstandingTransactions.transactionList.Remove(s);
                }
                // Update file to reflect outstanding transactions status
                // This is a full rewrite of the outstanding transaction file and hence it will implicitly garbage collect
                // the transactions that are no longer outstanding.
                OutstandingTransactions.WriteToFile();
            }
            Console.Out.WriteLine("Recovery completed.");
        }
Beispiel #3
0
        /// <summary>
        //	 Call from WC in response to a client's commit.
        /// </summary>
        /// <param name="context"></param>
        public void Commit(TP.Transaction context)
        {
            // Get the list of names of the resource manager involved in this transaction
            List <string> rmNameList = GetRMListForTransaction(context);

            if (null == rmNameList)
            {
                System.Console.WriteLine(string.Format("Transaction {0} unknown", context.Id));
                throw new AbortTransationException();
            }

            // Get the list of resource managers involved in this transaction
            List <RM> rmList = new List <RM>();

            lock (this.resourceManagers)
            {
                foreach (string name in rmNameList)
                {
                    RM manager = GetResourceMananger(name);
                    if (null == manager)
                    {
                        continue;
                    }

                    rmList.Add(manager);
                }

                // Request to prepare for all resource managers involved in this transaction
                bool allPrepared = true;
                List <ExecuteFuncWithTimeout <bool> > execPrepareList = new List <ExecuteFuncWithTimeout <bool> >();
                try
                {
                    // Execute the Prepare() function for each associated RMs with timeout
                    for (int i = 0; i < rmList.Count; ++i)
                    {
                        ExecuteFuncWithTimeout <bool> exec = new ExecuteFuncWithTimeout <bool>(rmList[i].GetName(), () => rmList[i].Prepare(context));
                        execPrepareList.Add(exec);
                        exec.Run();
                    }
                }
                // If a timeout occurs, it means that RMs are not all prepared and we should abort
                // the transaction
                catch (TimeoutException)
                {
                    System.Console.WriteLine(string.Format("Transaction {0} timed out while waiting for RequestToPrepare. Aborting transaction...", context.Id));
                    allPrepared = false;
                }

                if (allPrepared)
                {
                    // If all resource managers are ready responded to the request to prepare, check if
                    // any of them responded NO to the request.
                    foreach (ExecuteFuncWithTimeout <bool> exec in execPrepareList)
                    {
                        if (exec.completed && exec.result == false)
                        {
                            allPrepared = false;
                            System.Console.WriteLine(string.Format("Transaction {0} received No for RequestToPrepare. Aborting transaction...", context.Id));
                            break;
                        }
                    }
                }
                execPrepareList.Clear();

                // Initialize the list of RM to outstanding transaction list in case of recovery
                OutstandingTransactions.OutstandingTransactionsValue committedTransactionValue = new OutstandingTransactions.OutstandingTransactionsValue(
                    OutstandingTransactions.OutstandingTransactionsValue.TransactionType.Commit,
                    rmNameList);

                lock (OutstandingTransactions)
                {
                    // If all resource managers responded Prepared to the Request to prepare, commit the transaction.
                    if (allPrepared)
                    {
                        // Write transaction id and list of RM to outstanding transaction list before committing the transaction
                        // Flush the entry to the outstanding transaction file immediately
                        OutstandingTransactions.UpdateAndFlush(context.Id.ToString(), committedTransactionValue);

                        System.Console.WriteLine(string.Format("Transaction {0} received Prepared from all resource managers. Committing transaction...", context.Id));

                        // Execute commit() in all associated RMs
                        for (int i = 0; i < rmList.Count; ++i)
                        {
                            ExecuteActionWithTimeout exec = new ExecuteActionWithTimeout(rmList[i].GetName(), () => rmList[i].Commit(context));
                            try
                            {
                                exec.Run();
                                // Remove RM from list of RM when we received Done (ie no timeout has occurred)
                                committedTransactionValue.nackRMList.Remove(rmList[i].GetName());
                            }
                            catch (TimeoutException)
                            {
                                System.Console.WriteLine(string.Format("Transaction {0} timed out while waiting for RM {1} to commit...", context.Id, rmList[i].GetName()));
                            }
                        }

                        // Write transaction id and list of unacknowledged RMs to the outstanding transaction list.
                        // Flush the entry to the outstanding transaction file immediately
                        OutstandingTransactions.UpdateAndFlush(context.Id.ToString(), committedTransactionValue);

                        if (committedTransactionValue.nackRMList.Count == 0)
                        {
                            System.Console.WriteLine(string.Format("Transaction {0} commited", context.Id));
                        }
                        else
                        {
                            System.Console.WriteLine(string.Format("Transaction {0} commited with some timeouts", context.Id));
                        }
                    }
                    else
                    {
                        // Initialize the list of RM to outstanding transaction list in case of recovery
                        // Write transaction id and list of RM to outstanding transaction list before aborting the transaction
                        // Flush the entry to the outstanding transaction file immediately
                        committedTransactionValue.transactionType = OutstandingTransactions.OutstandingTransactionsValue.TransactionType.Abort;
                        OutstandingTransactions.UpdateAndFlush(context.Id.ToString(), committedTransactionValue);

                        System.Console.WriteLine(string.Format("Transaction {0} aborting...", context.Id));

                        // Execute abort() in all associated RMs
                        for (int i = 0; i < rmList.Count; ++i)
                        {
                            ExecuteActionWithTimeout exec = new ExecuteActionWithTimeout(rmList[i].GetName(), () => rmList[i].Abort(context));
                            try
                            {
                                exec.Run();
                            }
                            catch (TimeoutException)
                            {
                                System.Console.WriteLine(string.Format("Transaction {0} timed out while waiting for RM {1} to abort...", context.Id, rmList[i].GetName()));
                            }
                        }

                        // PRESUMED ABORT: Once the TM sends out the abort, it forgets about the transaction immediately.
                        // So we write transaction id and an _empty_ list of unacknowledged RMs to the outstanding transaction list.
                        // This will cancel out the entry we logged earlier about the transaction and all its RMs.
                        // Flush the entry to the outstanding transaction file immediately
                        committedTransactionValue.nackRMList.Clear();
                        OutstandingTransactions.UpdateAndFlush(context.Id.ToString(), committedTransactionValue);
                        if (committedTransactionValue.nackRMList.Count == 0)
                        {
                            System.Console.WriteLine(string.Format("Transaction {0} aborted", context.Id));
                        }
                        else
                        {
                            System.Console.WriteLine(string.Format("Transaction {0} aborted with some timeouts", context.Id));
                        }
                    }
                }
            }
        }