Allow transactions that don't write WAL to commit asynchronously.
authorRobert Haas <[email protected]>
Mon, 20 Dec 2010 17:59:33 +0000 (12:59 -0500)
committerRobert Haas <[email protected]>
Mon, 20 Dec 2010 17:59:33 +0000 (12:59 -0500)
This case can arise if a transaction has written data, but only to
temporary tables.  Loss of the commit record in case of a crash won't
matter, because the temporary tables will be lost anyway.

Reviewed by Heikki Linnakangas and Simon Riggs.

src/backend/access/transam/xact.c

index 79c9c0d844618f2a3c03eac48a714fbe2d00f021..67f817ca4b8e401d8ef02fac3df4f41fea485a18 100644 (file)
@@ -907,6 +907,7 @@ RecordTransactionCommit(void)
    int         nmsgs = 0;
    SharedInvalidationMessage *invalMessages = NULL;
    bool        RelcacheInitFileInval = false;
+   bool        wrote_xlog;
 
    /* Get data needed for commit record */
    nrels = smgrGetPendingDeletes(true, &rels);
@@ -914,6 +915,7 @@ RecordTransactionCommit(void)
    if (XLogStandbyInfoActive())
        nmsgs = xactGetCommittedInvalidationMessages(&invalMessages,
                                                     &RelcacheInitFileInval);
+   wrote_xlog = (XactLastRecEnd.xrecoff != 0);
 
    /*
     * If we haven't been assigned an XID yet, we neither can, nor do we want
@@ -940,7 +942,7 @@ RecordTransactionCommit(void)
         * assigned is a sequence advance record due to nextval() --- we want
         * to flush that to disk before reporting commit.)
         */
-       if (XactLastRecEnd.xrecoff == 0)
+       if (!wrote_xlog)
            goto cleanup;
    }
    else
@@ -1028,16 +1030,27 @@ RecordTransactionCommit(void)
    }
 
    /*
-    * Check if we want to commit asynchronously.  If the user has set
-    * synchronous_commit = off, and we're not doing cleanup of any non-temp
-    * rels nor committing any command that wanted to force sync commit, then
-    * we can defer flushing XLOG.  (We must not allow asynchronous commit if
-    * there are any non-temp tables to be deleted, because we might delete
-    * the files before the COMMIT record is flushed to disk.  We do allow
-    * asynchronous commit if all to-be-deleted tables are temporary though,
-    * since they are lost anyway if we crash.)
+    * Check if we want to commit asynchronously.  We can allow the XLOG flush
+    * to happen asynchronously if synchronous_commit=off, or if the current
+    * transaction has not performed any WAL-logged operation.  The latter case
+    * can arise if the current transaction wrote only to temporary tables.
+    * In case of a crash, the loss of such a transaction will be irrelevant
+    * since temp tables will be lost anyway.  (Given the foregoing, you might
+    * think that it would be unnecessary to emit the XLOG record at all in
+    * this case, but we don't currently try to do that.  It would certainly
+    * cause problems at least in Hot Standby mode, where the KnownAssignedXids
+    * machinery requires tracking every XID assignment.  It might be OK to
+    * skip it only when wal_level < hot_standby, but for now we don't.)
+    *
+    * However, if we're doing cleanup of any non-temp rels or committing any
+    * command that wanted to force sync commit, then we must flush XLOG
+    * immediately.  (We must not allow asynchronous commit if there are any
+    * non-temp tables to be deleted, because we might delete the files before
+    * the COMMIT record is flushed to disk.  We do allow asynchronous commit
+    * if all to-be-deleted tables are temporary though, since they are lost
+    * anyway if we crash.)
     */
-   if (XactSyncCommit || forceSyncCommit || nrels > 0)
+   if ((wrote_xlog && XactSyncCommit) || forceSyncCommit || nrels > 0)
    {
        /*
         * Synchronous commit case: