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.
This commit is contained in:
parent
5b1f9ce1d9
commit
11e178d0dc
@ -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);
|
|||||||
|
|
||||||
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);
|
|||||||
|
|
||||||
#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 */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user