From 4a78cdeb6b598940e9d9adb92deca6494628802a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 1 Aug 2007 22:45:09 +0000 Subject: Support an optional asynchronous commit mode, in which we don't flush WAL before reporting a transaction committed. Data consistency is still guaranteed (unlike setting fsync = off), but a crash may lose the effects of the last few transactions. Patch by Simon, some editorialization by Tom. --- src/backend/access/transam/xact.c | 90 +++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 17 deletions(-) (limited to 'src/backend/access/transam/xact.c') diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 72a7cf40a63..117525b5ac4 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.245 2007/06/07 21:45:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.246 2007/08/01 22:45:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -55,6 +55,8 @@ int XactIsoLevel; bool DefaultXactReadOnly = false; bool XactReadOnly; +bool XactSyncCommit = true; + int CommitDelay = 0; /* precommit delay in microseconds */ int CommitSiblings = 5; /* # concurrent xacts needed to sleep */ @@ -174,6 +176,11 @@ static TimestampTz xactStopTimestamp; */ static char *prepareGID; +/* + * Some commands want to force synchronous commit. + */ +static bool forceSyncCommit = false; + /* * Private context for transaction-abort work --- we reserve space for this * at startup to ensure that AbortTransaction and AbortSubTransaction can work @@ -554,6 +561,18 @@ CommandCounterIncrement(void) AtStart_Cache(); } +/* + * ForceSyncCommit + * + * Interface routine to allow commands to force a synchronous commit of the + * current top-level transaction + */ +void +ForceSyncCommit(void) +{ + forceSyncCommit = true; +} + /* ---------------------------------------------------------------- * StartTransaction stuff @@ -724,6 +743,7 @@ RecordTransactionCommit(void) { TransactionId xid = GetCurrentTransactionId(); bool madeTCentries; + bool isAsyncCommit = false; XLogRecPtr recptr; /* Tell bufmgr and smgr to prepare for commit */ @@ -810,21 +830,44 @@ RecordTransactionCommit(void) if (MyXactMadeXLogEntry) { /* - * Sleep before flush! So we can flush more than one commit - * records per single fsync. (The idea is some other backend may - * do the XLogFlush while we're sleeping. This needs work still, - * because on most Unixen, the minimum select() delay is 10msec or - * more, which is way too long.) - * - * We do not sleep if enableFsync is not turned on, nor if there - * are fewer than CommitSiblings other backends with active - * transactions. + * If the user has set synchronous_commit = off, and we're + * not doing cleanup of any rels nor committing any command + * that wanted to force sync commit, then we can defer fsync. */ - if (CommitDelay > 0 && enableFsync && - CountActiveBackends() >= CommitSiblings) - pg_usleep(CommitDelay); + if (XactSyncCommit || forceSyncCommit || nrels > 0) + { + /* + * Synchronous commit case. + * + * Sleep before flush! So we can flush more than one commit + * records per single fsync. (The idea is some other backend + * may do the XLogFlush while we're sleeping. This needs work + * still, because on most Unixen, the minimum select() delay + * is 10msec or more, which is way too long.) + * + * We do not sleep if enableFsync is not turned on, nor if + * there are fewer than CommitSiblings other backends with + * active transactions. + */ + if (CommitDelay > 0 && enableFsync && + CountActiveBackends() >= CommitSiblings) + pg_usleep(CommitDelay); - XLogFlush(recptr); + XLogFlush(recptr); + } + else + { + /* + * Asynchronous commit case. + */ + isAsyncCommit = true; + + /* + * Report the latest async commit LSN, so that + * the WAL writer knows to flush this commit. + */ + XLogSetAsyncCommitLSN(recptr); + } } /* @@ -835,12 +878,24 @@ RecordTransactionCommit(void) * emitted an XLOG record for our commit, and so in the event of a * crash the clog update might be lost. This is okay because no one * else will ever care whether we committed. + * + * The recptr here refers to the last xlog entry by this transaction + * so is the correct value to use for setting the clog. */ if (madeTCentries || MyXactMadeTempRelUpdate) { - TransactionIdCommit(xid); - /* to avoid race conditions, the parent must commit first */ - TransactionIdCommitTree(nchildren, children); + if (isAsyncCommit) + { + TransactionIdAsyncCommit(xid, recptr); + /* to avoid race conditions, the parent must commit first */ + TransactionIdAsyncCommitTree(nchildren, children, recptr); + } + else + { + TransactionIdCommit(xid); + /* to avoid race conditions, the parent must commit first */ + TransactionIdCommitTree(nchildren, children); + } } /* Checkpoint can proceed now */ @@ -1406,6 +1461,7 @@ StartTransaction(void) FreeXactSnapshot(); XactIsoLevel = DefaultXactIsoLevel; XactReadOnly = DefaultXactReadOnly; + forceSyncCommit = false; /* * reinitialize within-transaction counters -- cgit v1.2.3