Skip to content

Commit 7c3e803

Browse files
committed
Add a few entries to the tail of time mapping, to see old values.
Without a few entries beyond old_snapshot_threshold, the lookup would often fail, resulting in the more aggressive pruning or vacuum being skipped often enough to matter. This was very clearly shown by a python test script posted by Ants Aasma, and was likely a factor in an earlier but somewhat less clear-cut test case posted by Jeff Janes. This patch makes no change to the logic, per se -- it just makes the array of mapping entries big enough to make lookup misses based on timing much less likely. An occasional miss is still possible if a thread stalls for more than 10 minutes, but that does not create any problem with correctness of behavior. Besides, if things are so busy that a thread is stalling for more than 10 minutes, it is probably OK to skip the more aggressive cleanup at that particular point in time.
1 parent d34e7b2 commit 7c3e803

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

src/backend/utils/time/snapmgr.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,10 @@ typedef struct OldSnapshotControlData
9292
* Use a circular buffer with a head offset, a count of entries currently
9393
* used, and a timestamp corresponding to the xid at the head offset. A
9494
* count_used value of zero means that there are no times stored; a
95-
* count_used value of old_snapshot_threshold means that the buffer is
96-
* full and the head must be advanced to add new entries. Use timestamps
97-
* aligned to minute boundaries, since that seems less surprising than
98-
* aligning based on the first usage timestamp.
95+
* count_used value of OLD_SNAPSHOT_TIME_MAP_ENTRIES means that the buffer
96+
* is full and the head must be advanced to add new entries. Use
97+
* timestamps aligned to minute boundaries, since that seems less
98+
* surprising than aligning based on the first usage timestamp.
9999
*
100100
* It is OK if the xid for a given time slot is from earlier than
101101
* calculated by adding the number of minutes corresponding to the
@@ -243,7 +243,7 @@ SnapMgrShmemSize(void)
243243
size = offsetof(OldSnapshotControlData, xid_by_minute);
244244
if (old_snapshot_threshold > 0)
245245
size = add_size(size, mul_size(sizeof(TransactionId),
246-
old_snapshot_threshold));
246+
OLD_SNAPSHOT_TIME_MAP_ENTRIES));
247247

248248
return size;
249249
}
@@ -1643,7 +1643,7 @@ TransactionIdLimitedForOldSnapshots(TransactionId recentXmin,
16431643
if (offset > oldSnapshotControl->count_used - 1)
16441644
offset = oldSnapshotControl->count_used - 1;
16451645
offset = (oldSnapshotControl->head_offset + offset)
1646-
% old_snapshot_threshold;
1646+
% OLD_SNAPSHOT_TIME_MAP_ENTRIES;
16471647
xlimit = oldSnapshotControl->xid_by_minute[offset];
16481648

16491649
if (NormalTransactionIdFollows(xlimit, recentXmin))
@@ -1720,10 +1720,10 @@ MaintainOldSnapshotTimeMapping(int64 whenTaken, TransactionId xmin)
17201720
LWLockAcquire(OldSnapshotTimeMapLock, LW_EXCLUSIVE);
17211721

17221722
Assert(oldSnapshotControl->head_offset >= 0);
1723-
Assert(oldSnapshotControl->head_offset < old_snapshot_threshold);
1723+
Assert(oldSnapshotControl->head_offset < OLD_SNAPSHOT_TIME_MAP_ENTRIES);
17241724
Assert((oldSnapshotControl->head_timestamp % USECS_PER_MINUTE) == 0);
17251725
Assert(oldSnapshotControl->count_used >= 0);
1726-
Assert(oldSnapshotControl->count_used <= old_snapshot_threshold);
1726+
Assert(oldSnapshotControl->count_used <= OLD_SNAPSHOT_TIME_MAP_ENTRIES);
17271727

17281728
if (oldSnapshotControl->count_used == 0)
17291729
{
@@ -1750,7 +1750,7 @@ MaintainOldSnapshotTimeMapping(int64 whenTaken, TransactionId xmin)
17501750
int bucket = (oldSnapshotControl->head_offset
17511751
+ ((ts - oldSnapshotControl->head_timestamp)
17521752
/ USECS_PER_MINUTE))
1753-
% old_snapshot_threshold;
1753+
% OLD_SNAPSHOT_TIME_MAP_ENTRIES;
17541754

17551755
if (TransactionIdPrecedes(oldSnapshotControl->xid_by_minute[bucket], xmin))
17561756
oldSnapshotControl->xid_by_minute[bucket] = xmin;
@@ -1763,7 +1763,7 @@ MaintainOldSnapshotTimeMapping(int64 whenTaken, TransactionId xmin)
17631763

17641764
oldSnapshotControl->head_timestamp = ts;
17651765

1766-
if (advance >= old_snapshot_threshold)
1766+
if (advance >= OLD_SNAPSHOT_TIME_MAP_ENTRIES)
17671767
{
17681768
/* Advance is so far that all old data is junk; start over. */
17691769
oldSnapshotControl->head_offset = 0;
@@ -1777,12 +1777,12 @@ MaintainOldSnapshotTimeMapping(int64 whenTaken, TransactionId xmin)
17771777

17781778
for (i = 0; i < advance; i++)
17791779
{
1780-
if (oldSnapshotControl->count_used == old_snapshot_threshold)
1780+
if (oldSnapshotControl->count_used == OLD_SNAPSHOT_TIME_MAP_ENTRIES)
17811781
{
17821782
/* Map full and new value replaces old head. */
17831783
int old_head = oldSnapshotControl->head_offset;
17841784

1785-
if (old_head == (old_snapshot_threshold - 1))
1785+
if (old_head == (OLD_SNAPSHOT_TIME_MAP_ENTRIES - 1))
17861786
oldSnapshotControl->head_offset = 0;
17871787
else
17881788
oldSnapshotControl->head_offset = old_head + 1;
@@ -1793,7 +1793,7 @@ MaintainOldSnapshotTimeMapping(int64 whenTaken, TransactionId xmin)
17931793
/* Extend map to unused entry. */
17941794
int new_tail = (oldSnapshotControl->head_offset
17951795
+ oldSnapshotControl->count_used)
1796-
% old_snapshot_threshold;
1796+
% OLD_SNAPSHOT_TIME_MAP_ENTRIES;
17971797

17981798
oldSnapshotControl->count_used++;
17991799
oldSnapshotControl->xid_by_minute[new_tail] = xmin;

src/include/utils/snapmgr.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,19 @@
1919
#include "utils/snapshot.h"
2020

2121

22+
/*
23+
* The structure used to map times to TransactionId values for the "snapshot
24+
* too old" feature must have a few entries at the tail to hold old values;
25+
* otherwise the lookup will often fail and the expected early pruning or
26+
* vacuum will not usually occur. It is best if this padding is for a number
27+
* of minutes greater than a thread would normally be stalled, but it's OK if
28+
* early vacuum opportunities are occasionally missed, so there's no need to
29+
* use an extreme value or get too fancy. 10 minutes seems plenty.
30+
*/
31+
#define OLD_SNAPSHOT_PADDING_ENTRIES 10
32+
#define OLD_SNAPSHOT_TIME_MAP_ENTRIES (old_snapshot_threshold + OLD_SNAPSHOT_PADDING_ENTRIES)
33+
34+
2235
/* GUC variables */
2336
extern PGDLLIMPORT int old_snapshot_threshold;
2437

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy