34
34
/* pointer to "variable cache" in shared memory (set up by shmem.c) */
35
35
VariableCache ShmemVariableCache = NULL ;
36
36
37
- TransactionId GetNextTransactionId ()
37
+ TransactionId
38
+ GetNewTransactionId (bool isSubXact )
38
39
{
39
- return ShmemVariableCache -> nextXid ;
40
+ return TM -> GetNewTransactionId ( isSubXactShmemVariableCache -> nextXid ;
40
41
}
41
42
42
43
/*
@@ -50,206 +51,8 @@ TransactionId GetNextTransactionId()
50
51
* issue a warning about XID wrap.
51
52
*/
52
53
TransactionId
53
- GetNewTransactionId (bool isSubXact )
54
+ GetNewLocalTransactionId (bool isSubXact )
54
55
{
55
- TransactionId xid ;
56
-
57
- /*
58
- * Workers synchronize transaction state at the beginning of each parallel
59
- * operation, so we can't account for new XIDs after that point.
60
- */
61
- if (IsInParallelMode ())
62
- elog (ERROR , "cannot assign TransactionIds during a parallel operation" );
63
-
64
- /*
65
- * During bootstrap initialization, we return the special bootstrap
66
- * transaction id.
67
- */
68
- if (IsBootstrapProcessingMode ())
69
- {
70
- Assert (!isSubXact );
71
- MyPgXact -> xid = BootstrapTransactionId ;
72
- return BootstrapTransactionId ;
73
- }
74
-
75
- /* safety check, we should never get this far in a HS slave */
76
- if (RecoveryInProgress ())
77
- elog (ERROR , "cannot assign TransactionIds during recovery" );
78
-
79
- LWLockAcquire (XidGenLock , LW_EXCLUSIVE );
80
-
81
- xid = TM -> GetNextXid ();
82
-
83
- /*----------
84
- * Check to see if it's safe to assign another XID. This protects against
85
- * catastrophic data loss due to XID wraparound. The basic rules are:
86
- *
87
- * If we're past xidVacLimit, start trying to force autovacuum cycles.
88
- * If we're past xidWarnLimit, start issuing warnings.
89
- * If we're past xidStopLimit, refuse to execute transactions, unless
90
- * we are running in single-user mode (which gives an escape hatch
91
- * to the DBA who somehow got past the earlier defenses).
92
- *
93
- * Note that this coding also appears in GetNewMultiXactId.
94
- *----------
95
- */
96
- if (TransactionIdFollowsOrEquals (xid , ShmemVariableCache -> xidVacLimit ))
97
- {
98
- /*
99
- * For safety's sake, we release XidGenLock while sending signals,
100
- * warnings, etc. This is not so much because we care about
101
- * preserving concurrency in this situation, as to avoid any
102
- * possibility of deadlock while doing get_database_name(). First,
103
- * copy all the shared values we'll need in this path.
104
- */
105
- TransactionId xidWarnLimit = ShmemVariableCache -> xidWarnLimit ;
106
- TransactionId xidStopLimit = ShmemVariableCache -> xidStopLimit ;
107
- TransactionId xidWrapLimit = ShmemVariableCache -> xidWrapLimit ;
108
- Oid oldest_datoid = ShmemVariableCache -> oldestXidDB ;
109
-
110
- LWLockRelease (XidGenLock );
111
-
112
- /*
113
- * To avoid swamping the postmaster with signals, we issue the autovac
114
- * request only once per 64K transaction starts. This still gives
115
- * plenty of chances before we get into real trouble.
116
- */
117
- if (IsUnderPostmaster && (xid % 65536 ) == 0 )
118
- SendPostmasterSignal (PMSIGNAL_START_AUTOVAC_LAUNCHER );
119
-
120
- if (IsUnderPostmaster &&
121
- TransactionIdFollowsOrEquals (xid , xidStopLimit ))
122
- {
123
- char * oldest_datname = get_database_name (oldest_datoid );
124
-
125
- /* complain even if that DB has disappeared */
126
- if (oldest_datname )
127
- ereport (ERROR ,
128
- (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
129
- errmsg ("database is not accepting commands to avoid wraparound data loss in database \"%s\"" ,
130
- oldest_datname ),
131
- errhint ("Stop the postmaster and vacuum that database in single-user mode.\n"
132
- "You might also need to commit or roll back old prepared transactions." )));
133
- else
134
- ereport (ERROR ,
135
- (errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
136
- errmsg ("database is not accepting commands to avoid wraparound data loss in database with OID %u" ,
137
- oldest_datoid ),
138
- errhint ("Stop the postmaster and vacuum that database in single-user mode.\n"
139
- "You might also need to commit or roll back old prepared transactions." )));
140
- }
141
- else if (TransactionIdFollowsOrEquals (xid , xidWarnLimit ))
142
- {
143
- char * oldest_datname = get_database_name (oldest_datoid );
144
-
145
- /* complain even if that DB has disappeared */
146
- if (oldest_datname )
147
- ereport (WARNING ,
148
- (errmsg ("database \"%s\" must be vacuumed within %u transactions" ,
149
- oldest_datname ,
150
- xidWrapLimit - xid ),
151
- errhint ("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
152
- "You might also need to commit or roll back old prepared transactions." )));
153
- else
154
- ereport (WARNING ,
155
- (errmsg ("database with OID %u must be vacuumed within %u transactions" ,
156
- oldest_datoid ,
157
- xidWrapLimit - xid ),
158
- errhint ("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
159
- "You might also need to commit or roll back old prepared transactions." )));
160
- }
161
-
162
- /* Re-acquire lock and start over */
163
- LWLockAcquire (XidGenLock , LW_EXCLUSIVE );
164
- xid = TM -> GetNextXid ();
165
- }
166
-
167
- /*
168
- * If we are allocating the first XID of a new page of the commit log,
169
- * zero out that commit-log page before returning. We must do this while
170
- * holding XidGenLock, else another xact could acquire and commit a later
171
- * XID before we zero the page. Fortunately, a page of the commit log
172
- * holds 32K or more transactions, so we don't have to do this very often.
173
- *
174
- * Extend pg_subtrans and pg_commit_ts too.
175
- */
176
- ExtendCLOG (xid );
177
- ExtendCommitTs (xid );
178
- ExtendSUBTRANS (xid );
179
-
180
- /*
181
- * Now advance the nextXid counter. This must not happen until after we
182
- * have successfully completed ExtendCLOG() --- if that routine fails, we
183
- * want the next incoming transaction to try it again. We cannot assign
184
- * more XIDs until there is CLOG space for them.
185
- */
186
- if (xid == ShmemVariableCache -> nextXid ) {
187
- TransactionIdAdvance (ShmemVariableCache -> nextXid );
188
- } else {
189
- Assert (TransactionIdPrecedes (xid , ShmemVariableCache -> nextXid ));
190
- }
191
-
192
- /*
193
- * We must store the new XID into the shared ProcArray before releasing
194
- * XidGenLock. This ensures that every active XID older than
195
- * latestCompletedXid is present in the ProcArray, which is essential for
196
- * correct OldestXmin tracking; see src/backend/access/transam/README.
197
- *
198
- * XXX by storing xid into MyPgXact without acquiring ProcArrayLock, we
199
- * are relying on fetch/store of an xid to be atomic, else other backends
200
- * might see a partially-set xid here. But holding both locks at once
201
- * would be a nasty concurrency hit. So for now, assume atomicity.
202
- *
203
- * Note that readers of PGXACT xid fields should be careful to fetch the
204
- * value only once, rather than assume they can read a value multiple
205
- * times and get the same answer each time.
206
- *
207
- * The same comments apply to the subxact xid count and overflow fields.
208
- *
209
- * A solution to the atomic-store problem would be to give each PGXACT its
210
- * own spinlock used only for fetching/storing that PGXACT's xid and
211
- * related fields.
212
- *
213
- * If there's no room to fit a subtransaction XID into PGPROC, set the
214
- * cache-overflowed flag instead. This forces readers to look in
215
- * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
216
- * race-condition window, in that the new XID will not appear as running
217
- * until its parent link has been placed into pg_subtrans. However, that
218
- * will happen before anyone could possibly have a reason to inquire about
219
- * the status of the XID, so it seems OK. (Snapshots taken during this
220
- * window *will* include the parent XID, so they will deliver the correct
221
- * answer later on when someone does have a reason to inquire.)
222
- */
223
- {
224
- /*
225
- * Use volatile pointer to prevent code rearrangement; other backends
226
- * could be examining my subxids info concurrently, and we don't want
227
- * them to see an invalid intermediate state, such as incrementing
228
- * nxids before filling the array entry. Note we are assuming that
229
- * TransactionId and int fetch/store are atomic.
230
- */
231
- volatile PGPROC * myproc = MyProc ;
232
- volatile PGXACT * mypgxact = MyPgXact ;
233
-
234
- if (!isSubXact )
235
- mypgxact -> xid = xid ;
236
- else
237
- {
238
- int nxids = mypgxact -> nxids ;
239
-
240
- if (nxids < PGPROC_MAX_CACHED_SUBXIDS )
241
- {
242
- myproc -> subxids .xids [nxids ] = xid ;
243
- mypgxact -> nxids = nxids + 1 ;
244
- }
245
- else
246
- mypgxact -> overflowed = true;
247
- }
248
- }
249
-
250
- LWLockRelease (XidGenLock );
251
-
252
- return xid ;
253
56
}
254
57
255
58
/*
0 commit comments