Commit e620ee35 authored by Simon Riggs's avatar Simon Riggs

Optimize commit_siblings in two ways to improve group commit.

First, avoid scanning the whole ProcArray once we know there
are at least commit_siblings active; second, skip the check
altogether if commit_siblings = 0.

Greg Smith
parent 5a031a55
...@@ -1683,17 +1683,24 @@ SET ENABLE_SEQSCAN TO OFF; ...@@ -1683,17 +1683,24 @@ SET ENABLE_SEQSCAN TO OFF;
</indexterm> </indexterm>
<listitem> <listitem>
<para> <para>
Time delay between writing a commit record to the WAL buffer When the commit data for a transaction is flushed to disk, any
and flushing the buffer out to disk, in microseconds. A additional commits ready at that time are also flushed out.
nonzero delay can allow multiple transactions to be committed <varname>commit_delay</varname> adds a time delay, set in
with only one <function>fsync()</function> system call, if microseconds, before writing some commit records to the WAL
buffer and flushing the buffer out to disks. A nonzero delay
can allow more transactions to be committed with only one call
to the active <varname>wal_sync_method</varname>, if
system load is high enough that additional transactions become system load is high enough that additional transactions become
ready to commit within the given interval. But the delay is ready to commit within the given interval. But the delay is
just wasted if no other transactions become ready to just wasted if no other transactions become ready to
commit. Therefore, the delay is only performed if at least commit. Therefore, the delay is only performed if at least
<varname>commit_siblings</varname> other transactions are <varname>commit_siblings</varname> other transactions are
active at the instant that a server process has written its active at the instant that a server process has written its
commit record. The default is zero (no delay). commit record. The default is zero (no delay). Since
all pending commit data flushes are written at every flush
regardless of this setting, it is rare that adding delay to
that by increasing this parameter will actually improve commit
performance.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
...@@ -1052,7 +1052,7 @@ RecordTransactionCommit(void) ...@@ -1052,7 +1052,7 @@ RecordTransactionCommit(void)
* fewer than CommitSiblings other backends with active transactions. * fewer than CommitSiblings other backends with active transactions.
*/ */
if (CommitDelay > 0 && enableFsync && if (CommitDelay > 0 && enableFsync &&
CountActiveBackends() >= CommitSiblings) MinimumActiveBackends(CommitSiblings))
pg_usleep(CommitDelay); pg_usleep(CommitDelay);
XLogFlush(XactLastRecEnd); XLogFlush(XactLastRecEnd);
......
...@@ -1886,20 +1886,25 @@ CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode) ...@@ -1886,20 +1886,25 @@ CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
} }
/* /*
* CountActiveBackends --- count backends (other than myself) that are in * MinimumActiveBackends --- count backends (other than myself) that are
* active transactions. This is used as a heuristic to decide if * in active transactions. Return true if the count exceeds the
* minimum threshold passed. This is used as a heuristic to decide if
* a pre-XLOG-flush delay is worthwhile during commit. * a pre-XLOG-flush delay is worthwhile during commit.
* *
* Do not count backends that are blocked waiting for locks, since they are * Do not count backends that are blocked waiting for locks, since they are
* not going to get to run until someone else commits. * not going to get to run until someone else commits.
*/ */
int bool
CountActiveBackends(void) MinimumActiveBackends(int min)
{ {
ProcArrayStruct *arrayP = procArray; ProcArrayStruct *arrayP = procArray;
int count = 0; int count = 0;
int index; int index;
/* Quick short-circuit if no minimum is specified */
if (min == 0)
return true;
/* /*
* Note: for speed, we don't acquire ProcArrayLock. This is a little bit * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
* bogus, but since we are only testing fields for zero or nonzero, it * bogus, but since we are only testing fields for zero or nonzero, it
...@@ -1932,9 +1937,11 @@ CountActiveBackends(void) ...@@ -1932,9 +1937,11 @@ CountActiveBackends(void)
if (proc->waitLock != NULL) if (proc->waitLock != NULL)
continue; /* do not count if blocked on a lock */ continue; /* do not count if blocked on a lock */
count++; count++;
if (count >= min)
break;
} }
return count; return count >= min;
} }
/* /*
......
...@@ -1816,7 +1816,7 @@ static struct config_int ConfigureNamesInt[] = ...@@ -1816,7 +1816,7 @@ static struct config_int ConfigureNamesInt[] =
NULL NULL
}, },
&CommitSiblings, &CommitSiblings,
5, 1, 1000, NULL, NULL 5, 0, 1000, NULL, NULL
}, },
{ {
......
...@@ -60,7 +60,7 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin, ...@@ -60,7 +60,7 @@ extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid); extern VirtualTransactionId *GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid);
extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode); extern pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode);
extern int CountActiveBackends(void); extern bool MinimumActiveBackends(int min);
extern int CountDBBackends(Oid databaseid); extern int CountDBBackends(Oid databaseid);
extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending); extern void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending);
extern int CountUserBackends(Oid roleid); extern int CountUserBackends(Oid roleid);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment