Commit 11e178d0 authored by Kevin Grittner's avatar Kevin Grittner

Inline initial comparisons in TestForOldSnapshot()

Even with old_snapshot_threshold = -1 (which disables the "snapshot
too old" feature), performance regressions were seen at moderate to
high concurrency.  For example, a one-socket, four-core system
running 200 connections at saturation could see up to a 2.3%
regression, with larger regressions possible on NUMA machines.
By inlining the early (smaller, faster) tests in the
TestForOldSnapshot() function, the i7 case dropped to a 0.2%
regression, which could easily just be noise, and is clearly an
improvement.  Further testing will show whether more is needed.
parent 5b1f9ce1
...@@ -4282,33 +4282,15 @@ IssuePendingWritebacks(WritebackContext *context) ...@@ -4282,33 +4282,15 @@ IssuePendingWritebacks(WritebackContext *context)
/* /*
* Check whether the given snapshot is too old to have safely read the given * Implement slower/larger portions of TestForOldSnapshot
* page from the given table. If so, throw a "snapshot too old" error.
* *
* This test generally needs to be performed after every BufferGetPage() call * Smaller/faster portions are put inline, but the entire set of logic is too
* that is executed as part of a scan. It is not needed for calls made for * big for that.
* modifying the page (for example, to position to the right place to insert a
* new index tuple or for vacuuming). It may also be omitted where calls to
* lower-level functions will have already performed the test.
*
* Note that a NULL snapshot argument is allowed and causes a fast return
* without error; this is to support call sites which can be called from
* either scans or index modification areas.
*
* For best performance, keep the tests that are fastest and/or most likely to
* exclude a page from old snapshot testing near the front.
*/ */
void void
TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page) TestForOldSnapshot_impl(Snapshot snapshot, Relation relation)
{ {
Assert(relation != NULL); if (!IsCatalogRelation(relation)
if (old_snapshot_threshold >= 0
&& (snapshot) != NULL
&& (snapshot)->satisfies == HeapTupleSatisfiesMVCC
&& !XLogRecPtrIsInvalid((snapshot)->lsn)
&& PageGetLSN(page) > (snapshot)->lsn
&& !IsCatalogRelation(relation)
&& !RelationIsAccessibleInLogicalDecoding(relation) && !RelationIsAccessibleInLogicalDecoding(relation)
&& (snapshot)->whenTaken < GetOldSnapshotThresholdTimestamp()) && (snapshot)->whenTaken < GetOldSnapshotThresholdTimestamp())
ereport(ERROR, ereport(ERROR,
......
...@@ -239,7 +239,7 @@ extern bool BgBufferSync(struct WritebackContext *wb_context); ...@@ -239,7 +239,7 @@ extern bool BgBufferSync(struct WritebackContext *wb_context);
extern void AtProcExit_LocalBuffers(void); extern void AtProcExit_LocalBuffers(void);
extern void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page); extern void TestForOldSnapshot_impl(Snapshot snapshot, Relation relation);
/* in freelist.c */ /* in freelist.c */
extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype); extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype);
...@@ -257,6 +257,36 @@ extern void FreeAccessStrategy(BufferAccessStrategy strategy); ...@@ -257,6 +257,36 @@ extern void FreeAccessStrategy(BufferAccessStrategy strategy);
#ifndef FRONTEND #ifndef FRONTEND
/*
* Check whether the given snapshot is too old to have safely read the given
* page from the given table. If so, throw a "snapshot too old" error.
*
* This test generally needs to be performed after every BufferGetPage() call
* that is executed as part of a scan. It is not needed for calls made for
* modifying the page (for example, to position to the right place to insert a
* new index tuple or for vacuuming). It may also be omitted where calls to
* lower-level functions will have already performed the test.
*
* Note that a NULL snapshot argument is allowed and causes a fast return
* without error; this is to support call sites which can be called from
* either scans or index modification areas.
*
* For best performance, keep the tests that are fastest and/or most likely to
* exclude a page from old snapshot testing near the front.
*/
static inline void
TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
{
Assert(relation != NULL);
if (old_snapshot_threshold >= 0
&& (snapshot) != NULL
&& (snapshot)->satisfies == HeapTupleSatisfiesMVCC
&& !XLogRecPtrIsInvalid((snapshot)->lsn)
&& PageGetLSN(page) > (snapshot)->lsn)
TestForOldSnapshot_impl(snapshot, relation);
}
#endif /* FRONTEND */ #endif /* FRONTEND */
#endif /* BUFMGR_H */ #endif /* BUFMGR_H */
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