]> granicus.if.org Git - postgresql/blob - src/backend/utils/time/snapmgr.c
Initialize the minimum frozen Xid in vac_update_datfrozenxid using
[postgresql] / src / backend / utils / time / snapmgr.c
1 /*-------------------------------------------------------------------------
2  * snapmgr.c
3  *              PostgreSQL snapshot manager
4  *
5  * We keep track of snapshots in two ways: the "registered snapshots" list,
6  * and the "active snapshot" stack.  All snapshots in either of them live in
7  * persistent memory.  When a snapshot is no longer in any of these lists
8  * (tracked by separate refcounts on each snapshot), its memory can be freed.
9  *
10  * These arrangements let us reset MyProc->xmin when there are no snapshots
11  * referenced by this transaction.  (One possible improvement would be to be
12  * able to advance Xmin when the snapshot with the earliest Xmin is no longer
13  * referenced.  That's a bit harder though, it requires more locking, and
14  * anyway it should be rather uncommon to keep snapshots referenced for too
15  * long.)
16  *
17  * Note: parts of this code could probably be replaced by appropriate use
18  * of resowner.c.
19  *
20  *
21  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
22  * Portions Copyright (c) 1994, Regents of the University of California
23  *
24  * IDENTIFICATION
25  *        $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.5 2008/09/11 14:01:10 alvherre Exp $
26  *
27  *-------------------------------------------------------------------------
28  */
29 #include "postgres.h"
30
31 #include "access/transam.h"
32 #include "access/xact.h"
33 #include "storage/proc.h"
34 #include "storage/procarray.h"
35 #include "utils/memutils.h"
36 #include "utils/memutils.h"
37 #include "utils/snapmgr.h"
38 #include "utils/tqual.h"
39
40
41 /*
42  * CurrentSnapshot points to the only snapshot taken in a serializable
43  * transaction, and to the latest one taken in a read-committed transaction.
44  * SecondarySnapshot is a snapshot that's always up-to-date as of the current
45  * instant, even on a serializable transaction.  It should only be used for
46  * special-purpose code (say, RI checking.)
47  *
48  * These SnapshotData structs are static to simplify memory allocation
49  * (see the hack in GetSnapshotData to avoid repeated malloc/free).
50  */
51 static SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC};
52 static SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC};
53
54 /* Pointers to valid snapshots */
55 static Snapshot CurrentSnapshot = NULL;
56 static Snapshot SecondarySnapshot = NULL;
57
58 /*
59  * These are updated by GetSnapshotData.  We initialize them this way
60  * for the convenience of TransactionIdIsInProgress: even in bootstrap
61  * mode, we don't want it to say that BootstrapTransactionId is in progress.
62  *
63  * RecentGlobalXmin is initialized to InvalidTransactionId, to ensure that no
64  * one tries to use a stale value.  Readers should ensure that it has been set
65  * to something else before using it.
66  */
67 TransactionId TransactionXmin = FirstNormalTransactionId;
68 TransactionId RecentXmin = FirstNormalTransactionId;
69 TransactionId RecentGlobalXmin = InvalidTransactionId;
70
71 /*
72  * Elements of the list of registered snapshots.
73  *
74  * Note that we keep refcounts both here and in SnapshotData.  This is because
75  * the same snapshot may be registered more than once in a subtransaction, and
76  * if a subxact aborts we want to be able to subtract the correct amount of
77  * counts from SnapshotData.  (Another approach would be keeping one
78  * RegdSnapshotElt each time a snapshot is registered, but that seems
79  * unnecessary wastage.)
80  *
81  * NB: the code assumes that elements in this list are in non-increasing
82  * order of s_level; also, the list must be NULL-terminated.
83  */
84 typedef struct RegdSnapshotElt
85 {
86         Snapshot        s_snap;
87         uint32          s_count;
88         int                     s_level;
89         struct RegdSnapshotElt  *s_next;
90 } RegdSnapshotElt;
91
92 /*
93  * Elements of the active snapshot stack.
94  *
95  * It's not necessary to keep a refcount like we do for the registered list;
96  * each element here accounts for exactly one active_count on SnapshotData.
97  * We cannot condense them like we do for RegdSnapshotElt because it would mess
98  * up the order of entries in the stack.
99  *
100  * NB: the code assumes that elements in this list are in non-increasing
101  * order of as_level; also, the list must be NULL-terminated.
102  */
103 typedef struct ActiveSnapshotElt
104 {
105         Snapshot        as_snap;
106         int                     as_level;
107         struct ActiveSnapshotElt *as_next;
108 } ActiveSnapshotElt;
109
110 /* Head of the list of registered snapshots */
111 static RegdSnapshotElt     *RegisteredSnapshotList = NULL;
112
113 /* Top of the stack of active snapshots */
114 static ActiveSnapshotElt        *ActiveSnapshot = NULL;
115
116 /* first GetTransactionSnapshot call in a transaction? */
117 bool                                    FirstSnapshotSet = false;
118
119 /*
120  * Remembers whether this transaction registered a serializable snapshot at
121  * start.  We cannot trust FirstSnapshotSet in combination with
122  * IsXactIsoLevelSerializable, because GUC may be reset before us.
123  */
124 static bool                             registered_serializable = false;
125
126
127 static Snapshot CopySnapshot(Snapshot snapshot);
128 static void FreeSnapshot(Snapshot snapshot);
129 static void     SnapshotResetXmin(void);
130
131
132 /*
133  * GetTransactionSnapshot
134  *              Get the appropriate snapshot for a new query in a transaction.
135  *
136  *
137  * Note that the return value may point at static storage that will be modified
138  * by future calls and by CommandCounterIncrement().  Callers should call
139  * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
140  * used very long.
141  */
142 Snapshot
143 GetTransactionSnapshot(void)
144 {
145         /* First call in transaction? */
146         if (!FirstSnapshotSet)
147         {
148                 CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
149                 FirstSnapshotSet = true;
150
151                 /*
152                  * In serializable mode, the first snapshot must live until end of xact
153                  * regardless of what the caller does with it, so we must register it
154                  * internally here and unregister it at end of xact.
155                  */
156                 if (IsXactIsoLevelSerializable)
157                 {
158                         CurrentSnapshot = RegisterSnapshot(CurrentSnapshot);
159                         registered_serializable = true;
160                 }
161
162                 return CurrentSnapshot;
163         }
164
165         if (IsXactIsoLevelSerializable)
166                 return CurrentSnapshot;
167
168         CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
169
170         return CurrentSnapshot;
171 }
172
173 /*
174  * GetLatestSnapshot
175  *              Get a snapshot that is up-to-date as of the current instant,
176  *              even if we are executing in SERIALIZABLE mode.
177  */
178 Snapshot
179 GetLatestSnapshot(void)
180 {
181         /* Should not be first call in transaction */
182         if (!FirstSnapshotSet)
183                 elog(ERROR, "no snapshot has been set");
184
185         SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);
186
187         return SecondarySnapshot;
188 }
189
190 /*
191  * SnapshotSetCommandId
192  *              Propagate CommandCounterIncrement into the static snapshots, if set
193  */
194 void
195 SnapshotSetCommandId(CommandId curcid)
196 {
197         if (!FirstSnapshotSet)
198                 return;
199
200         if (CurrentSnapshot)
201                 CurrentSnapshot->curcid = curcid;
202         if (SecondarySnapshot)
203                 SecondarySnapshot->curcid = curcid;
204 }
205
206 /*
207  * CopySnapshot
208  *              Copy the given snapshot.
209  *
210  * The copy is palloc'd in TopTransactionContext and has initial refcounts set
211  * to 0.  The returned snapshot has the copied flag set.
212  */
213 static Snapshot
214 CopySnapshot(Snapshot snapshot)
215 {
216         Snapshot        newsnap;
217         Size            subxipoff;
218         Size            size;
219
220         Assert(snapshot != InvalidSnapshot);
221
222         /* We allocate any XID arrays needed in the same palloc block. */
223         size = subxipoff = sizeof(SnapshotData) +
224                 snapshot->xcnt * sizeof(TransactionId);
225         if (snapshot->subxcnt > 0)
226                 size += snapshot->subxcnt * sizeof(TransactionId);
227
228         newsnap = (Snapshot) MemoryContextAlloc(TopTransactionContext, size);
229         memcpy(newsnap, snapshot, sizeof(SnapshotData));
230
231         newsnap->regd_count = 0;
232         newsnap->active_count = 0;
233         newsnap->copied = true;
234
235         /* setup XID array */
236         if (snapshot->xcnt > 0)
237         {
238                 newsnap->xip = (TransactionId *) (newsnap + 1);
239                 memcpy(newsnap->xip, snapshot->xip,
240                            snapshot->xcnt * sizeof(TransactionId));
241         }
242         else
243                 newsnap->xip = NULL;
244
245         /* setup subXID array */
246         if (snapshot->subxcnt > 0)
247         {
248                 newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
249                 memcpy(newsnap->subxip, snapshot->subxip,
250                            snapshot->subxcnt * sizeof(TransactionId));
251         }
252         else
253                 newsnap->subxip = NULL;
254
255         return newsnap;
256 }
257
258 /*
259  * FreeSnapshot
260  *              Free the memory associated with a snapshot.
261  */
262 static void
263 FreeSnapshot(Snapshot snapshot)
264 {
265         Assert(snapshot->regd_count == 0);
266         Assert(snapshot->active_count == 0);
267         Assert(snapshot->copied);
268
269         pfree(snapshot);
270 }
271
272 /*
273  * PushActiveSnapshot
274  *              Set the given snapshot as the current active snapshot
275  *
276  * If this is the first use of this snapshot, create a new long-lived copy with
277  * active refcount=1.  Otherwise, only increment the refcount.
278  */
279 void
280 PushActiveSnapshot(Snapshot snap)
281 {
282         ActiveSnapshotElt       *newactive;
283
284         Assert(snap != InvalidSnapshot);
285
286         newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
287         /* Static snapshot?  Create a persistent copy */
288         newactive->as_snap = snap->copied ? snap : CopySnapshot(snap);
289         newactive->as_next = ActiveSnapshot;
290         newactive->as_level = GetCurrentTransactionNestLevel();
291
292         newactive->as_snap->active_count++;
293
294         ActiveSnapshot = newactive;
295 }
296
297 /*
298  * PushUpdatedSnapshot
299  *              As above, except we set the snapshot's CID to the current CID.
300  */
301 void
302 PushUpdatedSnapshot(Snapshot snapshot)
303 {
304         Snapshot        newsnap;
305
306         /*
307          * We cannot risk modifying a snapshot that's possibly already used
308          * elsewhere, so make a new copy to scribble on.
309          */
310         newsnap = CopySnapshot(snapshot);
311         newsnap->curcid = GetCurrentCommandId(false);
312
313         PushActiveSnapshot(newsnap);
314 }
315
316 /*
317  * PopActiveSnapshot
318  *
319  * Remove the topmost snapshot from the active snapshot stack, decrementing the
320  * reference count, and free it if this was the last reference.
321  */
322 void
323 PopActiveSnapshot(void)
324 {
325         ActiveSnapshotElt       *newstack;
326
327         newstack = ActiveSnapshot->as_next;
328
329         Assert(ActiveSnapshot->as_snap->active_count > 0);
330
331         ActiveSnapshot->as_snap->active_count--;
332
333         if (ActiveSnapshot->as_snap->active_count == 0 &&
334                 ActiveSnapshot->as_snap->regd_count == 0)
335                 FreeSnapshot(ActiveSnapshot->as_snap);
336
337         pfree(ActiveSnapshot);
338         ActiveSnapshot = newstack;
339
340         SnapshotResetXmin();
341 }
342
343 /*
344  * GetActiveSnapshot
345  *              Return the topmost snapshot in the Active stack.
346  */
347 Snapshot
348 GetActiveSnapshot(void)
349 {
350         Assert(ActiveSnapshot != NULL);
351
352         return ActiveSnapshot->as_snap;
353 }
354
355 /*
356  * ActiveSnapshotSet
357  *              Return whether there is at least one snapshot in the Active stack
358  */
359 bool
360 ActiveSnapshotSet(void)
361 {
362         return ActiveSnapshot != NULL;
363 }
364
365 /*
366  * RegisterSnapshot
367  *              Register a snapshot as being in use
368  *
369  * If InvalidSnapshot is passed, it is not registered.
370  */
371 Snapshot
372 RegisterSnapshot(Snapshot snapshot)
373 {
374         RegdSnapshotElt *elt;
375         RegdSnapshotElt *newhead;
376         int             level;
377
378         if (snapshot == InvalidSnapshot)
379                 return InvalidSnapshot;
380
381         level = GetCurrentTransactionNestLevel();
382
383         /*
384          * If there's already an item in the list for the same snapshot and the
385          * same subxact nest level, increment its refcounts.  Otherwise create a
386          * new one.
387          */
388         for (elt = RegisteredSnapshotList; elt != NULL; elt = elt->s_next)
389         {
390                 if (elt->s_level < level)
391                         break;
392
393                 if (elt->s_snap == snapshot && elt->s_level == level)
394                 {
395                         elt->s_snap->regd_count++;
396                         elt->s_count++;
397
398                         return elt->s_snap;
399                 }
400         }
401
402         /*
403          * Create the new list element.  If it's not been copied into persistent
404          * memory already, we must do so; otherwise we can just increment the
405          * reference count.
406          */
407         newhead = MemoryContextAlloc(TopTransactionContext, sizeof(RegdSnapshotElt));
408         newhead->s_next = RegisteredSnapshotList;
409         /* Static snapshot?  Create a persistent copy */
410         newhead->s_snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
411         newhead->s_level = level;
412         newhead->s_count = 1;
413
414         newhead->s_snap->regd_count++;
415
416         RegisteredSnapshotList = newhead;
417
418         return RegisteredSnapshotList->s_snap;
419 }
420
421 /*
422  * UnregisterSnapshot
423  *              Signals that a snapshot is no longer necessary
424  *
425  * If both reference counts fall to zero, the snapshot memory is released.
426  * If only the registered list refcount falls to zero, just the list element is
427  * freed.
428  */
429 void
430 UnregisterSnapshot(Snapshot snapshot)
431 {
432         RegdSnapshotElt *prev = NULL;
433         RegdSnapshotElt *elt;
434         bool            found = false;
435
436         if (snapshot == InvalidSnapshot)
437                 return;
438
439         for (elt = RegisteredSnapshotList; elt != NULL; elt = elt->s_next)
440         {
441                 if (elt->s_snap == snapshot)
442                 {
443                         Assert(elt->s_snap->regd_count > 0);
444                         Assert(elt->s_count > 0);
445
446                         elt->s_snap->regd_count--;
447                         elt->s_count--;
448                         found = true;
449
450                         if (elt->s_count == 0)
451                         {
452                                 /* delink it from the registered snapshot list */
453                                 if (prev)
454                                         prev->s_next = elt->s_next;
455                                 else
456                                         RegisteredSnapshotList = elt->s_next;
457
458                                 /* free the snapshot itself if it's no longer relevant */
459                                 if (elt->s_snap->regd_count == 0 && elt->s_snap->active_count == 0)
460                                         FreeSnapshot(elt->s_snap);
461
462                                 /* and free the list element */
463                                 pfree(elt);
464                         }
465
466                         break;
467                 }
468
469                 prev = elt;
470         }
471
472         if (!found)
473                 elog(WARNING, "unregistering failed for snapshot %p", snapshot);
474
475         SnapshotResetXmin();
476 }
477
478 /*
479  * SnapshotResetXmin
480  *
481  * If there are no more snapshots, we can reset our PGPROC->xmin to InvalidXid.
482  * Note we can do this without locking because we assume that storing an Xid
483  * is atomic.
484  */
485 static void
486 SnapshotResetXmin(void)
487 {
488         if (RegisteredSnapshotList == NULL && ActiveSnapshot == NULL)
489                 MyProc->xmin = InvalidTransactionId;
490 }
491
492 /*
493  * AtSubCommit_Snapshot
494  */
495 void
496 AtSubCommit_Snapshot(int level)
497 {
498         ActiveSnapshotElt       *active;
499         RegdSnapshotElt *regd;
500
501         /*
502          * Relabel the active snapshots set in this subtransaction as though they
503          * are owned by the parent subxact.
504          */
505         for (active = ActiveSnapshot; active != NULL; active = active->as_next)
506         {
507                 if (active->as_level < level)
508                         break;
509                 active->as_level = level - 1;
510         }
511
512         /*
513          * Reassign all registered snapshots to the parent subxact.
514          *
515          * Note: this code is somewhat bogus in that we could end up with multiple
516          * entries for the same snapshot and the same subxact level (my parent's
517          * level).  Cleaning that up is more trouble than it's currently worth,
518          * however.
519          */
520         for (regd = RegisteredSnapshotList; regd != NULL; regd = regd->s_next)
521         {
522                 if (regd->s_level == level)
523                         regd->s_level--;
524         }
525 }
526
527 /*
528  * AtSubAbort_Snapshot
529  *              Clean up snapshots after a subtransaction abort
530  */
531 void
532 AtSubAbort_Snapshot(int level)
533 {
534         RegdSnapshotElt *prev;
535         RegdSnapshotElt *regd;
536
537         /* Forget the active snapshots set by this subtransaction */
538         while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
539         {
540                 ActiveSnapshotElt       *next;
541
542                 next = ActiveSnapshot->as_next;
543
544                 /*
545                  * Decrement the snapshot's active count.  If it's still registered or
546                  * marked as active by an outer subtransaction, we can't free it yet.
547                  */
548                 Assert(ActiveSnapshot->as_snap->active_count >= 1);
549                 ActiveSnapshot->as_snap->active_count -= 1;
550
551                 if (ActiveSnapshot->as_snap->active_count == 0 &&
552                         ActiveSnapshot->as_snap->regd_count == 0)
553                         FreeSnapshot(ActiveSnapshot->as_snap);
554
555                 /* and free the stack element */
556                 pfree(ActiveSnapshot);
557
558                 ActiveSnapshot = next;
559         }
560
561         /* Unregister all snapshots registered during this subtransaction */
562         prev = NULL;
563         for (regd = RegisteredSnapshotList; regd != NULL; )
564         {
565                 if (regd->s_level >= level)
566                 {
567                         RegdSnapshotElt *tofree;
568
569                         if (prev)
570                                 prev->s_next = regd->s_next;
571                         else
572                                 RegisteredSnapshotList = regd->s_next;
573
574                         tofree = regd;
575                         regd = regd->s_next;
576
577                         tofree->s_snap->regd_count -= tofree->s_count;
578
579                         /* free the snapshot if possible */
580                         if (tofree->s_snap->regd_count == 0 &&
581                                 tofree->s_snap->active_count == 0)
582                                 FreeSnapshot(tofree->s_snap);
583
584                         /* and free the list element */
585                         pfree(tofree);
586                 }
587                 else
588                 {
589                         prev = regd;
590                         regd = regd->s_next;
591                 }
592         }
593
594         SnapshotResetXmin();
595 }
596
597 /*
598  * AtEOXact_Snapshot
599  *              Snapshot manager's cleanup function for end of transaction
600  */
601 void
602 AtEOXact_Snapshot(bool isCommit)
603 {
604         /* On commit, complain about leftover snapshots */
605         if (isCommit)
606         {
607                 ActiveSnapshotElt       *active;
608                 RegdSnapshotElt *regd;
609
610                 /*
611                  * On a serializable snapshot we must first unregister our private
612                  * refcount to the serializable snapshot.
613                  */
614                 if (registered_serializable)
615                         UnregisterSnapshot(CurrentSnapshot);
616
617                 /* complain about unpopped active snapshots */
618                 for (active = ActiveSnapshot; active != NULL; active = active->as_next)
619                 {
620                         ereport(WARNING,
621                                         (errmsg("snapshot %p still active", active)));
622                 }
623
624                 /* complain about any unregistered snapshot */
625                 for (regd = RegisteredSnapshotList; regd != NULL; regd = regd->s_next)
626                 {
627                         ereport(WARNING,
628                                         (errmsg("snapshot %p not destroyed at commit (%d regd refs, %d active refs)",
629                                                         regd->s_snap, regd->s_snap->regd_count,
630                                                         regd->s_snap->active_count)));
631                 }
632         }
633
634         /*
635          * And reset our state.  We don't need to free the memory explicitly --
636          * it'll go away with TopTransactionContext.
637          */
638         ActiveSnapshot = NULL;
639         RegisteredSnapshotList = NULL;
640
641         CurrentSnapshot = NULL;
642         SecondarySnapshot = NULL;
643
644         FirstSnapshotSet = false;
645         registered_serializable = false;
646 }