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
        /// <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));
                        }
                    }
                }
            }
        }