@@ -78,10 +78,13 @@ typedef struct OldSnapshotControlData
7878 * Variables for old snapshot handling are shared among processes and are
7979 * only allowed to move forward.
8080 */
81- slock_t mutex_current ;/* protectcurrent timestamp */
81+ slock_t mutex_current ;/* protectcurrent_timestamp */
8282int64 current_timestamp ;/* latest snapshot timestamp */
83- slock_t mutex_latest_xmin ;/* protect latest snapshot xmin */
83+ slock_t mutex_latest_xmin ;/* protect latest_xmin
84+ * and next_map_update
85+ */
8486TransactionId latest_xmin ;/* latest snapshot xmin */
87+ int64 next_map_update ;/* latest snapshot valid up to */
8588slock_t mutex_threshold ;/* protect threshold fields */
8689int64 threshold_timestamp ;/* earlier snapshot is old */
8790TransactionId threshold_xid ;/* earlier xid may be gone */
@@ -95,7 +98,10 @@ typedef struct OldSnapshotControlData
9598 * count_used value of OLD_SNAPSHOT_TIME_MAP_ENTRIES means that the buffer
9699 * is full and the head must be advanced to add new entries. Use
97100 * timestamps aligned to minute boundaries, since that seems less
98- * surprising than aligning based on the first usage timestamp.
101+ * surprising than aligning based on the first usage timestamp. The
102+ * latest bucket is effectively stored within latest_xmin. The circular
103+ * buffer is updated when we get a new xmin value that doesn't fall into
104+ * the same interval.
99105 *
100106 * It is OK if the xid for a given time slot is from earlier than
101107 * calculated by adding the number of minutes corresponding to the
@@ -269,6 +275,7 @@ SnapMgrInit(void)
269275oldSnapshotControl -> current_timestamp = 0 ;
270276SpinLockInit (& oldSnapshotControl -> mutex_latest_xmin );
271277oldSnapshotControl -> latest_xmin = InvalidTransactionId ;
278+ oldSnapshotControl -> next_map_update = 0 ;
272279SpinLockInit (& oldSnapshotControl -> mutex_threshold );
273280oldSnapshotControl -> threshold_timestamp = 0 ;
274281oldSnapshotControl -> threshold_xid = InvalidTransactionId ;
@@ -1595,9 +1602,15 @@ TransactionIdLimitedForOldSnapshots(TransactionId recentXmin,
15951602{
15961603int64 ts = GetSnapshotCurrentTimestamp ();
15971604TransactionId xlimit = recentXmin ;
1598- TransactionId latest_xmin = oldSnapshotControl -> latest_xmin ;
1605+ TransactionId latest_xmin ;
1606+ int64 update_ts ;
15991607bool same_ts_as_threshold = false;
16001608
1609+ SpinLockAcquire (& oldSnapshotControl -> mutex_latest_xmin );
1610+ latest_xmin = oldSnapshotControl -> latest_xmin ;
1611+ update_ts = oldSnapshotControl -> next_map_update ;
1612+ SpinLockRelease (& oldSnapshotControl -> mutex_latest_xmin );
1613+
16011614/*
16021615 * Zero threshold always overrides to latest xmin, if valid. Without
16031616 * some heuristic it will find its own snapshot too old on, for
@@ -1632,26 +1645,35 @@ TransactionIdLimitedForOldSnapshots(TransactionId recentXmin,
16321645
16331646if (!same_ts_as_threshold )
16341647{
1635- LWLockAcquire (OldSnapshotTimeMapLock ,LW_SHARED );
1636-
1637- if (oldSnapshotControl -> count_used > 0
1638- && ts >=oldSnapshotControl -> head_timestamp )
1648+ if (ts == update_ts )
16391649{
1640- int offset ;
1641-
1642- offset = ((ts - oldSnapshotControl -> head_timestamp )
1643- /USECS_PER_MINUTE );
1644- if (offset > oldSnapshotControl -> count_used - 1 )
1645- offset = oldSnapshotControl -> count_used - 1 ;
1646- offset = (oldSnapshotControl -> head_offset + offset )
1647- %OLD_SNAPSHOT_TIME_MAP_ENTRIES ;
1648- xlimit = oldSnapshotControl -> xid_by_minute [offset ];
1649-
1650+ xlimit = latest_xmin ;
16501651if (NormalTransactionIdFollows (xlimit ,recentXmin ))
16511652SetOldSnapshotThresholdTimestamp (ts ,xlimit );
16521653}
1654+ else
1655+ {
1656+ LWLockAcquire (OldSnapshotTimeMapLock ,LW_SHARED );
16531657
1654- LWLockRelease (OldSnapshotTimeMapLock );
1658+ if (oldSnapshotControl -> count_used > 0
1659+ && ts >=oldSnapshotControl -> head_timestamp )
1660+ {
1661+ int offset ;
1662+
1663+ offset = ((ts - oldSnapshotControl -> head_timestamp )
1664+ /USECS_PER_MINUTE );
1665+ if (offset > oldSnapshotControl -> count_used - 1 )
1666+ offset = oldSnapshotControl -> count_used - 1 ;
1667+ offset = (oldSnapshotControl -> head_offset + offset )
1668+ %OLD_SNAPSHOT_TIME_MAP_ENTRIES ;
1669+ xlimit = oldSnapshotControl -> xid_by_minute [offset ];
1670+
1671+ if (NormalTransactionIdFollows (xlimit ,recentXmin ))
1672+ SetOldSnapshotThresholdTimestamp (ts ,xlimit );
1673+ }
1674+
1675+ LWLockRelease (OldSnapshotTimeMapLock );
1676+ }
16551677}
16561678
16571679/*
@@ -1681,16 +1703,35 @@ void
16811703MaintainOldSnapshotTimeMapping (int64 whenTaken ,TransactionId xmin )
16821704{
16831705int64 ts ;
1706+ TransactionId latest_xmin ;
1707+ int64 update_ts ;
1708+ bool map_update_required = false;
16841709
16851710/* Never call this function when old snapshot checking is disabled. */
16861711Assert (old_snapshot_threshold >=0 );
16871712
1688- /* Keep track of the latest xmin seen by any process. */
1713+ ts = AlignTimestampToMinuteBoundary (whenTaken );
1714+
1715+ /*
1716+ * Keep track of the latest xmin seen by any process. Update mapping
1717+ * with a new value when we have crossed a bucket boundary.
1718+ */
16891719SpinLockAcquire (& oldSnapshotControl -> mutex_latest_xmin );
1690- if (TransactionIdFollows (xmin ,oldSnapshotControl -> latest_xmin ))
1720+ latest_xmin = oldSnapshotControl -> latest_xmin ;
1721+ update_ts = oldSnapshotControl -> next_map_update ;
1722+ if (ts > update_ts )
1723+ {
1724+ oldSnapshotControl -> next_map_update = ts ;
1725+ map_update_required = true;
1726+ }
1727+ if (TransactionIdFollows (xmin ,latest_xmin ))
16911728oldSnapshotControl -> latest_xmin = xmin ;
16921729SpinLockRelease (& oldSnapshotControl -> mutex_latest_xmin );
16931730
1731+ /* We only needed to update the most recent xmin value. */
1732+ if (!map_update_required )
1733+ return ;
1734+
16941735/* No further tracking needed for 0 (used for testing). */
16951736if (old_snapshot_threshold == 0 )
16961737return ;
@@ -1716,8 +1757,6 @@ MaintainOldSnapshotTimeMapping(int64 whenTaken, TransactionId xmin)
17161757return ;
17171758}
17181759
1719- ts = AlignTimestampToMinuteBoundary (whenTaken );
1720-
17211760LWLockAcquire (OldSnapshotTimeMapLock ,LW_EXCLUSIVE );
17221761
17231762Assert (oldSnapshotControl -> head_offset >=0 );