/src/postgres/src/backend/utils/time/snapmgr.c
Line | Count | Source |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * snapmgr.c |
4 | | * PostgreSQL snapshot manager |
5 | | * |
6 | | * The following functions return an MVCC snapshot that can be used in tuple |
7 | | * visibility checks: |
8 | | * |
9 | | * - GetTransactionSnapshot |
10 | | * - GetLatestSnapshot |
11 | | * - GetCatalogSnapshot |
12 | | * - GetNonHistoricCatalogSnapshot |
13 | | * |
14 | | * Each of these functions returns a reference to a statically allocated |
15 | | * snapshot. The statically allocated snapshot is subject to change on any |
16 | | * snapshot-related function call, and should not be used directly. Instead, |
17 | | * call PushActiveSnapshot() or RegisterSnapshot() to create a longer-lived |
18 | | * copy and use that. |
19 | | * |
20 | | * We keep track of snapshots in two ways: those "registered" by resowner.c, |
21 | | * and the "active snapshot" stack. All snapshots in either of them live in |
22 | | * persistent memory. When a snapshot is no longer in any of these lists |
23 | | * (tracked by separate refcounts on each snapshot), its memory can be freed. |
24 | | * |
25 | | * In addition to the above-mentioned MVCC snapshots, there are some special |
26 | | * snapshots like SnapshotSelf, SnapshotAny, and "dirty" snapshots. They can |
27 | | * only be used in limited contexts and cannot be registered or pushed to the |
28 | | * active stack. |
29 | | * |
30 | | * ActiveSnapshot stack |
31 | | * -------------------- |
32 | | * |
33 | | * Most visibility checks use the current "active snapshot" returned by |
34 | | * GetActiveSnapshot(). When running normal queries, the active snapshot is |
35 | | * set when query execution begins based on the transaction isolation level. |
36 | | * |
37 | | * The active snapshot is tracked in a stack so that the currently active one |
38 | | * is at the top of the stack. It mirrors the process call stack: whenever we |
39 | | * recurse or switch context to fetch rows from a different portal for |
40 | | * example, the appropriate snapshot is pushed to become the active snapshot, |
41 | | * and popped on return. Once upon a time, ActiveSnapshot was just a global |
42 | | * variable that was saved and restored similar to CurrentMemoryContext, but |
43 | | * nowadays it's managed as a separate data structure so that we can keep |
44 | | * track of which snapshots are in use and reset MyProc->xmin when there is no |
45 | | * active snapshot. |
46 | | * |
47 | | * However, there are a couple of exceptions where the active snapshot stack |
48 | | * does not strictly mirror the call stack: |
49 | | * |
50 | | * - VACUUM and a few other utility commands manage their own transactions, |
51 | | * which take their own snapshots. They are called with an active snapshot |
52 | | * set, like most utility commands, but they pop the active snapshot that |
53 | | * was pushed by the caller. PortalRunUtility knows about the possibility |
54 | | * that the snapshot it pushed is no longer active on return. |
55 | | * |
56 | | * - When COMMIT or ROLLBACK is executed within a procedure or DO-block, the |
57 | | * active snapshot stack is destroyed, and re-established later when |
58 | | * subsequent statements in the procedure are executed. There are many |
59 | | * limitations on when in-procedure COMMIT/ROLLBACK is allowed; one such |
60 | | * limitation is that all the snapshots on the active snapshot stack are |
61 | | * known to portals that are being executed, which makes it safe to reset |
62 | | * the stack. See EnsurePortalSnapshotExists(). |
63 | | * |
64 | | * Registered snapshots |
65 | | * -------------------- |
66 | | * |
67 | | * In addition to snapshots pushed to the active snapshot stack, a snapshot |
68 | | * can be registered with a resource owner. |
69 | | * |
70 | | * The FirstXactSnapshot, if any, is treated a bit specially: we increment its |
71 | | * regd_count and list it in RegisteredSnapshots, but this reference is not |
72 | | * tracked by a resource owner. We used to use the TopTransactionResourceOwner |
73 | | * to track this snapshot reference, but that introduces logical circularity |
74 | | * and thus makes it impossible to clean up in a sane fashion. It's better to |
75 | | * handle this reference as an internally-tracked registration, so that this |
76 | | * module is entirely lower-level than ResourceOwners. |
77 | | * |
78 | | * Likewise, any snapshots that have been exported by pg_export_snapshot |
79 | | * have regd_count = 1 and are listed in RegisteredSnapshots, but are not |
80 | | * tracked by any resource owner. |
81 | | * |
82 | | * Likewise, the CatalogSnapshot is listed in RegisteredSnapshots when it |
83 | | * is valid, but is not tracked by any resource owner. |
84 | | * |
85 | | * The same is true for historic snapshots used during logical decoding, |
86 | | * their lifetime is managed separately (as they live longer than one xact.c |
87 | | * transaction). |
88 | | * |
89 | | * These arrangements let us reset MyProc->xmin when there are no snapshots |
90 | | * referenced by this transaction, and advance it when the one with oldest |
91 | | * Xmin is no longer referenced. For simplicity however, only registered |
92 | | * snapshots not active snapshots participate in tracking which one is oldest; |
93 | | * we don't try to change MyProc->xmin except when the active-snapshot |
94 | | * stack is empty. |
95 | | * |
96 | | * |
97 | | * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group |
98 | | * Portions Copyright (c) 1994, Regents of the University of California |
99 | | * |
100 | | * IDENTIFICATION |
101 | | * src/backend/utils/time/snapmgr.c |
102 | | * |
103 | | *------------------------------------------------------------------------- |
104 | | */ |
105 | | #include "postgres.h" |
106 | | |
107 | | #include <sys/stat.h> |
108 | | #include <unistd.h> |
109 | | |
110 | | #include "access/subtrans.h" |
111 | | #include "access/transam.h" |
112 | | #include "access/xact.h" |
113 | | #include "datatype/timestamp.h" |
114 | | #include "lib/pairingheap.h" |
115 | | #include "miscadmin.h" |
116 | | #include "port/pg_lfind.h" |
117 | | #include "storage/fd.h" |
118 | | #include "storage/predicate.h" |
119 | | #include "storage/proc.h" |
120 | | #include "storage/procarray.h" |
121 | | #include "utils/builtins.h" |
122 | | #include "utils/injection_point.h" |
123 | | #include "utils/memutils.h" |
124 | | #include "utils/resowner.h" |
125 | | #include "utils/snapmgr.h" |
126 | | #include "utils/syscache.h" |
127 | | |
128 | | |
129 | | /* |
130 | | * CurrentSnapshot points to the only snapshot taken in transaction-snapshot |
131 | | * mode, and to the latest one taken in a read-committed transaction. |
132 | | * SecondarySnapshot is a snapshot that's always up-to-date as of the current |
133 | | * instant, even in transaction-snapshot mode. It should only be used for |
134 | | * special-purpose code (say, RI checking.) CatalogSnapshot points to an |
135 | | * MVCC snapshot intended to be used for catalog scans; we must invalidate it |
136 | | * whenever a system catalog change occurs. |
137 | | * |
138 | | * These SnapshotData structs are static to simplify memory allocation |
139 | | * (see the hack in GetSnapshotData to avoid repeated malloc/free). |
140 | | */ |
141 | | static SnapshotData CurrentSnapshotData = {SNAPSHOT_MVCC}; |
142 | | static SnapshotData SecondarySnapshotData = {SNAPSHOT_MVCC}; |
143 | | static SnapshotData CatalogSnapshotData = {SNAPSHOT_MVCC}; |
144 | | SnapshotData SnapshotSelfData = {SNAPSHOT_SELF}; |
145 | | SnapshotData SnapshotAnyData = {SNAPSHOT_ANY}; |
146 | | SnapshotData SnapshotToastData = {SNAPSHOT_TOAST}; |
147 | | |
148 | | /* Pointers to valid snapshots */ |
149 | | static Snapshot CurrentSnapshot = NULL; |
150 | | static Snapshot SecondarySnapshot = NULL; |
151 | | static Snapshot CatalogSnapshot = NULL; |
152 | | static Snapshot HistoricSnapshot = NULL; |
153 | | |
154 | | /* |
155 | | * These are updated by GetSnapshotData. We initialize them this way |
156 | | * for the convenience of TransactionIdIsInProgress: even in bootstrap |
157 | | * mode, we don't want it to say that BootstrapTransactionId is in progress. |
158 | | */ |
159 | | TransactionId TransactionXmin = FirstNormalTransactionId; |
160 | | TransactionId RecentXmin = FirstNormalTransactionId; |
161 | | |
162 | | /* (table, ctid) => (cmin, cmax) mapping during timetravel */ |
163 | | static HTAB *tuplecid_data = NULL; |
164 | | |
165 | | /* |
166 | | * Elements of the active snapshot stack. |
167 | | * |
168 | | * Each element here accounts for exactly one active_count on SnapshotData. |
169 | | * |
170 | | * NB: the code assumes that elements in this list are in non-increasing |
171 | | * order of as_level; also, the list must be NULL-terminated. |
172 | | */ |
173 | | typedef struct ActiveSnapshotElt |
174 | | { |
175 | | Snapshot as_snap; |
176 | | int as_level; |
177 | | struct ActiveSnapshotElt *as_next; |
178 | | } ActiveSnapshotElt; |
179 | | |
180 | | /* Top of the stack of active snapshots */ |
181 | | static ActiveSnapshotElt *ActiveSnapshot = NULL; |
182 | | |
183 | | /* |
184 | | * Currently registered Snapshots. Ordered in a heap by xmin, so that we can |
185 | | * quickly find the one with lowest xmin, to advance our MyProc->xmin. |
186 | | */ |
187 | | static int xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, |
188 | | void *arg); |
189 | | |
190 | | static pairingheap RegisteredSnapshots = {&xmin_cmp, NULL, NULL}; |
191 | | |
192 | | /* first GetTransactionSnapshot call in a transaction? */ |
193 | | bool FirstSnapshotSet = false; |
194 | | |
195 | | /* |
196 | | * Remember the serializable transaction snapshot, if any. We cannot trust |
197 | | * FirstSnapshotSet in combination with IsolationUsesXactSnapshot(), because |
198 | | * GUC may be reset before us, changing the value of IsolationUsesXactSnapshot. |
199 | | */ |
200 | | static Snapshot FirstXactSnapshot = NULL; |
201 | | |
202 | | /* Define pathname of exported-snapshot files */ |
203 | 0 | #define SNAPSHOT_EXPORT_DIR "pg_snapshots" |
204 | | |
205 | | /* Structure holding info about exported snapshot. */ |
206 | | typedef struct ExportedSnapshot |
207 | | { |
208 | | char *snapfile; |
209 | | Snapshot snapshot; |
210 | | } ExportedSnapshot; |
211 | | |
212 | | /* Current xact's exported snapshots (a list of ExportedSnapshot structs) */ |
213 | | static List *exportedSnapshots = NIL; |
214 | | |
215 | | /* Prototypes for local functions */ |
216 | | static Snapshot CopySnapshot(Snapshot snapshot); |
217 | | static void UnregisterSnapshotNoOwner(Snapshot snapshot); |
218 | | static void FreeSnapshot(Snapshot snapshot); |
219 | | static void SnapshotResetXmin(void); |
220 | | |
221 | | /* ResourceOwner callbacks to track snapshot references */ |
222 | | static void ResOwnerReleaseSnapshot(Datum res); |
223 | | |
224 | | static const ResourceOwnerDesc snapshot_resowner_desc = |
225 | | { |
226 | | .name = "snapshot reference", |
227 | | .release_phase = RESOURCE_RELEASE_AFTER_LOCKS, |
228 | | .release_priority = RELEASE_PRIO_SNAPSHOT_REFS, |
229 | | .ReleaseResource = ResOwnerReleaseSnapshot, |
230 | | .DebugPrint = NULL /* the default message is fine */ |
231 | | }; |
232 | | |
233 | | /* Convenience wrappers over ResourceOwnerRemember/Forget */ |
234 | | static inline void |
235 | | ResourceOwnerRememberSnapshot(ResourceOwner owner, Snapshot snap) |
236 | 0 | { |
237 | 0 | ResourceOwnerRemember(owner, PointerGetDatum(snap), &snapshot_resowner_desc); |
238 | 0 | } |
239 | | static inline void |
240 | | ResourceOwnerForgetSnapshot(ResourceOwner owner, Snapshot snap) |
241 | 0 | { |
242 | 0 | ResourceOwnerForget(owner, PointerGetDatum(snap), &snapshot_resowner_desc); |
243 | 0 | } |
244 | | |
245 | | /* |
246 | | * Snapshot fields to be serialized. |
247 | | * |
248 | | * Only these fields need to be sent to the cooperating backend; the |
249 | | * remaining ones can (and must) be set by the receiver upon restore. |
250 | | */ |
251 | | typedef struct SerializedSnapshotData |
252 | | { |
253 | | TransactionId xmin; |
254 | | TransactionId xmax; |
255 | | uint32 xcnt; |
256 | | int32 subxcnt; |
257 | | bool suboverflowed; |
258 | | bool takenDuringRecovery; |
259 | | CommandId curcid; |
260 | | } SerializedSnapshotData; |
261 | | |
262 | | /* |
263 | | * GetTransactionSnapshot |
264 | | * Get the appropriate snapshot for a new query in a transaction. |
265 | | * |
266 | | * Note that the return value points at static storage that will be modified |
267 | | * by future calls and by CommandCounterIncrement(). Callers must call |
268 | | * RegisterSnapshot or PushActiveSnapshot on the returned snap before doing |
269 | | * any other non-trivial work that could invalidate it. |
270 | | */ |
271 | | Snapshot |
272 | | GetTransactionSnapshot(void) |
273 | 0 | { |
274 | | /* |
275 | | * Return historic snapshot if doing logical decoding. |
276 | | * |
277 | | * Historic snapshots are only usable for catalog access, not for |
278 | | * general-purpose queries. The caller is responsible for ensuring that |
279 | | * the snapshot is used correctly! (PostgreSQL code never calls this |
280 | | * during logical decoding, but extensions can do it.) |
281 | | */ |
282 | 0 | if (HistoricSnapshotActive()) |
283 | 0 | { |
284 | | /* |
285 | | * We'll never need a non-historic transaction snapshot in this |
286 | | * (sub-)transaction, so there's no need to be careful to set one up |
287 | | * for later calls to GetTransactionSnapshot(). |
288 | | */ |
289 | 0 | Assert(!FirstSnapshotSet); |
290 | 0 | return HistoricSnapshot; |
291 | 0 | } |
292 | | |
293 | | /* First call in transaction? */ |
294 | 0 | if (!FirstSnapshotSet) |
295 | 0 | { |
296 | | /* |
297 | | * Don't allow catalog snapshot to be older than xact snapshot. Must |
298 | | * do this first to allow the empty-heap Assert to succeed. |
299 | | */ |
300 | 0 | InvalidateCatalogSnapshot(); |
301 | |
|
302 | 0 | Assert(pairingheap_is_empty(&RegisteredSnapshots)); |
303 | 0 | Assert(FirstXactSnapshot == NULL); |
304 | |
|
305 | 0 | if (IsInParallelMode()) |
306 | 0 | elog(ERROR, |
307 | 0 | "cannot take query snapshot during a parallel operation"); |
308 | | |
309 | | /* |
310 | | * In transaction-snapshot mode, the first snapshot must live until |
311 | | * end of xact regardless of what the caller does with it, so we must |
312 | | * make a copy of it rather than returning CurrentSnapshotData |
313 | | * directly. Furthermore, if we're running in serializable mode, |
314 | | * predicate.c needs to wrap the snapshot fetch in its own processing. |
315 | | */ |
316 | 0 | if (IsolationUsesXactSnapshot()) |
317 | 0 | { |
318 | | /* First, create the snapshot in CurrentSnapshotData */ |
319 | 0 | if (IsolationIsSerializable()) |
320 | 0 | CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData); |
321 | 0 | else |
322 | 0 | CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); |
323 | | /* Make a saved copy */ |
324 | 0 | CurrentSnapshot = CopySnapshot(CurrentSnapshot); |
325 | 0 | FirstXactSnapshot = CurrentSnapshot; |
326 | | /* Mark it as "registered" in FirstXactSnapshot */ |
327 | 0 | FirstXactSnapshot->regd_count++; |
328 | 0 | pairingheap_add(&RegisteredSnapshots, &FirstXactSnapshot->ph_node); |
329 | 0 | } |
330 | 0 | else |
331 | 0 | CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); |
332 | |
|
333 | 0 | FirstSnapshotSet = true; |
334 | 0 | return CurrentSnapshot; |
335 | 0 | } |
336 | | |
337 | 0 | if (IsolationUsesXactSnapshot()) |
338 | 0 | return CurrentSnapshot; |
339 | | |
340 | | /* Don't allow catalog snapshot to be older than xact snapshot. */ |
341 | 0 | InvalidateCatalogSnapshot(); |
342 | |
|
343 | 0 | CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); |
344 | |
|
345 | 0 | return CurrentSnapshot; |
346 | 0 | } |
347 | | |
348 | | /* |
349 | | * GetLatestSnapshot |
350 | | * Get a snapshot that is up-to-date as of the current instant, |
351 | | * even if we are executing in transaction-snapshot mode. |
352 | | */ |
353 | | Snapshot |
354 | | GetLatestSnapshot(void) |
355 | 0 | { |
356 | | /* |
357 | | * We might be able to relax this, but nothing that could otherwise work |
358 | | * needs it. |
359 | | */ |
360 | 0 | if (IsInParallelMode()) |
361 | 0 | elog(ERROR, |
362 | 0 | "cannot update SecondarySnapshot during a parallel operation"); |
363 | | |
364 | | /* |
365 | | * So far there are no cases requiring support for GetLatestSnapshot() |
366 | | * during logical decoding, but it wouldn't be hard to add if required. |
367 | | */ |
368 | 0 | Assert(!HistoricSnapshotActive()); |
369 | | |
370 | | /* If first call in transaction, go ahead and set the xact snapshot */ |
371 | 0 | if (!FirstSnapshotSet) |
372 | 0 | return GetTransactionSnapshot(); |
373 | | |
374 | 0 | SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData); |
375 | |
|
376 | 0 | return SecondarySnapshot; |
377 | 0 | } |
378 | | |
379 | | /* |
380 | | * GetCatalogSnapshot |
381 | | * Get a snapshot that is sufficiently up-to-date for scan of the |
382 | | * system catalog with the specified OID. |
383 | | */ |
384 | | Snapshot |
385 | | GetCatalogSnapshot(Oid relid) |
386 | 0 | { |
387 | | /* |
388 | | * Return historic snapshot while we're doing logical decoding, so we can |
389 | | * see the appropriate state of the catalog. |
390 | | * |
391 | | * This is the primary reason for needing to reset the system caches after |
392 | | * finishing decoding. |
393 | | */ |
394 | 0 | if (HistoricSnapshotActive()) |
395 | 0 | return HistoricSnapshot; |
396 | | |
397 | 0 | return GetNonHistoricCatalogSnapshot(relid); |
398 | 0 | } |
399 | | |
400 | | /* |
401 | | * GetNonHistoricCatalogSnapshot |
402 | | * Get a snapshot that is sufficiently up-to-date for scan of the system |
403 | | * catalog with the specified OID, even while historic snapshots are set |
404 | | * up. |
405 | | */ |
406 | | Snapshot |
407 | | GetNonHistoricCatalogSnapshot(Oid relid) |
408 | 0 | { |
409 | | /* |
410 | | * If the caller is trying to scan a relation that has no syscache, no |
411 | | * catcache invalidations will be sent when it is updated. For a few key |
412 | | * relations, snapshot invalidations are sent instead. If we're trying to |
413 | | * scan a relation for which neither catcache nor snapshot invalidations |
414 | | * are sent, we must refresh the snapshot every time. |
415 | | */ |
416 | 0 | if (CatalogSnapshot && |
417 | 0 | !RelationInvalidatesSnapshotsOnly(relid) && |
418 | 0 | !RelationHasSysCache(relid)) |
419 | 0 | InvalidateCatalogSnapshot(); |
420 | |
|
421 | 0 | if (CatalogSnapshot == NULL) |
422 | 0 | { |
423 | | /* Get new snapshot. */ |
424 | 0 | CatalogSnapshot = GetSnapshotData(&CatalogSnapshotData); |
425 | | |
426 | | /* |
427 | | * Make sure the catalog snapshot will be accounted for in decisions |
428 | | * about advancing PGPROC->xmin. We could apply RegisterSnapshot, but |
429 | | * that would result in making a physical copy, which is overkill; and |
430 | | * it would also create a dependency on some resource owner, which we |
431 | | * do not want for reasons explained at the head of this file. Instead |
432 | | * just shove the CatalogSnapshot into the pairing heap manually. This |
433 | | * has to be reversed in InvalidateCatalogSnapshot, of course. |
434 | | * |
435 | | * NB: it had better be impossible for this to throw error, since the |
436 | | * CatalogSnapshot pointer is already valid. |
437 | | */ |
438 | 0 | pairingheap_add(&RegisteredSnapshots, &CatalogSnapshot->ph_node); |
439 | 0 | } |
440 | |
|
441 | 0 | return CatalogSnapshot; |
442 | 0 | } |
443 | | |
444 | | /* |
445 | | * InvalidateCatalogSnapshot |
446 | | * Mark the current catalog snapshot, if any, as invalid |
447 | | * |
448 | | * We could change this API to allow the caller to provide more fine-grained |
449 | | * invalidation details, so that a change to relation A wouldn't prevent us |
450 | | * from using our cached snapshot to scan relation B, but so far there's no |
451 | | * evidence that the CPU cycles we spent tracking such fine details would be |
452 | | * well-spent. |
453 | | */ |
454 | | void |
455 | | InvalidateCatalogSnapshot(void) |
456 | 0 | { |
457 | 0 | if (CatalogSnapshot) |
458 | 0 | { |
459 | 0 | pairingheap_remove(&RegisteredSnapshots, &CatalogSnapshot->ph_node); |
460 | 0 | CatalogSnapshot = NULL; |
461 | 0 | SnapshotResetXmin(); |
462 | 0 | INJECTION_POINT("invalidate-catalog-snapshot-end", NULL); |
463 | 0 | } |
464 | 0 | } |
465 | | |
466 | | /* |
467 | | * InvalidateCatalogSnapshotConditionally |
468 | | * Drop catalog snapshot if it's the only one we have |
469 | | * |
470 | | * This is called when we are about to wait for client input, so we don't |
471 | | * want to continue holding the catalog snapshot if it might mean that the |
472 | | * global xmin horizon can't advance. However, if there are other snapshots |
473 | | * still active or registered, the catalog snapshot isn't likely to be the |
474 | | * oldest one, so we might as well keep it. |
475 | | */ |
476 | | void |
477 | | InvalidateCatalogSnapshotConditionally(void) |
478 | 0 | { |
479 | 0 | if (CatalogSnapshot && |
480 | 0 | ActiveSnapshot == NULL && |
481 | 0 | pairingheap_is_singular(&RegisteredSnapshots)) |
482 | 0 | InvalidateCatalogSnapshot(); |
483 | 0 | } |
484 | | |
485 | | /* |
486 | | * SnapshotSetCommandId |
487 | | * Propagate CommandCounterIncrement into the static snapshots, if set |
488 | | */ |
489 | | void |
490 | | SnapshotSetCommandId(CommandId curcid) |
491 | 0 | { |
492 | 0 | if (!FirstSnapshotSet) |
493 | 0 | return; |
494 | | |
495 | 0 | if (CurrentSnapshot) |
496 | 0 | CurrentSnapshot->curcid = curcid; |
497 | 0 | if (SecondarySnapshot) |
498 | 0 | SecondarySnapshot->curcid = curcid; |
499 | | /* Should we do the same with CatalogSnapshot? */ |
500 | 0 | } |
501 | | |
502 | | /* |
503 | | * SetTransactionSnapshot |
504 | | * Set the transaction's snapshot from an imported MVCC snapshot. |
505 | | * |
506 | | * Note that this is very closely tied to GetTransactionSnapshot --- it |
507 | | * must take care of all the same considerations as the first-snapshot case |
508 | | * in GetTransactionSnapshot. |
509 | | */ |
510 | | static void |
511 | | SetTransactionSnapshot(Snapshot sourcesnap, VirtualTransactionId *sourcevxid, |
512 | | int sourcepid, PGPROC *sourceproc) |
513 | 0 | { |
514 | | /* Caller should have checked this already */ |
515 | 0 | Assert(!FirstSnapshotSet); |
516 | | |
517 | | /* Better do this to ensure following Assert succeeds. */ |
518 | 0 | InvalidateCatalogSnapshot(); |
519 | |
|
520 | 0 | Assert(pairingheap_is_empty(&RegisteredSnapshots)); |
521 | 0 | Assert(FirstXactSnapshot == NULL); |
522 | 0 | Assert(!HistoricSnapshotActive()); |
523 | | |
524 | | /* |
525 | | * Even though we are not going to use the snapshot it computes, we must |
526 | | * call GetSnapshotData, for two reasons: (1) to be sure that |
527 | | * CurrentSnapshotData's XID arrays have been allocated, and (2) to update |
528 | | * the state for GlobalVis*. |
529 | | */ |
530 | 0 | CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); |
531 | | |
532 | | /* |
533 | | * Now copy appropriate fields from the source snapshot. |
534 | | */ |
535 | 0 | CurrentSnapshot->xmin = sourcesnap->xmin; |
536 | 0 | CurrentSnapshot->xmax = sourcesnap->xmax; |
537 | 0 | CurrentSnapshot->xcnt = sourcesnap->xcnt; |
538 | 0 | Assert(sourcesnap->xcnt <= GetMaxSnapshotXidCount()); |
539 | 0 | if (sourcesnap->xcnt > 0) |
540 | 0 | memcpy(CurrentSnapshot->xip, sourcesnap->xip, |
541 | 0 | sourcesnap->xcnt * sizeof(TransactionId)); |
542 | 0 | CurrentSnapshot->subxcnt = sourcesnap->subxcnt; |
543 | 0 | Assert(sourcesnap->subxcnt <= GetMaxSnapshotSubxidCount()); |
544 | 0 | if (sourcesnap->subxcnt > 0) |
545 | 0 | memcpy(CurrentSnapshot->subxip, sourcesnap->subxip, |
546 | 0 | sourcesnap->subxcnt * sizeof(TransactionId)); |
547 | 0 | CurrentSnapshot->suboverflowed = sourcesnap->suboverflowed; |
548 | 0 | CurrentSnapshot->takenDuringRecovery = sourcesnap->takenDuringRecovery; |
549 | | /* NB: curcid should NOT be copied, it's a local matter */ |
550 | |
|
551 | 0 | CurrentSnapshot->snapXactCompletionCount = 0; |
552 | | |
553 | | /* |
554 | | * Now we have to fix what GetSnapshotData did with MyProc->xmin and |
555 | | * TransactionXmin. There is a race condition: to make sure we are not |
556 | | * causing the global xmin to go backwards, we have to test that the |
557 | | * source transaction is still running, and that has to be done |
558 | | * atomically. So let procarray.c do it. |
559 | | * |
560 | | * Note: in serializable mode, predicate.c will do this a second time. It |
561 | | * doesn't seem worth contorting the logic here to avoid two calls, |
562 | | * especially since it's not clear that predicate.c *must* do this. |
563 | | */ |
564 | 0 | if (sourceproc != NULL) |
565 | 0 | { |
566 | 0 | if (!ProcArrayInstallRestoredXmin(CurrentSnapshot->xmin, sourceproc)) |
567 | 0 | ereport(ERROR, |
568 | 0 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
569 | 0 | errmsg("could not import the requested snapshot"), |
570 | 0 | errdetail("The source transaction is not running anymore."))); |
571 | 0 | } |
572 | 0 | else if (!ProcArrayInstallImportedXmin(CurrentSnapshot->xmin, sourcevxid)) |
573 | 0 | ereport(ERROR, |
574 | 0 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
575 | 0 | errmsg("could not import the requested snapshot"), |
576 | 0 | errdetail("The source process with PID %d is not running anymore.", |
577 | 0 | sourcepid))); |
578 | | |
579 | | /* |
580 | | * In transaction-snapshot mode, the first snapshot must live until end of |
581 | | * xact, so we must make a copy of it. Furthermore, if we're running in |
582 | | * serializable mode, predicate.c needs to do its own processing. |
583 | | */ |
584 | 0 | if (IsolationUsesXactSnapshot()) |
585 | 0 | { |
586 | 0 | if (IsolationIsSerializable()) |
587 | 0 | SetSerializableTransactionSnapshot(CurrentSnapshot, sourcevxid, |
588 | 0 | sourcepid); |
589 | | /* Make a saved copy */ |
590 | 0 | CurrentSnapshot = CopySnapshot(CurrentSnapshot); |
591 | 0 | FirstXactSnapshot = CurrentSnapshot; |
592 | | /* Mark it as "registered" in FirstXactSnapshot */ |
593 | 0 | FirstXactSnapshot->regd_count++; |
594 | 0 | pairingheap_add(&RegisteredSnapshots, &FirstXactSnapshot->ph_node); |
595 | 0 | } |
596 | |
|
597 | 0 | FirstSnapshotSet = true; |
598 | 0 | } |
599 | | |
600 | | /* |
601 | | * CopySnapshot |
602 | | * Copy the given snapshot. |
603 | | * |
604 | | * The copy is palloc'd in TopTransactionContext and has initial refcounts set |
605 | | * to 0. The returned snapshot has the copied flag set. |
606 | | */ |
607 | | static Snapshot |
608 | | CopySnapshot(Snapshot snapshot) |
609 | 0 | { |
610 | 0 | Snapshot newsnap; |
611 | 0 | Size subxipoff; |
612 | 0 | Size size; |
613 | |
|
614 | 0 | Assert(snapshot != InvalidSnapshot); |
615 | | |
616 | | /* We allocate any XID arrays needed in the same palloc block. */ |
617 | 0 | size = subxipoff = sizeof(SnapshotData) + |
618 | 0 | snapshot->xcnt * sizeof(TransactionId); |
619 | 0 | if (snapshot->subxcnt > 0) |
620 | 0 | size += snapshot->subxcnt * sizeof(TransactionId); |
621 | |
|
622 | 0 | newsnap = (Snapshot) MemoryContextAlloc(TopTransactionContext, size); |
623 | 0 | memcpy(newsnap, snapshot, sizeof(SnapshotData)); |
624 | |
|
625 | 0 | newsnap->regd_count = 0; |
626 | 0 | newsnap->active_count = 0; |
627 | 0 | newsnap->copied = true; |
628 | 0 | newsnap->snapXactCompletionCount = 0; |
629 | | |
630 | | /* setup XID array */ |
631 | 0 | if (snapshot->xcnt > 0) |
632 | 0 | { |
633 | 0 | newsnap->xip = (TransactionId *) (newsnap + 1); |
634 | 0 | memcpy(newsnap->xip, snapshot->xip, |
635 | 0 | snapshot->xcnt * sizeof(TransactionId)); |
636 | 0 | } |
637 | 0 | else |
638 | 0 | newsnap->xip = NULL; |
639 | | |
640 | | /* |
641 | | * Setup subXID array. Don't bother to copy it if it had overflowed, |
642 | | * though, because it's not used anywhere in that case. Except if it's a |
643 | | * snapshot taken during recovery; all the top-level XIDs are in subxip as |
644 | | * well in that case, so we mustn't lose them. |
645 | | */ |
646 | 0 | if (snapshot->subxcnt > 0 && |
647 | 0 | (!snapshot->suboverflowed || snapshot->takenDuringRecovery)) |
648 | 0 | { |
649 | 0 | newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff); |
650 | 0 | memcpy(newsnap->subxip, snapshot->subxip, |
651 | 0 | snapshot->subxcnt * sizeof(TransactionId)); |
652 | 0 | } |
653 | 0 | else |
654 | 0 | newsnap->subxip = NULL; |
655 | |
|
656 | 0 | return newsnap; |
657 | 0 | } |
658 | | |
659 | | /* |
660 | | * FreeSnapshot |
661 | | * Free the memory associated with a snapshot. |
662 | | */ |
663 | | static void |
664 | | FreeSnapshot(Snapshot snapshot) |
665 | 0 | { |
666 | 0 | Assert(snapshot->regd_count == 0); |
667 | 0 | Assert(snapshot->active_count == 0); |
668 | 0 | Assert(snapshot->copied); |
669 | |
|
670 | 0 | pfree(snapshot); |
671 | 0 | } |
672 | | |
673 | | /* |
674 | | * PushActiveSnapshot |
675 | | * Set the given snapshot as the current active snapshot |
676 | | * |
677 | | * If the passed snapshot is a statically-allocated one, or it is possibly |
678 | | * subject to a future command counter update, create a new long-lived copy |
679 | | * with active refcount=1. Otherwise, only increment the refcount. |
680 | | */ |
681 | | void |
682 | | PushActiveSnapshot(Snapshot snapshot) |
683 | 0 | { |
684 | 0 | PushActiveSnapshotWithLevel(snapshot, GetCurrentTransactionNestLevel()); |
685 | 0 | } |
686 | | |
687 | | /* |
688 | | * PushActiveSnapshotWithLevel |
689 | | * Set the given snapshot as the current active snapshot |
690 | | * |
691 | | * Same as PushActiveSnapshot except that caller can specify the |
692 | | * transaction nesting level that "owns" the snapshot. This level |
693 | | * must not be deeper than the current top of the snapshot stack. |
694 | | */ |
695 | | void |
696 | | PushActiveSnapshotWithLevel(Snapshot snapshot, int snap_level) |
697 | 0 | { |
698 | 0 | ActiveSnapshotElt *newactive; |
699 | |
|
700 | 0 | Assert(snapshot != InvalidSnapshot); |
701 | 0 | Assert(ActiveSnapshot == NULL || snap_level >= ActiveSnapshot->as_level); |
702 | |
|
703 | 0 | newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt)); |
704 | | |
705 | | /* |
706 | | * Checking SecondarySnapshot is probably useless here, but it seems |
707 | | * better to be sure. |
708 | | */ |
709 | 0 | if (snapshot == CurrentSnapshot || snapshot == SecondarySnapshot || |
710 | 0 | !snapshot->copied) |
711 | 0 | newactive->as_snap = CopySnapshot(snapshot); |
712 | 0 | else |
713 | 0 | newactive->as_snap = snapshot; |
714 | |
|
715 | 0 | newactive->as_next = ActiveSnapshot; |
716 | 0 | newactive->as_level = snap_level; |
717 | |
|
718 | 0 | newactive->as_snap->active_count++; |
719 | |
|
720 | 0 | ActiveSnapshot = newactive; |
721 | 0 | } |
722 | | |
723 | | /* |
724 | | * PushCopiedSnapshot |
725 | | * As above, except forcibly copy the presented snapshot. |
726 | | * |
727 | | * This should be used when the ActiveSnapshot has to be modifiable, for |
728 | | * example if the caller intends to call UpdateActiveSnapshotCommandId. |
729 | | * The new snapshot will be released when popped from the stack. |
730 | | */ |
731 | | void |
732 | | PushCopiedSnapshot(Snapshot snapshot) |
733 | 0 | { |
734 | 0 | PushActiveSnapshot(CopySnapshot(snapshot)); |
735 | 0 | } |
736 | | |
737 | | /* |
738 | | * UpdateActiveSnapshotCommandId |
739 | | * |
740 | | * Update the current CID of the active snapshot. This can only be applied |
741 | | * to a snapshot that is not referenced elsewhere. |
742 | | */ |
743 | | void |
744 | | UpdateActiveSnapshotCommandId(void) |
745 | 0 | { |
746 | 0 | CommandId save_curcid, |
747 | 0 | curcid; |
748 | |
|
749 | 0 | Assert(ActiveSnapshot != NULL); |
750 | 0 | Assert(ActiveSnapshot->as_snap->active_count == 1); |
751 | 0 | Assert(ActiveSnapshot->as_snap->regd_count == 0); |
752 | | |
753 | | /* |
754 | | * Don't allow modification of the active snapshot during parallel |
755 | | * operation. We share the snapshot to worker backends at the beginning |
756 | | * of parallel operation, so any change to the snapshot can lead to |
757 | | * inconsistencies. We have other defenses against |
758 | | * CommandCounterIncrement, but there are a few places that call this |
759 | | * directly, so we put an additional guard here. |
760 | | */ |
761 | 0 | save_curcid = ActiveSnapshot->as_snap->curcid; |
762 | 0 | curcid = GetCurrentCommandId(false); |
763 | 0 | if (IsInParallelMode() && save_curcid != curcid) |
764 | 0 | elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation"); |
765 | 0 | ActiveSnapshot->as_snap->curcid = curcid; |
766 | 0 | } |
767 | | |
768 | | /* |
769 | | * PopActiveSnapshot |
770 | | * |
771 | | * Remove the topmost snapshot from the active snapshot stack, decrementing the |
772 | | * reference count, and free it if this was the last reference. |
773 | | */ |
774 | | void |
775 | | PopActiveSnapshot(void) |
776 | 0 | { |
777 | 0 | ActiveSnapshotElt *newstack; |
778 | |
|
779 | 0 | newstack = ActiveSnapshot->as_next; |
780 | |
|
781 | 0 | Assert(ActiveSnapshot->as_snap->active_count > 0); |
782 | |
|
783 | 0 | ActiveSnapshot->as_snap->active_count--; |
784 | |
|
785 | 0 | if (ActiveSnapshot->as_snap->active_count == 0 && |
786 | 0 | ActiveSnapshot->as_snap->regd_count == 0) |
787 | 0 | FreeSnapshot(ActiveSnapshot->as_snap); |
788 | |
|
789 | 0 | pfree(ActiveSnapshot); |
790 | 0 | ActiveSnapshot = newstack; |
791 | |
|
792 | 0 | SnapshotResetXmin(); |
793 | 0 | } |
794 | | |
795 | | /* |
796 | | * GetActiveSnapshot |
797 | | * Return the topmost snapshot in the Active stack. |
798 | | */ |
799 | | Snapshot |
800 | | GetActiveSnapshot(void) |
801 | 0 | { |
802 | 0 | Assert(ActiveSnapshot != NULL); |
803 | |
|
804 | 0 | return ActiveSnapshot->as_snap; |
805 | 0 | } |
806 | | |
807 | | /* |
808 | | * ActiveSnapshotSet |
809 | | * Return whether there is at least one snapshot in the Active stack |
810 | | */ |
811 | | bool |
812 | | ActiveSnapshotSet(void) |
813 | 0 | { |
814 | 0 | return ActiveSnapshot != NULL; |
815 | 0 | } |
816 | | |
817 | | /* |
818 | | * RegisterSnapshot |
819 | | * Register a snapshot as being in use by the current resource owner |
820 | | * |
821 | | * If InvalidSnapshot is passed, it is not registered. |
822 | | */ |
823 | | Snapshot |
824 | | RegisterSnapshot(Snapshot snapshot) |
825 | 0 | { |
826 | 0 | if (snapshot == InvalidSnapshot) |
827 | 0 | return InvalidSnapshot; |
828 | | |
829 | 0 | return RegisterSnapshotOnOwner(snapshot, CurrentResourceOwner); |
830 | 0 | } |
831 | | |
832 | | /* |
833 | | * RegisterSnapshotOnOwner |
834 | | * As above, but use the specified resource owner |
835 | | */ |
836 | | Snapshot |
837 | | RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner) |
838 | 0 | { |
839 | 0 | Snapshot snap; |
840 | |
|
841 | 0 | if (snapshot == InvalidSnapshot) |
842 | 0 | return InvalidSnapshot; |
843 | | |
844 | | /* Static snapshot? Create a persistent copy */ |
845 | 0 | snap = snapshot->copied ? snapshot : CopySnapshot(snapshot); |
846 | | |
847 | | /* and tell resowner.c about it */ |
848 | 0 | ResourceOwnerEnlarge(owner); |
849 | 0 | snap->regd_count++; |
850 | 0 | ResourceOwnerRememberSnapshot(owner, snap); |
851 | |
|
852 | 0 | if (snap->regd_count == 1) |
853 | 0 | pairingheap_add(&RegisteredSnapshots, &snap->ph_node); |
854 | |
|
855 | 0 | return snap; |
856 | 0 | } |
857 | | |
858 | | /* |
859 | | * UnregisterSnapshot |
860 | | * |
861 | | * Decrement the reference count of a snapshot, remove the corresponding |
862 | | * reference from CurrentResourceOwner, and free the snapshot if no more |
863 | | * references remain. |
864 | | */ |
865 | | void |
866 | | UnregisterSnapshot(Snapshot snapshot) |
867 | 0 | { |
868 | 0 | if (snapshot == NULL) |
869 | 0 | return; |
870 | | |
871 | 0 | UnregisterSnapshotFromOwner(snapshot, CurrentResourceOwner); |
872 | 0 | } |
873 | | |
874 | | /* |
875 | | * UnregisterSnapshotFromOwner |
876 | | * As above, but use the specified resource owner |
877 | | */ |
878 | | void |
879 | | UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner) |
880 | 0 | { |
881 | 0 | if (snapshot == NULL) |
882 | 0 | return; |
883 | | |
884 | 0 | ResourceOwnerForgetSnapshot(owner, snapshot); |
885 | 0 | UnregisterSnapshotNoOwner(snapshot); |
886 | 0 | } |
887 | | |
888 | | static void |
889 | | UnregisterSnapshotNoOwner(Snapshot snapshot) |
890 | 0 | { |
891 | 0 | Assert(snapshot->regd_count > 0); |
892 | 0 | Assert(!pairingheap_is_empty(&RegisteredSnapshots)); |
893 | |
|
894 | 0 | snapshot->regd_count--; |
895 | 0 | if (snapshot->regd_count == 0) |
896 | 0 | pairingheap_remove(&RegisteredSnapshots, &snapshot->ph_node); |
897 | |
|
898 | 0 | if (snapshot->regd_count == 0 && snapshot->active_count == 0) |
899 | 0 | { |
900 | 0 | FreeSnapshot(snapshot); |
901 | 0 | SnapshotResetXmin(); |
902 | 0 | } |
903 | 0 | } |
904 | | |
905 | | /* |
906 | | * Comparison function for RegisteredSnapshots heap. Snapshots are ordered |
907 | | * by xmin, so that the snapshot with smallest xmin is at the top. |
908 | | */ |
909 | | static int |
910 | | xmin_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg) |
911 | 0 | { |
912 | 0 | const SnapshotData *asnap = pairingheap_const_container(SnapshotData, ph_node, a); |
913 | 0 | const SnapshotData *bsnap = pairingheap_const_container(SnapshotData, ph_node, b); |
914 | |
|
915 | 0 | if (TransactionIdPrecedes(asnap->xmin, bsnap->xmin)) |
916 | 0 | return 1; |
917 | 0 | else if (TransactionIdFollows(asnap->xmin, bsnap->xmin)) |
918 | 0 | return -1; |
919 | 0 | else |
920 | 0 | return 0; |
921 | 0 | } |
922 | | |
923 | | /* |
924 | | * SnapshotResetXmin |
925 | | * |
926 | | * If there are no more snapshots, we can reset our PGPROC->xmin to |
927 | | * InvalidTransactionId. Note we can do this without locking because we assume |
928 | | * that storing an Xid is atomic. |
929 | | * |
930 | | * Even if there are some remaining snapshots, we may be able to advance our |
931 | | * PGPROC->xmin to some degree. This typically happens when a portal is |
932 | | * dropped. For efficiency, we only consider recomputing PGPROC->xmin when |
933 | | * the active snapshot stack is empty; this allows us not to need to track |
934 | | * which active snapshot is oldest. |
935 | | */ |
936 | | static void |
937 | | SnapshotResetXmin(void) |
938 | 0 | { |
939 | 0 | Snapshot minSnapshot; |
940 | |
|
941 | 0 | if (ActiveSnapshot != NULL) |
942 | 0 | return; |
943 | | |
944 | 0 | if (pairingheap_is_empty(&RegisteredSnapshots)) |
945 | 0 | { |
946 | 0 | MyProc->xmin = TransactionXmin = InvalidTransactionId; |
947 | 0 | return; |
948 | 0 | } |
949 | | |
950 | 0 | minSnapshot = pairingheap_container(SnapshotData, ph_node, |
951 | 0 | pairingheap_first(&RegisteredSnapshots)); |
952 | |
|
953 | 0 | if (TransactionIdPrecedes(MyProc->xmin, minSnapshot->xmin)) |
954 | 0 | MyProc->xmin = TransactionXmin = minSnapshot->xmin; |
955 | 0 | } |
956 | | |
957 | | /* |
958 | | * AtSubCommit_Snapshot |
959 | | */ |
960 | | void |
961 | | AtSubCommit_Snapshot(int level) |
962 | 0 | { |
963 | 0 | ActiveSnapshotElt *active; |
964 | | |
965 | | /* |
966 | | * Relabel the active snapshots set in this subtransaction as though they |
967 | | * are owned by the parent subxact. |
968 | | */ |
969 | 0 | for (active = ActiveSnapshot; active != NULL; active = active->as_next) |
970 | 0 | { |
971 | 0 | if (active->as_level < level) |
972 | 0 | break; |
973 | 0 | active->as_level = level - 1; |
974 | 0 | } |
975 | 0 | } |
976 | | |
977 | | /* |
978 | | * AtSubAbort_Snapshot |
979 | | * Clean up snapshots after a subtransaction abort |
980 | | */ |
981 | | void |
982 | | AtSubAbort_Snapshot(int level) |
983 | 0 | { |
984 | | /* Forget the active snapshots set by this subtransaction */ |
985 | 0 | while (ActiveSnapshot && ActiveSnapshot->as_level >= level) |
986 | 0 | { |
987 | 0 | ActiveSnapshotElt *next; |
988 | |
|
989 | 0 | next = ActiveSnapshot->as_next; |
990 | | |
991 | | /* |
992 | | * Decrement the snapshot's active count. If it's still registered or |
993 | | * marked as active by an outer subtransaction, we can't free it yet. |
994 | | */ |
995 | 0 | Assert(ActiveSnapshot->as_snap->active_count >= 1); |
996 | 0 | ActiveSnapshot->as_snap->active_count -= 1; |
997 | |
|
998 | 0 | if (ActiveSnapshot->as_snap->active_count == 0 && |
999 | 0 | ActiveSnapshot->as_snap->regd_count == 0) |
1000 | 0 | FreeSnapshot(ActiveSnapshot->as_snap); |
1001 | | |
1002 | | /* and free the stack element */ |
1003 | 0 | pfree(ActiveSnapshot); |
1004 | |
|
1005 | 0 | ActiveSnapshot = next; |
1006 | 0 | } |
1007 | |
|
1008 | 0 | SnapshotResetXmin(); |
1009 | 0 | } |
1010 | | |
1011 | | /* |
1012 | | * AtEOXact_Snapshot |
1013 | | * Snapshot manager's cleanup function for end of transaction |
1014 | | */ |
1015 | | void |
1016 | | AtEOXact_Snapshot(bool isCommit, bool resetXmin) |
1017 | 0 | { |
1018 | | /* |
1019 | | * In transaction-snapshot mode we must release our privately-managed |
1020 | | * reference to the transaction snapshot. We must remove it from |
1021 | | * RegisteredSnapshots to keep the check below happy. But we don't bother |
1022 | | * to do FreeSnapshot, for two reasons: the memory will go away with |
1023 | | * TopTransactionContext anyway, and if someone has left the snapshot |
1024 | | * stacked as active, we don't want the code below to be chasing through a |
1025 | | * dangling pointer. |
1026 | | */ |
1027 | 0 | if (FirstXactSnapshot != NULL) |
1028 | 0 | { |
1029 | 0 | Assert(FirstXactSnapshot->regd_count > 0); |
1030 | 0 | Assert(!pairingheap_is_empty(&RegisteredSnapshots)); |
1031 | 0 | pairingheap_remove(&RegisteredSnapshots, &FirstXactSnapshot->ph_node); |
1032 | 0 | } |
1033 | 0 | FirstXactSnapshot = NULL; |
1034 | | |
1035 | | /* |
1036 | | * If we exported any snapshots, clean them up. |
1037 | | */ |
1038 | 0 | if (exportedSnapshots != NIL) |
1039 | 0 | { |
1040 | 0 | ListCell *lc; |
1041 | | |
1042 | | /* |
1043 | | * Get rid of the files. Unlink failure is only a WARNING because (1) |
1044 | | * it's too late to abort the transaction, and (2) leaving a leaked |
1045 | | * file around has little real consequence anyway. |
1046 | | * |
1047 | | * We also need to remove the snapshots from RegisteredSnapshots to |
1048 | | * prevent a warning below. |
1049 | | * |
1050 | | * As with the FirstXactSnapshot, we don't need to free resources of |
1051 | | * the snapshot itself as it will go away with the memory context. |
1052 | | */ |
1053 | 0 | foreach(lc, exportedSnapshots) |
1054 | 0 | { |
1055 | 0 | ExportedSnapshot *esnap = (ExportedSnapshot *) lfirst(lc); |
1056 | |
|
1057 | 0 | if (unlink(esnap->snapfile)) |
1058 | 0 | elog(WARNING, "could not unlink file \"%s\": %m", |
1059 | 0 | esnap->snapfile); |
1060 | | |
1061 | 0 | pairingheap_remove(&RegisteredSnapshots, |
1062 | 0 | &esnap->snapshot->ph_node); |
1063 | 0 | } |
1064 | | |
1065 | 0 | exportedSnapshots = NIL; |
1066 | 0 | } |
1067 | | |
1068 | | /* Drop catalog snapshot if any */ |
1069 | 0 | InvalidateCatalogSnapshot(); |
1070 | | |
1071 | | /* On commit, complain about leftover snapshots */ |
1072 | 0 | if (isCommit) |
1073 | 0 | { |
1074 | 0 | ActiveSnapshotElt *active; |
1075 | |
|
1076 | 0 | if (!pairingheap_is_empty(&RegisteredSnapshots)) |
1077 | 0 | elog(WARNING, "registered snapshots seem to remain after cleanup"); |
1078 | | |
1079 | | /* complain about unpopped active snapshots */ |
1080 | 0 | for (active = ActiveSnapshot; active != NULL; active = active->as_next) |
1081 | 0 | elog(WARNING, "snapshot %p still active", active); |
1082 | 0 | } |
1083 | | |
1084 | | /* |
1085 | | * And reset our state. We don't need to free the memory explicitly -- |
1086 | | * it'll go away with TopTransactionContext. |
1087 | | */ |
1088 | 0 | ActiveSnapshot = NULL; |
1089 | 0 | pairingheap_reset(&RegisteredSnapshots); |
1090 | |
|
1091 | 0 | CurrentSnapshot = NULL; |
1092 | 0 | SecondarySnapshot = NULL; |
1093 | |
|
1094 | 0 | FirstSnapshotSet = false; |
1095 | | |
1096 | | /* |
1097 | | * During normal commit processing, we call ProcArrayEndTransaction() to |
1098 | | * reset the MyProc->xmin. That call happens prior to the call to |
1099 | | * AtEOXact_Snapshot(), so we need not touch xmin here at all. |
1100 | | */ |
1101 | 0 | if (resetXmin) |
1102 | 0 | SnapshotResetXmin(); |
1103 | |
|
1104 | 0 | Assert(resetXmin || MyProc->xmin == 0); |
1105 | 0 | } |
1106 | | |
1107 | | |
1108 | | /* |
1109 | | * ExportSnapshot |
1110 | | * Export the snapshot to a file so that other backends can import it. |
1111 | | * Returns the token (the file name) that can be used to import this |
1112 | | * snapshot. |
1113 | | */ |
1114 | | char * |
1115 | | ExportSnapshot(Snapshot snapshot) |
1116 | 0 | { |
1117 | 0 | TransactionId topXid; |
1118 | 0 | TransactionId *children; |
1119 | 0 | ExportedSnapshot *esnap; |
1120 | 0 | int nchildren; |
1121 | 0 | int addTopXid; |
1122 | 0 | StringInfoData buf; |
1123 | 0 | FILE *f; |
1124 | 0 | MemoryContext oldcxt; |
1125 | 0 | char path[MAXPGPATH]; |
1126 | 0 | char pathtmp[MAXPGPATH]; |
1127 | | |
1128 | | /* |
1129 | | * It's tempting to call RequireTransactionBlock here, since it's not very |
1130 | | * useful to export a snapshot that will disappear immediately afterwards. |
1131 | | * However, we haven't got enough information to do that, since we don't |
1132 | | * know if we're at top level or not. For example, we could be inside a |
1133 | | * plpgsql function that is going to fire off other transactions via |
1134 | | * dblink. Rather than disallow perfectly legitimate usages, don't make a |
1135 | | * check. |
1136 | | * |
1137 | | * Also note that we don't make any restriction on the transaction's |
1138 | | * isolation level; however, importers must check the level if they are |
1139 | | * serializable. |
1140 | | */ |
1141 | | |
1142 | | /* |
1143 | | * Get our transaction ID if there is one, to include in the snapshot. |
1144 | | */ |
1145 | 0 | topXid = GetTopTransactionIdIfAny(); |
1146 | | |
1147 | | /* |
1148 | | * We cannot export a snapshot from a subtransaction because there's no |
1149 | | * easy way for importers to verify that the same subtransaction is still |
1150 | | * running. |
1151 | | */ |
1152 | 0 | if (IsSubTransaction()) |
1153 | 0 | ereport(ERROR, |
1154 | 0 | (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), |
1155 | 0 | errmsg("cannot export a snapshot from a subtransaction"))); |
1156 | | |
1157 | | /* |
1158 | | * We do however allow previous committed subtransactions to exist. |
1159 | | * Importers of the snapshot must see them as still running, so get their |
1160 | | * XIDs to add them to the snapshot. |
1161 | | */ |
1162 | 0 | nchildren = xactGetCommittedChildren(&children); |
1163 | | |
1164 | | /* |
1165 | | * Generate file path for the snapshot. We start numbering of snapshots |
1166 | | * inside the transaction from 1. |
1167 | | */ |
1168 | 0 | snprintf(path, sizeof(path), SNAPSHOT_EXPORT_DIR "/%08X-%08X-%d", |
1169 | 0 | MyProc->vxid.procNumber, MyProc->vxid.lxid, |
1170 | 0 | list_length(exportedSnapshots) + 1); |
1171 | | |
1172 | | /* |
1173 | | * Copy the snapshot into TopTransactionContext, add it to the |
1174 | | * exportedSnapshots list, and mark it pseudo-registered. We do this to |
1175 | | * ensure that the snapshot's xmin is honored for the rest of the |
1176 | | * transaction. |
1177 | | */ |
1178 | 0 | snapshot = CopySnapshot(snapshot); |
1179 | |
|
1180 | 0 | oldcxt = MemoryContextSwitchTo(TopTransactionContext); |
1181 | 0 | esnap = palloc_object(ExportedSnapshot); |
1182 | 0 | esnap->snapfile = pstrdup(path); |
1183 | 0 | esnap->snapshot = snapshot; |
1184 | 0 | exportedSnapshots = lappend(exportedSnapshots, esnap); |
1185 | 0 | MemoryContextSwitchTo(oldcxt); |
1186 | |
|
1187 | 0 | snapshot->regd_count++; |
1188 | 0 | pairingheap_add(&RegisteredSnapshots, &snapshot->ph_node); |
1189 | | |
1190 | | /* |
1191 | | * Fill buf with a text serialization of the snapshot, plus identification |
1192 | | * data about this transaction. The format expected by ImportSnapshot is |
1193 | | * pretty rigid: each line must be fieldname:value. |
1194 | | */ |
1195 | 0 | initStringInfo(&buf); |
1196 | |
|
1197 | 0 | appendStringInfo(&buf, "vxid:%d/%u\n", MyProc->vxid.procNumber, MyProc->vxid.lxid); |
1198 | 0 | appendStringInfo(&buf, "pid:%d\n", MyProcPid); |
1199 | 0 | appendStringInfo(&buf, "dbid:%u\n", MyDatabaseId); |
1200 | 0 | appendStringInfo(&buf, "iso:%d\n", XactIsoLevel); |
1201 | 0 | appendStringInfo(&buf, "ro:%d\n", XactReadOnly); |
1202 | |
|
1203 | 0 | appendStringInfo(&buf, "xmin:%u\n", snapshot->xmin); |
1204 | 0 | appendStringInfo(&buf, "xmax:%u\n", snapshot->xmax); |
1205 | | |
1206 | | /* |
1207 | | * We must include our own top transaction ID in the top-xid data, since |
1208 | | * by definition we will still be running when the importing transaction |
1209 | | * adopts the snapshot, but GetSnapshotData never includes our own XID in |
1210 | | * the snapshot. (There must, therefore, be enough room to add it.) |
1211 | | * |
1212 | | * However, it could be that our topXid is after the xmax, in which case |
1213 | | * we shouldn't include it because xip[] members are expected to be before |
1214 | | * xmax. (We need not make the same check for subxip[] members, see |
1215 | | * snapshot.h.) |
1216 | | */ |
1217 | 0 | addTopXid = (TransactionIdIsValid(topXid) && |
1218 | 0 | TransactionIdPrecedes(topXid, snapshot->xmax)) ? 1 : 0; |
1219 | 0 | appendStringInfo(&buf, "xcnt:%d\n", snapshot->xcnt + addTopXid); |
1220 | 0 | for (uint32 i = 0; i < snapshot->xcnt; i++) |
1221 | 0 | appendStringInfo(&buf, "xip:%u\n", snapshot->xip[i]); |
1222 | 0 | if (addTopXid) |
1223 | 0 | appendStringInfo(&buf, "xip:%u\n", topXid); |
1224 | | |
1225 | | /* |
1226 | | * Similarly, we add our subcommitted child XIDs to the subxid data. Here, |
1227 | | * we have to cope with possible overflow. |
1228 | | */ |
1229 | 0 | if (snapshot->suboverflowed || |
1230 | 0 | snapshot->subxcnt + nchildren > GetMaxSnapshotSubxidCount()) |
1231 | 0 | appendStringInfoString(&buf, "sof:1\n"); |
1232 | 0 | else |
1233 | 0 | { |
1234 | 0 | appendStringInfoString(&buf, "sof:0\n"); |
1235 | 0 | appendStringInfo(&buf, "sxcnt:%d\n", snapshot->subxcnt + nchildren); |
1236 | 0 | for (int32 i = 0; i < snapshot->subxcnt; i++) |
1237 | 0 | appendStringInfo(&buf, "sxp:%u\n", snapshot->subxip[i]); |
1238 | 0 | for (int32 i = 0; i < nchildren; i++) |
1239 | 0 | appendStringInfo(&buf, "sxp:%u\n", children[i]); |
1240 | 0 | } |
1241 | 0 | appendStringInfo(&buf, "rec:%u\n", snapshot->takenDuringRecovery); |
1242 | | |
1243 | | /* |
1244 | | * Now write the text representation into a file. We first write to a |
1245 | | * ".tmp" filename, and rename to final filename if no error. This |
1246 | | * ensures that no other backend can read an incomplete file |
1247 | | * (ImportSnapshot won't allow it because of its valid-characters check). |
1248 | | */ |
1249 | 0 | snprintf(pathtmp, sizeof(pathtmp), "%s.tmp", path); |
1250 | 0 | if (!(f = AllocateFile(pathtmp, PG_BINARY_W))) |
1251 | 0 | ereport(ERROR, |
1252 | 0 | (errcode_for_file_access(), |
1253 | 0 | errmsg("could not create file \"%s\": %m", pathtmp))); |
1254 | | |
1255 | 0 | if (fwrite(buf.data, buf.len, 1, f) != 1) |
1256 | 0 | ereport(ERROR, |
1257 | 0 | (errcode_for_file_access(), |
1258 | 0 | errmsg("could not write to file \"%s\": %m", pathtmp))); |
1259 | | |
1260 | | /* no fsync() since file need not survive a system crash */ |
1261 | | |
1262 | 0 | if (FreeFile(f)) |
1263 | 0 | ereport(ERROR, |
1264 | 0 | (errcode_for_file_access(), |
1265 | 0 | errmsg("could not write to file \"%s\": %m", pathtmp))); |
1266 | | |
1267 | | /* |
1268 | | * Now that we have written everything into a .tmp file, rename the file |
1269 | | * to remove the .tmp suffix. |
1270 | | */ |
1271 | 0 | if (rename(pathtmp, path) < 0) |
1272 | 0 | ereport(ERROR, |
1273 | 0 | (errcode_for_file_access(), |
1274 | 0 | errmsg("could not rename file \"%s\" to \"%s\": %m", |
1275 | 0 | pathtmp, path))); |
1276 | | |
1277 | | /* |
1278 | | * The basename of the file is what we return from pg_export_snapshot(). |
1279 | | * It's already in path in a textual format and we know that the path |
1280 | | * starts with SNAPSHOT_EXPORT_DIR. Skip over the prefix and the slash |
1281 | | * and pstrdup it so as not to return the address of a local variable. |
1282 | | */ |
1283 | 0 | return pstrdup(path + strlen(SNAPSHOT_EXPORT_DIR) + 1); |
1284 | 0 | } |
1285 | | |
1286 | | /* |
1287 | | * pg_export_snapshot |
1288 | | * SQL-callable wrapper for ExportSnapshot. |
1289 | | */ |
1290 | | Datum |
1291 | | pg_export_snapshot(PG_FUNCTION_ARGS) |
1292 | 0 | { |
1293 | 0 | char *snapshotName; |
1294 | |
|
1295 | 0 | snapshotName = ExportSnapshot(GetActiveSnapshot()); |
1296 | 0 | PG_RETURN_TEXT_P(cstring_to_text(snapshotName)); |
1297 | 0 | } |
1298 | | |
1299 | | |
1300 | | /* |
1301 | | * Parsing subroutines for ImportSnapshot: parse a line with the given |
1302 | | * prefix followed by a value, and advance *s to the next line. The |
1303 | | * filename is provided for use in error messages. |
1304 | | */ |
1305 | | static int |
1306 | | parseIntFromText(const char *prefix, char **s, const char *filename) |
1307 | 0 | { |
1308 | 0 | char *ptr = *s; |
1309 | 0 | int prefixlen = strlen(prefix); |
1310 | 0 | int val; |
1311 | |
|
1312 | 0 | if (strncmp(ptr, prefix, prefixlen) != 0) |
1313 | 0 | ereport(ERROR, |
1314 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1315 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1316 | 0 | ptr += prefixlen; |
1317 | 0 | if (sscanf(ptr, "%d", &val) != 1) |
1318 | 0 | ereport(ERROR, |
1319 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1320 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1321 | 0 | ptr = strchr(ptr, '\n'); |
1322 | 0 | if (!ptr) |
1323 | 0 | ereport(ERROR, |
1324 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1325 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1326 | 0 | *s = ptr + 1; |
1327 | 0 | return val; |
1328 | 0 | } |
1329 | | |
1330 | | static TransactionId |
1331 | | parseXidFromText(const char *prefix, char **s, const char *filename) |
1332 | 0 | { |
1333 | 0 | char *ptr = *s; |
1334 | 0 | int prefixlen = strlen(prefix); |
1335 | 0 | TransactionId val; |
1336 | |
|
1337 | 0 | if (strncmp(ptr, prefix, prefixlen) != 0) |
1338 | 0 | ereport(ERROR, |
1339 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1340 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1341 | 0 | ptr += prefixlen; |
1342 | 0 | if (sscanf(ptr, "%u", &val) != 1) |
1343 | 0 | ereport(ERROR, |
1344 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1345 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1346 | 0 | ptr = strchr(ptr, '\n'); |
1347 | 0 | if (!ptr) |
1348 | 0 | ereport(ERROR, |
1349 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1350 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1351 | 0 | *s = ptr + 1; |
1352 | 0 | return val; |
1353 | 0 | } |
1354 | | |
1355 | | static void |
1356 | | parseVxidFromText(const char *prefix, char **s, const char *filename, |
1357 | | VirtualTransactionId *vxid) |
1358 | 0 | { |
1359 | 0 | char *ptr = *s; |
1360 | 0 | int prefixlen = strlen(prefix); |
1361 | |
|
1362 | 0 | if (strncmp(ptr, prefix, prefixlen) != 0) |
1363 | 0 | ereport(ERROR, |
1364 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1365 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1366 | 0 | ptr += prefixlen; |
1367 | 0 | if (sscanf(ptr, "%d/%u", &vxid->procNumber, &vxid->localTransactionId) != 2) |
1368 | 0 | ereport(ERROR, |
1369 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1370 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1371 | 0 | ptr = strchr(ptr, '\n'); |
1372 | 0 | if (!ptr) |
1373 | 0 | ereport(ERROR, |
1374 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1375 | 0 | errmsg("invalid snapshot data in file \"%s\"", filename))); |
1376 | 0 | *s = ptr + 1; |
1377 | 0 | } |
1378 | | |
1379 | | /* |
1380 | | * ImportSnapshot |
1381 | | * Import a previously exported snapshot. The argument should be a |
1382 | | * filename in SNAPSHOT_EXPORT_DIR. Load the snapshot from that file. |
1383 | | * This is called by "SET TRANSACTION SNAPSHOT 'foo'". |
1384 | | */ |
1385 | | void |
1386 | | ImportSnapshot(const char *idstr) |
1387 | 0 | { |
1388 | 0 | char path[MAXPGPATH]; |
1389 | 0 | FILE *f; |
1390 | 0 | struct stat stat_buf; |
1391 | 0 | char *filebuf; |
1392 | 0 | int xcnt; |
1393 | 0 | int i; |
1394 | 0 | VirtualTransactionId src_vxid; |
1395 | 0 | int src_pid; |
1396 | 0 | Oid src_dbid; |
1397 | 0 | int src_isolevel; |
1398 | 0 | bool src_readonly; |
1399 | 0 | SnapshotData snapshot; |
1400 | | |
1401 | | /* |
1402 | | * Must be at top level of a fresh transaction. Note in particular that |
1403 | | * we check we haven't acquired an XID --- if we have, it's conceivable |
1404 | | * that the snapshot would show it as not running, making for very screwy |
1405 | | * behavior. |
1406 | | */ |
1407 | 0 | if (FirstSnapshotSet || |
1408 | 0 | GetTopTransactionIdIfAny() != InvalidTransactionId || |
1409 | 0 | IsSubTransaction()) |
1410 | 0 | ereport(ERROR, |
1411 | 0 | (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), |
1412 | 0 | errmsg("SET TRANSACTION SNAPSHOT must be called before any query"))); |
1413 | | |
1414 | | /* |
1415 | | * If we are in read committed mode then the next query would execute with |
1416 | | * a new snapshot thus making this function call quite useless. |
1417 | | */ |
1418 | 0 | if (!IsolationUsesXactSnapshot()) |
1419 | 0 | ereport(ERROR, |
1420 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
1421 | 0 | errmsg("a snapshot-importing transaction must have isolation level SERIALIZABLE or REPEATABLE READ"))); |
1422 | | |
1423 | | /* |
1424 | | * Verify the identifier: only 0-9, A-F and hyphens are allowed. We do |
1425 | | * this mainly to prevent reading arbitrary files. |
1426 | | */ |
1427 | 0 | if (strspn(idstr, "0123456789ABCDEF-") != strlen(idstr)) |
1428 | 0 | ereport(ERROR, |
1429 | 0 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
1430 | 0 | errmsg("invalid snapshot identifier: \"%s\"", idstr))); |
1431 | | |
1432 | | /* OK, read the file */ |
1433 | 0 | snprintf(path, MAXPGPATH, SNAPSHOT_EXPORT_DIR "/%s", idstr); |
1434 | |
|
1435 | 0 | f = AllocateFile(path, PG_BINARY_R); |
1436 | 0 | if (!f) |
1437 | 0 | { |
1438 | | /* |
1439 | | * If file is missing while identifier has a correct format, avoid |
1440 | | * system errors. |
1441 | | */ |
1442 | 0 | if (errno == ENOENT) |
1443 | 0 | ereport(ERROR, |
1444 | 0 | (errcode(ERRCODE_UNDEFINED_OBJECT), |
1445 | 0 | errmsg("snapshot \"%s\" does not exist", idstr))); |
1446 | 0 | else |
1447 | 0 | ereport(ERROR, |
1448 | 0 | (errcode_for_file_access(), |
1449 | 0 | errmsg("could not open file \"%s\" for reading: %m", |
1450 | 0 | path))); |
1451 | 0 | } |
1452 | | |
1453 | | /* get the size of the file so that we know how much memory we need */ |
1454 | 0 | if (fstat(fileno(f), &stat_buf)) |
1455 | 0 | elog(ERROR, "could not stat file \"%s\": %m", path); |
1456 | | |
1457 | | /* and read the file into a palloc'd string */ |
1458 | 0 | filebuf = (char *) palloc(stat_buf.st_size + 1); |
1459 | 0 | if (fread(filebuf, stat_buf.st_size, 1, f) != 1) |
1460 | 0 | elog(ERROR, "could not read file \"%s\": %m", path); |
1461 | | |
1462 | 0 | filebuf[stat_buf.st_size] = '\0'; |
1463 | |
|
1464 | 0 | FreeFile(f); |
1465 | | |
1466 | | /* |
1467 | | * Construct a snapshot struct by parsing the file content. |
1468 | | */ |
1469 | 0 | memset(&snapshot, 0, sizeof(snapshot)); |
1470 | |
|
1471 | 0 | parseVxidFromText("vxid:", &filebuf, path, &src_vxid); |
1472 | 0 | src_pid = parseIntFromText("pid:", &filebuf, path); |
1473 | | /* we abuse parseXidFromText a bit here ... */ |
1474 | 0 | src_dbid = parseXidFromText("dbid:", &filebuf, path); |
1475 | 0 | src_isolevel = parseIntFromText("iso:", &filebuf, path); |
1476 | 0 | src_readonly = parseIntFromText("ro:", &filebuf, path); |
1477 | |
|
1478 | 0 | snapshot.snapshot_type = SNAPSHOT_MVCC; |
1479 | |
|
1480 | 0 | snapshot.xmin = parseXidFromText("xmin:", &filebuf, path); |
1481 | 0 | snapshot.xmax = parseXidFromText("xmax:", &filebuf, path); |
1482 | |
|
1483 | 0 | snapshot.xcnt = xcnt = parseIntFromText("xcnt:", &filebuf, path); |
1484 | | |
1485 | | /* sanity-check the xid count before palloc */ |
1486 | 0 | if (xcnt < 0 || xcnt > GetMaxSnapshotXidCount()) |
1487 | 0 | ereport(ERROR, |
1488 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1489 | 0 | errmsg("invalid snapshot data in file \"%s\"", path))); |
1490 | | |
1491 | 0 | snapshot.xip = (TransactionId *) palloc(xcnt * sizeof(TransactionId)); |
1492 | 0 | for (i = 0; i < xcnt; i++) |
1493 | 0 | snapshot.xip[i] = parseXidFromText("xip:", &filebuf, path); |
1494 | |
|
1495 | 0 | snapshot.suboverflowed = parseIntFromText("sof:", &filebuf, path); |
1496 | |
|
1497 | 0 | if (!snapshot.suboverflowed) |
1498 | 0 | { |
1499 | 0 | snapshot.subxcnt = xcnt = parseIntFromText("sxcnt:", &filebuf, path); |
1500 | | |
1501 | | /* sanity-check the xid count before palloc */ |
1502 | 0 | if (xcnt < 0 || xcnt > GetMaxSnapshotSubxidCount()) |
1503 | 0 | ereport(ERROR, |
1504 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1505 | 0 | errmsg("invalid snapshot data in file \"%s\"", path))); |
1506 | | |
1507 | 0 | snapshot.subxip = (TransactionId *) palloc(xcnt * sizeof(TransactionId)); |
1508 | 0 | for (i = 0; i < xcnt; i++) |
1509 | 0 | snapshot.subxip[i] = parseXidFromText("sxp:", &filebuf, path); |
1510 | 0 | } |
1511 | 0 | else |
1512 | 0 | { |
1513 | 0 | snapshot.subxcnt = 0; |
1514 | 0 | snapshot.subxip = NULL; |
1515 | 0 | } |
1516 | | |
1517 | 0 | snapshot.takenDuringRecovery = parseIntFromText("rec:", &filebuf, path); |
1518 | | |
1519 | | /* |
1520 | | * Do some additional sanity checking, just to protect ourselves. We |
1521 | | * don't trouble to check the array elements, just the most critical |
1522 | | * fields. |
1523 | | */ |
1524 | 0 | if (!VirtualTransactionIdIsValid(src_vxid) || |
1525 | 0 | !OidIsValid(src_dbid) || |
1526 | 0 | !TransactionIdIsNormal(snapshot.xmin) || |
1527 | 0 | !TransactionIdIsNormal(snapshot.xmax)) |
1528 | 0 | ereport(ERROR, |
1529 | 0 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), |
1530 | 0 | errmsg("invalid snapshot data in file \"%s\"", path))); |
1531 | | |
1532 | | /* |
1533 | | * If we're serializable, the source transaction must be too, otherwise |
1534 | | * predicate.c has problems (SxactGlobalXmin could go backwards). Also, a |
1535 | | * non-read-only transaction can't adopt a snapshot from a read-only |
1536 | | * transaction, as predicate.c handles the cases very differently. |
1537 | | */ |
1538 | 0 | if (IsolationIsSerializable()) |
1539 | 0 | { |
1540 | 0 | if (src_isolevel != XACT_SERIALIZABLE) |
1541 | 0 | ereport(ERROR, |
1542 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
1543 | 0 | errmsg("a serializable transaction cannot import a snapshot from a non-serializable transaction"))); |
1544 | 0 | if (src_readonly && !XactReadOnly) |
1545 | 0 | ereport(ERROR, |
1546 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
1547 | 0 | errmsg("a non-read-only serializable transaction cannot import a snapshot from a read-only transaction"))); |
1548 | 0 | } |
1549 | | |
1550 | | /* |
1551 | | * We cannot import a snapshot that was taken in a different database, |
1552 | | * because vacuum calculates OldestXmin on a per-database basis; so the |
1553 | | * source transaction's xmin doesn't protect us from data loss. This |
1554 | | * restriction could be removed if the source transaction were to mark its |
1555 | | * xmin as being globally applicable. But that would require some |
1556 | | * additional syntax, since that has to be known when the snapshot is |
1557 | | * initially taken. (See pgsql-hackers discussion of 2011-10-21.) |
1558 | | */ |
1559 | 0 | if (src_dbid != MyDatabaseId) |
1560 | 0 | ereport(ERROR, |
1561 | 0 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), |
1562 | 0 | errmsg("cannot import a snapshot from a different database"))); |
1563 | | |
1564 | | /* OK, install the snapshot */ |
1565 | 0 | SetTransactionSnapshot(&snapshot, &src_vxid, src_pid, NULL); |
1566 | 0 | } |
1567 | | |
1568 | | /* |
1569 | | * XactHasExportedSnapshots |
1570 | | * Test whether current transaction has exported any snapshots. |
1571 | | */ |
1572 | | bool |
1573 | | XactHasExportedSnapshots(void) |
1574 | 0 | { |
1575 | 0 | return (exportedSnapshots != NIL); |
1576 | 0 | } |
1577 | | |
1578 | | /* |
1579 | | * DeleteAllExportedSnapshotFiles |
1580 | | * Clean up any files that have been left behind by a crashed backend |
1581 | | * that had exported snapshots before it died. |
1582 | | * |
1583 | | * This should be called during database startup or crash recovery. |
1584 | | */ |
1585 | | void |
1586 | | DeleteAllExportedSnapshotFiles(void) |
1587 | | { |
1588 | | char buf[MAXPGPATH + sizeof(SNAPSHOT_EXPORT_DIR)]; |
1589 | | DIR *s_dir; |
1590 | | struct dirent *s_de; |
1591 | | |
1592 | | /* |
1593 | | * Problems in reading the directory, or unlinking files, are reported at |
1594 | | * LOG level. Since we're running in the startup process, ERROR level |
1595 | | * would prevent database start, and it's not important enough for that. |
1596 | | */ |
1597 | | s_dir = AllocateDir(SNAPSHOT_EXPORT_DIR); |
1598 | | |
1599 | | while ((s_de = ReadDirExtended(s_dir, SNAPSHOT_EXPORT_DIR, LOG)) != NULL) |
1600 | | { |
1601 | | if (strcmp(s_de->d_name, ".") == 0 || |
1602 | | strcmp(s_de->d_name, "..") == 0) |
1603 | | continue; |
1604 | | |
1605 | | snprintf(buf, sizeof(buf), SNAPSHOT_EXPORT_DIR "/%s", s_de->d_name); |
1606 | | |
1607 | | if (unlink(buf) != 0) |
1608 | | ereport(LOG, |
1609 | | (errcode_for_file_access(), |
1610 | | errmsg("could not remove file \"%s\": %m", buf))); |
1611 | | } |
1612 | | |
1613 | | FreeDir(s_dir); |
1614 | | } |
1615 | | |
1616 | | /* |
1617 | | * ThereAreNoPriorRegisteredSnapshots |
1618 | | * Is the registered snapshot count less than or equal to one? |
1619 | | * |
1620 | | * Don't use this to settle important decisions. While zero registrations and |
1621 | | * no ActiveSnapshot would confirm a certain idleness, the system makes no |
1622 | | * guarantees about the significance of one registered snapshot. |
1623 | | */ |
1624 | | bool |
1625 | | ThereAreNoPriorRegisteredSnapshots(void) |
1626 | 0 | { |
1627 | 0 | if (pairingheap_is_empty(&RegisteredSnapshots) || |
1628 | 0 | pairingheap_is_singular(&RegisteredSnapshots)) |
1629 | 0 | return true; |
1630 | | |
1631 | 0 | return false; |
1632 | 0 | } |
1633 | | |
1634 | | /* |
1635 | | * HaveRegisteredOrActiveSnapshot |
1636 | | * Is there any registered or active snapshot? |
1637 | | * |
1638 | | * NB: Unless pushed or active, the cached catalog snapshot will not cause |
1639 | | * this function to return true. That allows this function to be used in |
1640 | | * checks enforcing a longer-lived snapshot. |
1641 | | */ |
1642 | | bool |
1643 | | HaveRegisteredOrActiveSnapshot(void) |
1644 | 0 | { |
1645 | 0 | if (ActiveSnapshot != NULL) |
1646 | 0 | return true; |
1647 | | |
1648 | | /* |
1649 | | * The catalog snapshot is in RegisteredSnapshots when valid, but can be |
1650 | | * removed at any time due to invalidation processing. If explicitly |
1651 | | * registered more than one snapshot has to be in RegisteredSnapshots. |
1652 | | */ |
1653 | 0 | if (CatalogSnapshot != NULL && |
1654 | 0 | pairingheap_is_singular(&RegisteredSnapshots)) |
1655 | 0 | return false; |
1656 | | |
1657 | 0 | return !pairingheap_is_empty(&RegisteredSnapshots); |
1658 | 0 | } |
1659 | | |
1660 | | |
1661 | | /* |
1662 | | * Setup a snapshot that replaces normal catalog snapshots that allows catalog |
1663 | | * access to behave just like it did at a certain point in the past. |
1664 | | * |
1665 | | * Needed for logical decoding. |
1666 | | */ |
1667 | | void |
1668 | | SetupHistoricSnapshot(Snapshot historic_snapshot, HTAB *tuplecids) |
1669 | 0 | { |
1670 | 0 | Assert(historic_snapshot != NULL); |
1671 | | |
1672 | | /* setup the timetravel snapshot */ |
1673 | 0 | HistoricSnapshot = historic_snapshot; |
1674 | | |
1675 | | /* setup (cmin, cmax) lookup hash */ |
1676 | 0 | tuplecid_data = tuplecids; |
1677 | 0 | } |
1678 | | |
1679 | | |
1680 | | /* |
1681 | | * Make catalog snapshots behave normally again. |
1682 | | */ |
1683 | | void |
1684 | | TeardownHistoricSnapshot(bool is_error) |
1685 | 0 | { |
1686 | 0 | HistoricSnapshot = NULL; |
1687 | 0 | tuplecid_data = NULL; |
1688 | 0 | } |
1689 | | |
1690 | | bool |
1691 | | HistoricSnapshotActive(void) |
1692 | 0 | { |
1693 | 0 | return HistoricSnapshot != NULL; |
1694 | 0 | } |
1695 | | |
1696 | | HTAB * |
1697 | | HistoricSnapshotGetTupleCids(void) |
1698 | 0 | { |
1699 | 0 | Assert(HistoricSnapshotActive()); |
1700 | 0 | return tuplecid_data; |
1701 | 0 | } |
1702 | | |
1703 | | /* |
1704 | | * EstimateSnapshotSpace |
1705 | | * Returns the size needed to store the given snapshot. |
1706 | | * |
1707 | | * We are exporting only required fields from the Snapshot, stored in |
1708 | | * SerializedSnapshotData. |
1709 | | */ |
1710 | | Size |
1711 | | EstimateSnapshotSpace(Snapshot snapshot) |
1712 | 0 | { |
1713 | 0 | Size size; |
1714 | |
|
1715 | 0 | Assert(snapshot != InvalidSnapshot); |
1716 | 0 | Assert(snapshot->snapshot_type == SNAPSHOT_MVCC); |
1717 | | |
1718 | | /* We allocate any XID arrays needed in the same palloc block. */ |
1719 | 0 | size = add_size(sizeof(SerializedSnapshotData), |
1720 | 0 | mul_size(snapshot->xcnt, sizeof(TransactionId))); |
1721 | 0 | if (snapshot->subxcnt > 0 && |
1722 | 0 | (!snapshot->suboverflowed || snapshot->takenDuringRecovery)) |
1723 | 0 | size = add_size(size, |
1724 | 0 | mul_size(snapshot->subxcnt, sizeof(TransactionId))); |
1725 | |
|
1726 | 0 | return size; |
1727 | 0 | } |
1728 | | |
1729 | | /* |
1730 | | * SerializeSnapshot |
1731 | | * Dumps the serialized snapshot (extracted from given snapshot) onto the |
1732 | | * memory location at start_address. |
1733 | | */ |
1734 | | void |
1735 | | SerializeSnapshot(Snapshot snapshot, char *start_address) |
1736 | 0 | { |
1737 | 0 | SerializedSnapshotData serialized_snapshot = {0}; |
1738 | |
|
1739 | 0 | Assert(snapshot->subxcnt >= 0); |
1740 | | |
1741 | | /* Copy all required fields */ |
1742 | 0 | serialized_snapshot.xmin = snapshot->xmin; |
1743 | 0 | serialized_snapshot.xmax = snapshot->xmax; |
1744 | 0 | serialized_snapshot.xcnt = snapshot->xcnt; |
1745 | 0 | serialized_snapshot.subxcnt = snapshot->subxcnt; |
1746 | 0 | serialized_snapshot.suboverflowed = snapshot->suboverflowed; |
1747 | 0 | serialized_snapshot.takenDuringRecovery = snapshot->takenDuringRecovery; |
1748 | 0 | serialized_snapshot.curcid = snapshot->curcid; |
1749 | | |
1750 | | /* |
1751 | | * Ignore the SubXID array if it has overflowed, unless the snapshot was |
1752 | | * taken during recovery - in that case, top-level XIDs are in subxip as |
1753 | | * well, and we mustn't lose them. |
1754 | | */ |
1755 | 0 | if (serialized_snapshot.suboverflowed && !snapshot->takenDuringRecovery) |
1756 | 0 | serialized_snapshot.subxcnt = 0; |
1757 | | |
1758 | | /* Copy struct to possibly-unaligned buffer */ |
1759 | 0 | memcpy(start_address, |
1760 | 0 | &serialized_snapshot, sizeof(SerializedSnapshotData)); |
1761 | | |
1762 | | /* Copy XID array */ |
1763 | 0 | if (snapshot->xcnt > 0) |
1764 | 0 | memcpy((TransactionId *) (start_address + |
1765 | 0 | sizeof(SerializedSnapshotData)), |
1766 | 0 | snapshot->xip, snapshot->xcnt * sizeof(TransactionId)); |
1767 | | |
1768 | | /* |
1769 | | * Copy SubXID array. Don't bother to copy it if it had overflowed, |
1770 | | * though, because it's not used anywhere in that case. Except if it's a |
1771 | | * snapshot taken during recovery; all the top-level XIDs are in subxip as |
1772 | | * well in that case, so we mustn't lose them. |
1773 | | */ |
1774 | 0 | if (serialized_snapshot.subxcnt > 0) |
1775 | 0 | { |
1776 | 0 | Size subxipoff = sizeof(SerializedSnapshotData) + |
1777 | 0 | snapshot->xcnt * sizeof(TransactionId); |
1778 | |
|
1779 | 0 | memcpy((TransactionId *) (start_address + subxipoff), |
1780 | 0 | snapshot->subxip, snapshot->subxcnt * sizeof(TransactionId)); |
1781 | 0 | } |
1782 | 0 | } |
1783 | | |
1784 | | /* |
1785 | | * RestoreSnapshot |
1786 | | * Restore a serialized snapshot from the specified address. |
1787 | | * |
1788 | | * The copy is palloc'd in TopTransactionContext and has initial refcounts set |
1789 | | * to 0. The returned snapshot has the copied flag set. |
1790 | | */ |
1791 | | Snapshot |
1792 | | RestoreSnapshot(char *start_address) |
1793 | 0 | { |
1794 | 0 | SerializedSnapshotData serialized_snapshot; |
1795 | 0 | Size size; |
1796 | 0 | Snapshot snapshot; |
1797 | 0 | TransactionId *serialized_xids; |
1798 | |
|
1799 | 0 | memcpy(&serialized_snapshot, start_address, |
1800 | 0 | sizeof(SerializedSnapshotData)); |
1801 | 0 | serialized_xids = (TransactionId *) |
1802 | 0 | (start_address + sizeof(SerializedSnapshotData)); |
1803 | | |
1804 | | /* We allocate any XID arrays needed in the same palloc block. */ |
1805 | 0 | size = sizeof(SnapshotData) |
1806 | 0 | + serialized_snapshot.xcnt * sizeof(TransactionId) |
1807 | 0 | + serialized_snapshot.subxcnt * sizeof(TransactionId); |
1808 | | |
1809 | | /* Copy all required fields */ |
1810 | 0 | snapshot = (Snapshot) MemoryContextAlloc(TopTransactionContext, size); |
1811 | 0 | snapshot->snapshot_type = SNAPSHOT_MVCC; |
1812 | 0 | snapshot->xmin = serialized_snapshot.xmin; |
1813 | 0 | snapshot->xmax = serialized_snapshot.xmax; |
1814 | 0 | snapshot->xip = NULL; |
1815 | 0 | snapshot->xcnt = serialized_snapshot.xcnt; |
1816 | 0 | snapshot->subxip = NULL; |
1817 | 0 | snapshot->subxcnt = serialized_snapshot.subxcnt; |
1818 | 0 | snapshot->suboverflowed = serialized_snapshot.suboverflowed; |
1819 | 0 | snapshot->takenDuringRecovery = serialized_snapshot.takenDuringRecovery; |
1820 | 0 | snapshot->curcid = serialized_snapshot.curcid; |
1821 | 0 | snapshot->snapXactCompletionCount = 0; |
1822 | | |
1823 | | /* Copy XIDs, if present. */ |
1824 | 0 | if (serialized_snapshot.xcnt > 0) |
1825 | 0 | { |
1826 | 0 | snapshot->xip = (TransactionId *) (snapshot + 1); |
1827 | 0 | memcpy(snapshot->xip, serialized_xids, |
1828 | 0 | serialized_snapshot.xcnt * sizeof(TransactionId)); |
1829 | 0 | } |
1830 | | |
1831 | | /* Copy SubXIDs, if present. */ |
1832 | 0 | if (serialized_snapshot.subxcnt > 0) |
1833 | 0 | { |
1834 | 0 | snapshot->subxip = ((TransactionId *) (snapshot + 1)) + |
1835 | 0 | serialized_snapshot.xcnt; |
1836 | 0 | memcpy(snapshot->subxip, serialized_xids + serialized_snapshot.xcnt, |
1837 | 0 | serialized_snapshot.subxcnt * sizeof(TransactionId)); |
1838 | 0 | } |
1839 | | |
1840 | | /* Set the copied flag so that the caller will set refcounts correctly. */ |
1841 | 0 | snapshot->regd_count = 0; |
1842 | 0 | snapshot->active_count = 0; |
1843 | 0 | snapshot->copied = true; |
1844 | |
|
1845 | 0 | return snapshot; |
1846 | 0 | } |
1847 | | |
1848 | | /* |
1849 | | * Install a restored snapshot as the transaction snapshot. |
1850 | | */ |
1851 | | void |
1852 | | RestoreTransactionSnapshot(Snapshot snapshot, PGPROC *source_pgproc) |
1853 | 0 | { |
1854 | 0 | SetTransactionSnapshot(snapshot, NULL, InvalidPid, source_pgproc); |
1855 | 0 | } |
1856 | | |
1857 | | /* |
1858 | | * XidInMVCCSnapshot |
1859 | | * Is the given XID still-in-progress according to the snapshot? |
1860 | | * |
1861 | | * Note: GetSnapshotData never stores either top xid or subxids of our own |
1862 | | * backend into a snapshot, so these xids will not be reported as "running" |
1863 | | * by this function. This is OK for current uses, because we always check |
1864 | | * TransactionIdIsCurrentTransactionId first, except when it's known the |
1865 | | * XID could not be ours anyway. |
1866 | | */ |
1867 | | bool |
1868 | | XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) |
1869 | 0 | { |
1870 | | /* |
1871 | | * Make a quick range check to eliminate most XIDs without looking at the |
1872 | | * xip arrays. Note that this is OK even if we convert a subxact XID to |
1873 | | * its parent below, because a subxact with XID < xmin has surely also got |
1874 | | * a parent with XID < xmin, while one with XID >= xmax must belong to a |
1875 | | * parent that was not yet committed at the time of this snapshot. |
1876 | | */ |
1877 | | |
1878 | | /* Any xid < xmin is not in-progress */ |
1879 | 0 | if (TransactionIdPrecedes(xid, snapshot->xmin)) |
1880 | 0 | return false; |
1881 | | /* Any xid >= xmax is in-progress */ |
1882 | 0 | if (TransactionIdFollowsOrEquals(xid, snapshot->xmax)) |
1883 | 0 | return true; |
1884 | | |
1885 | | /* |
1886 | | * Snapshot information is stored slightly differently in snapshots taken |
1887 | | * during recovery. |
1888 | | */ |
1889 | 0 | if (!snapshot->takenDuringRecovery) |
1890 | 0 | { |
1891 | | /* |
1892 | | * If the snapshot contains full subxact data, the fastest way to |
1893 | | * check things is just to compare the given XID against both subxact |
1894 | | * XIDs and top-level XIDs. If the snapshot overflowed, we have to |
1895 | | * use pg_subtrans to convert a subxact XID to its parent XID, but |
1896 | | * then we need only look at top-level XIDs not subxacts. |
1897 | | */ |
1898 | 0 | if (!snapshot->suboverflowed) |
1899 | 0 | { |
1900 | | /* we have full data, so search subxip */ |
1901 | 0 | if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt)) |
1902 | 0 | return true; |
1903 | | |
1904 | | /* not there, fall through to search xip[] */ |
1905 | 0 | } |
1906 | 0 | else |
1907 | 0 | { |
1908 | | /* |
1909 | | * Snapshot overflowed, so convert xid to top-level. This is safe |
1910 | | * because we eliminated too-old XIDs above. |
1911 | | */ |
1912 | 0 | xid = SubTransGetTopmostTransaction(xid); |
1913 | | |
1914 | | /* |
1915 | | * If xid was indeed a subxact, we might now have an xid < xmin, |
1916 | | * so recheck to avoid an array scan. No point in rechecking |
1917 | | * xmax. |
1918 | | */ |
1919 | 0 | if (TransactionIdPrecedes(xid, snapshot->xmin)) |
1920 | 0 | return false; |
1921 | 0 | } |
1922 | | |
1923 | 0 | if (pg_lfind32(xid, snapshot->xip, snapshot->xcnt)) |
1924 | 0 | return true; |
1925 | 0 | } |
1926 | 0 | else |
1927 | 0 | { |
1928 | | /* |
1929 | | * In recovery we store all xids in the subxip array because it is by |
1930 | | * far the bigger array, and we mostly don't know which xids are |
1931 | | * top-level and which are subxacts. The xip array is empty. |
1932 | | * |
1933 | | * We start by searching subtrans, if we overflowed. |
1934 | | */ |
1935 | 0 | if (snapshot->suboverflowed) |
1936 | 0 | { |
1937 | | /* |
1938 | | * Snapshot overflowed, so convert xid to top-level. This is safe |
1939 | | * because we eliminated too-old XIDs above. |
1940 | | */ |
1941 | 0 | xid = SubTransGetTopmostTransaction(xid); |
1942 | | |
1943 | | /* |
1944 | | * If xid was indeed a subxact, we might now have an xid < xmin, |
1945 | | * so recheck to avoid an array scan. No point in rechecking |
1946 | | * xmax. |
1947 | | */ |
1948 | 0 | if (TransactionIdPrecedes(xid, snapshot->xmin)) |
1949 | 0 | return false; |
1950 | 0 | } |
1951 | | |
1952 | | /* |
1953 | | * We now have either a top-level xid higher than xmin or an |
1954 | | * indeterminate xid. We don't know whether it's top level or subxact |
1955 | | * but it doesn't matter. If it's present, the xid is visible. |
1956 | | */ |
1957 | 0 | if (pg_lfind32(xid, snapshot->subxip, snapshot->subxcnt)) |
1958 | 0 | return true; |
1959 | 0 | } |
1960 | | |
1961 | 0 | return false; |
1962 | 0 | } |
1963 | | |
1964 | | /* ResourceOwner callbacks */ |
1965 | | |
1966 | | static void |
1967 | | ResOwnerReleaseSnapshot(Datum res) |
1968 | 0 | { |
1969 | 0 | UnregisterSnapshotNoOwner((Snapshot) DatumGetPointer(res)); |
1970 | 0 | } |