Handle errors while PREPARing a transaction gracefully.
authorPavan Deolasee <[email protected]>
Mon, 15 Feb 2016 12:56:13 +0000 (18:26 +0530)
committerPavan Deolasee <[email protected]>
Mon, 15 Feb 2016 18:30:08 +0000 (00:00 +0530)
If an error occurs after PREPARE TRANSACTION command is sent, we don't know if
the command is successful or not. So the coordinator will go ahead and abort
the transaction. But the node which failed to run PREPARE TRANSACTION may not
be even reachable on the coordinator. So we don't try to rollback transaction
on such nodes.

src/backend/access/transam/xact.c
src/backend/pgxc/pool/execRemote.c
src/backend/storage/ipc/procarray.c

index f42d8d3d1cb6cd13e26b7436a93608108badaffd..8aaa6f20bde45284ad343eb8888c8c641da52514 100644 (file)
@@ -2477,7 +2477,10 @@ CommitTransaction(void)
                 * We need to mark our XIDs as committed in pg_clog.  This is where we
                 * durably commit.
                 */
-               latestXid = RecordTransactionCommit();
+#ifdef XCP
+               if (!IsConnFromDatanode())
+#endif
+                       latestXid = RecordTransactionCommit();
        }
        else
        {
@@ -3250,7 +3253,12 @@ AbortTransaction(void)
         * record.
         */
        if (!is_parallel_worker)
-               latestXid = RecordTransactionAbort(false);
+       {
+#ifdef XCP
+               if (!IsConnFromDatanode())
+#endif
+                       latestXid = RecordTransactionAbort(false);
+       }
        else
        {
                latestXid = InvalidTransactionId;
@@ -6784,8 +6792,18 @@ SetTopTransactionId(GlobalTransactionId xid)
        TransactionState s = CurrentTransactionState;
        Assert(!GlobalTransactionIdIsValid(s->transactionId) ||
                        GlobalTransactionIdEquals(s->transactionId, xid));
-       XactTopTransactionId = s->transactionId = xid;
-       elog(DEBUG2, "Assigning XID received from the remote node - %d", xid);
+
+       if (!IsConnFromDatanode())
+       {
+               XactTopTransactionId = s->transactionId = xid;
+               elog(DEBUG2, "Assigning XID received from the remote node - %d", xid);
+       }
+       else if (!TransactionIdIsValid(GetNextTransactionId()))
+       {
+               SetNextTransactionId(xid);
+               if (whereToSendOutput == DestRemote)
+                       pq_putmessage('x', (const char *) &xid, sizeof (GlobalTransactionId));
+       }
 }
 #endif
 #endif
index e52355f21120ba89d1c635cc7f6f7d28c4536294..0a21135ba46c3562693912a7069bf03acb76bf61 100644 (file)
@@ -2319,9 +2319,20 @@ prepare_err:
                if (conn->ck_resp_rollback)
                {
                        conn->ck_resp_rollback = false;
+
+                       if (conn->state != DN_CONNECTION_STATE_IDLE)
+                       {
+                               ereport(WARNING,
+                                               (errcode(ERRCODE_INTERNAL_ERROR),
+                                                errmsg("Error while PREPARING transaction %s on "
+                                                        "node %s. Administrative action may be required "
+                                                        "to abort this transaction on the node",
+                                                        prepareGID, conn->nodename)));
+                               continue;
+                       }
+
                        /* sanity checks */
                        Assert(conn->sock != NO_SOCKET);
-                       Assert(conn->state == DN_CONNECTION_STATE_IDLE);
                        /* Send down abort prepared command */
                        if (pgxc_node_send_gxid(conn, auxXid))
                        {
@@ -2359,9 +2370,20 @@ prepare_err:
                if (conn->ck_resp_rollback)
                {
                        conn->ck_resp_rollback = false;
+
+                       if (conn->state != DN_CONNECTION_STATE_IDLE)
+                       {
+                               ereport(WARNING,
+                                               (errcode(ERRCODE_INTERNAL_ERROR),
+                                                errmsg("Error while PREPARING transaction %s on "
+                                                        "node %s. Administrative action may be required "
+                                                        "to abort this transaction on the node",
+                                                        prepareGID, conn->nodename)));
+                               continue;
+                       }
+
                        /* sanity checks */
                        Assert(conn->sock != NO_SOCKET);
-                       Assert(conn->state == DN_CONNECTION_STATE_IDLE);
                        /* Send down abort prepared command */
                        if (pgxc_node_send_gxid(conn, auxXid))
                        {
index 84b6a87d0d5786749a1797cccad1cb5a447b2083..b7fc75d52dacca3366e3a56c525c2c3e57c7518c 100644 (file)
@@ -496,6 +496,10 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
                 * anyone else's calculation of a snapshot.  We might change their
                 * estimate of global xmin, but that's OK.
                 */
+#ifdef XCP
+               if (IsConnFromDatanode())
+                       allPgXact[proc->pgprocno].xid = InvalidTransactionId;
+#endif
                Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
 
                proc->lxid = InvalidLocalTransactionId;
@@ -4371,7 +4375,7 @@ KnownAssignedXidsReset(void)
 void
 ProcArrayCheckXminConsistency(TransactionId global_xmin)
 {
-       ProcArrayStruct *arrayP = procArray;
+       volatile ProcArrayStruct *arrayP = procArray;
        int                     index;
 
        for (index = 0; index < arrayP->numProcs; index++)