In checkpoint, move the check for in-progress xacts out of critical section.
authorHeikki Linnakangas
Fri, 4 Apr 2014 14:29:50 +0000 (17:29 +0300)
committerHeikki Linnakangas
Fri, 4 Apr 2014 14:31:22 +0000 (17:31 +0300)
GetVirtualXIDsDelayingChkpt calls palloc, which isn't safe in a critical
section. I thought I covered this case with the exemption for the
checkpointer, but CreateCheckPoint is also called from the startup process.

src/backend/access/transam/xlog.c

index e2a14de7212df869302be3bffb42f3880a0abca9..3a48227ad930871a2e524300d160a378717ecbd5 100644 (file)
@@ -8076,6 +8076,42 @@ CreateCheckPoint(int flags)
 
    TRACE_POSTGRESQL_CHECKPOINT_START(flags);
 
+   /*
+    * Get the other info we need for the checkpoint record.
+    */
+   LWLockAcquire(XidGenLock, LW_SHARED);
+   checkPoint.nextXid = ShmemVariableCache->nextXid;
+   checkPoint.oldestXid = ShmemVariableCache->oldestXid;
+   checkPoint.oldestXidDB = ShmemVariableCache->oldestXidDB;
+   LWLockRelease(XidGenLock);
+
+   /* Increase XID epoch if we've wrapped around since last checkpoint */
+   checkPoint.nextXidEpoch = ControlFile->checkPointCopy.nextXidEpoch;
+   if (checkPoint.nextXid < ControlFile->checkPointCopy.nextXid)
+       checkPoint.nextXidEpoch++;
+
+   LWLockAcquire(OidGenLock, LW_SHARED);
+   checkPoint.nextOid = ShmemVariableCache->nextOid;
+   if (!shutdown)
+       checkPoint.nextOid += ShmemVariableCache->oidCount;
+   LWLockRelease(OidGenLock);
+
+   MultiXactGetCheckptMulti(shutdown,
+                            &checkPoint.nextMulti,
+                            &checkPoint.nextMultiOffset,
+                            &checkPoint.oldestMulti,
+                            &checkPoint.oldestMultiDB);
+
+   /*
+    * Having constructed the checkpoint record, ensure all shmem disk buffers
+    * and commit-log buffers are flushed to disk.
+    *
+    * This I/O could fail for various reasons.  If so, we will fail to
+    * complete the checkpoint, but there is no reason to force a system
+    * panic. Accordingly, exit critical section while doing it.
+    */
+   END_CRIT_SECTION();
+
    /*
     * In some cases there are groups of actions that must all occur on one
     * side or the other of a checkpoint record. Before flushing the
@@ -8116,42 +8152,6 @@ CreateCheckPoint(int flags)
    }
    pfree(vxids);
 
-   /*
-    * Get the other info we need for the checkpoint record.
-    */
-   LWLockAcquire(XidGenLock, LW_SHARED);
-   checkPoint.nextXid = ShmemVariableCache->nextXid;
-   checkPoint.oldestXid = ShmemVariableCache->oldestXid;
-   checkPoint.oldestXidDB = ShmemVariableCache->oldestXidDB;
-   LWLockRelease(XidGenLock);
-
-   /* Increase XID epoch if we've wrapped around since last checkpoint */
-   checkPoint.nextXidEpoch = ControlFile->checkPointCopy.nextXidEpoch;
-   if (checkPoint.nextXid < ControlFile->checkPointCopy.nextXid)
-       checkPoint.nextXidEpoch++;
-
-   LWLockAcquire(OidGenLock, LW_SHARED);
-   checkPoint.nextOid = ShmemVariableCache->nextOid;
-   if (!shutdown)
-       checkPoint.nextOid += ShmemVariableCache->oidCount;
-   LWLockRelease(OidGenLock);
-
-   MultiXactGetCheckptMulti(shutdown,
-                            &checkPoint.nextMulti,
-                            &checkPoint.nextMultiOffset,
-                            &checkPoint.oldestMulti,
-                            &checkPoint.oldestMultiDB);
-
-   /*
-    * Having constructed the checkpoint record, ensure all shmem disk buffers
-    * and commit-log buffers are flushed to disk.
-    *
-    * This I/O could fail for various reasons.  If so, we will fail to
-    * complete the checkpoint, but there is no reason to force a system
-    * panic. Accordingly, exit critical section while doing it.
-    */
-   END_CRIT_SECTION();
-
    CheckPointGuts(checkPoint.redo, flags);
 
    /*