]> granicus.if.org Git - postgresql/commitdiff
Inline initial comparisons in TestForOldSnapshot()
authorKevin Grittner <kgrittn@postgresql.org>
Thu, 21 Apr 2016 13:40:08 +0000 (08:40 -0500)
committerKevin Grittner <kgrittn@postgresql.org>
Thu, 21 Apr 2016 13:40:08 +0000 (08:40 -0500)
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.

src/backend/storage/buffer/bufmgr.c
src/include/storage/bufmgr.h

index ac1e513560c162a53c810d8a35d18a8397513e63..c0d5fa74e102add8a2df483e8249c3b978ef7723 100644 (file)
@@ -4282,33 +4282,15 @@ IssuePendingWritebacks(WritebackContext *context)
 
 
 /*
- * 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.
+ * Implement slower/larger portions of TestForOldSnapshot
  *
- * 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.
+ * Smaller/faster portions are put inline, but the entire set of logic is too
+ * big for that.
  */
 void
-TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
+TestForOldSnapshot_impl(Snapshot snapshot, Relation relation)
 {
-       Assert(relation != NULL);
-
-       if (old_snapshot_threshold >= 0
-        && (snapshot) != NULL
-        && (snapshot)->satisfies == HeapTupleSatisfiesMVCC
-        && !XLogRecPtrIsInvalid((snapshot)->lsn)
-        && PageGetLSN(page) > (snapshot)->lsn
-        && !IsCatalogRelation(relation)
+       if (!IsCatalogRelation(relation)
         && !RelationIsAccessibleInLogicalDecoding(relation)
         && (snapshot)->whenTaken < GetOldSnapshotThresholdTimestamp())
                ereport(ERROR,
index b514b4696d146cdcb229e2d52b68d8c80887b902..38b602724e11512e13cf9899c93fcdb038c3acd5 100644 (file)
@@ -239,7 +239,7 @@ extern bool BgBufferSync(struct WritebackContext *wb_context);
 
 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 */
 extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype);
@@ -257,6 +257,36 @@ extern void FreeAccessStrategy(BufferAccessStrategy strategy);
 
 #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   /* BUFMGR_H */