1 /*-------------------------------------------------------------------------
2  *
3  * old_snapshot.h
4  *		Data structures for 'snapshot too old'
5  *
6  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  * IDENTIFICATION
10  *	  src/include/utils/old_snapshot.h
11  *
12  *-------------------------------------------------------------------------
13  */
14 
15 #ifndef OLD_SNAPSHOT_H
16 #define OLD_SNAPSHOT_H
17 
18 #include "datatype/timestamp.h"
19 #include "storage/s_lock.h"
20 
21 /*
22  * Structure for dealing with old_snapshot_threshold implementation.
23  */
24 typedef struct OldSnapshotControlData
25 {
26 	/*
27 	 * Variables for old snapshot handling are shared among processes and are
28 	 * only allowed to move forward.
29 	 */
30 	slock_t		mutex_current;	/* protect current_timestamp */
31 	TimestampTz current_timestamp;	/* latest snapshot timestamp */
32 	slock_t		mutex_latest_xmin;	/* protect latest_xmin and next_map_update */
33 	TransactionId latest_xmin;	/* latest snapshot xmin */
34 	TimestampTz next_map_update;	/* latest snapshot valid up to */
35 	slock_t		mutex_threshold;	/* protect threshold fields */
36 	TimestampTz threshold_timestamp;	/* earlier snapshot is old */
37 	TransactionId threshold_xid;	/* earlier xid may be gone */
38 
39 	/*
40 	 * Keep one xid per minute for old snapshot error handling.
41 	 *
42 	 * Use a circular buffer with a head offset, a count of entries currently
43 	 * used, and a timestamp corresponding to the xid at the head offset.  A
44 	 * count_used value of zero means that there are no times stored; a
45 	 * count_used value of OLD_SNAPSHOT_TIME_MAP_ENTRIES means that the buffer
46 	 * is full and the head must be advanced to add new entries.  Use
47 	 * timestamps aligned to minute boundaries, since that seems less
48 	 * surprising than aligning based on the first usage timestamp.  The
49 	 * latest bucket is effectively stored within latest_xmin.  The circular
50 	 * buffer is updated when we get a new xmin value that doesn't fall into
51 	 * the same interval.
52 	 *
53 	 * It is OK if the xid for a given time slot is from earlier than
54 	 * calculated by adding the number of minutes corresponding to the
55 	 * (possibly wrapped) distance from the head offset to the time of the
56 	 * head entry, since that just results in the vacuuming of old tuples
57 	 * being slightly less aggressive.  It would not be OK for it to be off in
58 	 * the other direction, since it might result in vacuuming tuples that are
59 	 * still expected to be there.
60 	 *
61 	 * Use of an SLRU was considered but not chosen because it is more
62 	 * heavyweight than is needed for this, and would probably not be any less
63 	 * code to implement.
64 	 *
65 	 * Persistence is not needed.
66 	 */
67 	int			head_offset;	/* subscript of oldest tracked time */
68 	TimestampTz head_timestamp; /* time corresponding to head xid */
69 	int			count_used;		/* how many slots are in use */
70 	TransactionId xid_by_minute[FLEXIBLE_ARRAY_MEMBER];
71 } OldSnapshotControlData;
72 
73 extern PGDLLIMPORT volatile OldSnapshotControlData *oldSnapshotControl;
74 
75 #endif
76