snapmgr.c 15.6 KB
Newer Older
1
/*-------------------------------------------------------------------------
2 3
 * snapmgr.c
 *		PostgreSQL snapshot manager
4
 *
5
 * We keep track of snapshots in two ways: those "registered" by resowner.c,
6 7 8
 * and the "active snapshot" stack.  All snapshots in either of them live in
 * persistent memory.  When a snapshot is no longer in any of these lists
 * (tracked by separate refcounts on each snapshot), its memory can be freed.
9
 *
10 11 12 13 14 15 16 17
 * The FirstXactSnapshot, if any, is treated a bit specially: we increment its
 * regd_count and count it in RegisteredSnapshots, but this reference is not
 * tracked by a resource owner. We used to use the TopTransactionResourceOwner
 * to track this snapshot reference, but that introduces logical circularity
 * and thus makes it impossible to clean up in a sane fashion.  It's better to
 * handle this reference as an internally-tracked registration, so that this
 * module is entirely lower-level than ResourceOwners.
 *
18
 * These arrangements let us reset MyProc->xmin when there are no snapshots
19
 * referenced by this transaction.	(One possible improvement would be to be
20
 * able to advance Xmin when the snapshot with the earliest Xmin is no longer
21
 * referenced.	That's a bit harder though, it requires more locking, and
22 23 24 25
 * anyway it should be rather uncommon to keep snapshots referenced for too
 * long.)
 *
 *
B
Bruce Momjian 已提交
26
 * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
27 28 29
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
30
 *	  src/backend/utils/time/snapmgr.c
31 32 33 34 35 36
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/transam.h"
37
#include "access/xact.h"
38
#include "storage/predicate.h"
T
Tom Lane 已提交
39
#include "storage/proc.h"
40
#include "storage/procarray.h"
41
#include "utils/memutils.h"
42
#include "utils/memutils.h"
43
#include "utils/snapmgr.h"
44 45 46 47
#include "utils/tqual.h"


/*
48 49
 * CurrentSnapshot points to the only snapshot taken in transaction-snapshot
 * mode, and to the latest one taken in a read-committed transaction.
50
 * SecondarySnapshot is a snapshot that's always up-to-date as of the current
51
 * instant, even in transaction-snapshot mode.	It should only be used for
52 53
 * special-purpose code (say, RI checking.)
 *
54 55 56
 * These SnapshotData structs are static to simplify memory allocation
 * (see the hack in GetSnapshotData to avoid repeated malloc/free).
 */
57 58
static SnapshotData CurrentSnapshotData = {HeapTupleSatisfiesMVCC};
static SnapshotData SecondarySnapshotData = {HeapTupleSatisfiesMVCC};
59

60
/* Pointers to valid snapshots */
61 62
static Snapshot CurrentSnapshot = NULL;
static Snapshot SecondarySnapshot = NULL;
63 64 65 66 67

/*
 * These are updated by GetSnapshotData.  We initialize them this way
 * for the convenience of TransactionIdIsInProgress: even in bootstrap
 * mode, we don't want it to say that BootstrapTransactionId is in progress.
68 69
 *
 * RecentGlobalXmin is initialized to InvalidTransactionId, to ensure that no
70
 * one tries to use a stale value.	Readers should ensure that it has been set
71
 * to something else before using it.
72 73 74
 */
TransactionId TransactionXmin = FirstNormalTransactionId;
TransactionId RecentXmin = FirstNormalTransactionId;
75
TransactionId RecentGlobalXmin = InvalidTransactionId;
76

77 78 79
/*
 * Elements of the active snapshot stack.
 *
80
 * Each element here accounts for exactly one active_count on SnapshotData.
81 82 83 84 85 86 87 88 89 90 91 92
 *
 * NB: the code assumes that elements in this list are in non-increasing
 * order of as_level; also, the list must be NULL-terminated.
 */
typedef struct ActiveSnapshotElt
{
	Snapshot	as_snap;
	int			as_level;
	struct ActiveSnapshotElt *as_next;
} ActiveSnapshotElt;

/* Top of the stack of active snapshots */
93
static ActiveSnapshotElt *ActiveSnapshot = NULL;
94

95 96 97 98 99 100 101
/*
 * How many snapshots is resowner.c tracking for us?
 *
 * Note: for now, a simple counter is enough.  However, if we ever want to be
 * smarter about advancing our MyProc->xmin we will need to be more
 * sophisticated about this, perhaps keeping our own list of snapshots.
 */
102
static int	RegisteredSnapshots = 0;
103

104
/* first GetTransactionSnapshot call in a transaction? */
105
bool		FirstSnapshotSet = false;
106 107

/*
108 109 110
 * Remember the serializable transaction snapshot, if any.  We cannot trust
 * FirstSnapshotSet in combination with IsolationUsesXactSnapshot(), because
 * GUC may be reset before us, changing the value of IsolationUsesXactSnapshot.
111
 */
112
static Snapshot FirstXactSnapshot = NULL;
113 114


115
static Snapshot CopySnapshot(Snapshot snapshot);
116
static void FreeSnapshot(Snapshot snapshot);
117
static void SnapshotResetXmin(void);
118

119 120 121 122 123

/*
 * GetTransactionSnapshot
 *		Get the appropriate snapshot for a new query in a transaction.
 *
124 125 126 127
 * Note that the return value may point at static storage that will be modified
 * by future calls and by CommandCounterIncrement().  Callers should call
 * RegisterSnapshot or PushActiveSnapshot on the returned snap if it is to be
 * used very long.
128 129 130 131 132
 */
Snapshot
GetTransactionSnapshot(void)
{
	/* First call in transaction? */
133
	if (!FirstSnapshotSet)
134
	{
135
		Assert(RegisteredSnapshots == 0);
136
		Assert(FirstXactSnapshot == NULL);
137

138
		/*
139 140
		 * In transaction-snapshot mode, the first snapshot must live until
		 * end of xact regardless of what the caller does with it, so we must
141 142
		 * make a copy of it rather than returning CurrentSnapshotData
		 * directly.
143
		 */
144
		if (IsolationUsesXactSnapshot())
145
		{
146
			/* First, create the snapshot in CurrentSnapshotData */
147
			if (IsolationIsSerializable())
148
				CurrentSnapshot = GetSerializableTransactionSnapshot(&CurrentSnapshotData);
149 150
			else
				CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
151 152 153 154 155 156
			/* Make a saved copy */
			CurrentSnapshot = CopySnapshot(CurrentSnapshot);
			FirstXactSnapshot = CurrentSnapshot;
			/* Mark it as "registered" in FirstXactSnapshot */
			FirstXactSnapshot->regd_count++;
			RegisteredSnapshots++;
157
		}
158 159
		else
			CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
160

161
		FirstSnapshotSet = true;
162
		return CurrentSnapshot;
163 164
	}

165
	if (IsolationUsesXactSnapshot())
166
		return CurrentSnapshot;
167

168
	CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
169

170
	return CurrentSnapshot;
171 172 173 174 175
}

/*
 * GetLatestSnapshot
 *		Get a snapshot that is up-to-date as of the current instant,
176
 *		even if we are executing in transaction-snapshot mode.
177 178 179 180 181
 */
Snapshot
GetLatestSnapshot(void)
{
	/* Should not be first call in transaction */
182
	if (!FirstSnapshotSet)
183 184
		elog(ERROR, "no snapshot has been set");

185
	SecondarySnapshot = GetSnapshotData(&SecondarySnapshotData);
186

187 188 189 190 191
	return SecondarySnapshot;
}

/*
 * SnapshotSetCommandId
192
 *		Propagate CommandCounterIncrement into the static snapshots, if set
193 194 195 196 197 198 199 200 201 202 203
 */
void
SnapshotSetCommandId(CommandId curcid)
{
	if (!FirstSnapshotSet)
		return;

	if (CurrentSnapshot)
		CurrentSnapshot->curcid = curcid;
	if (SecondarySnapshot)
		SecondarySnapshot->curcid = curcid;
204 205 206 207 208 209
}

/*
 * CopySnapshot
 *		Copy the given snapshot.
 *
210 211
 * The copy is palloc'd in TopTransactionContext and has initial refcounts set
 * to 0.  The returned snapshot has the copied flag set.
212
 */
213
static Snapshot
214 215 216 217 218 219
CopySnapshot(Snapshot snapshot)
{
	Snapshot	newsnap;
	Size		subxipoff;
	Size		size;

220 221
	Assert(snapshot != InvalidSnapshot);

222 223 224 225 226 227
	/* We allocate any XID arrays needed in the same palloc block. */
	size = subxipoff = sizeof(SnapshotData) +
		snapshot->xcnt * sizeof(TransactionId);
	if (snapshot->subxcnt > 0)
		size += snapshot->subxcnt * sizeof(TransactionId);

228
	newsnap = (Snapshot) MemoryContextAlloc(TopTransactionContext, size);
229 230
	memcpy(newsnap, snapshot, sizeof(SnapshotData));

231 232 233 234
	newsnap->regd_count = 0;
	newsnap->active_count = 0;
	newsnap->copied = true;

235 236 237 238 239 240 241 242 243 244
	/* setup XID array */
	if (snapshot->xcnt > 0)
	{
		newsnap->xip = (TransactionId *) (newsnap + 1);
		memcpy(newsnap->xip, snapshot->xip,
			   snapshot->xcnt * sizeof(TransactionId));
	}
	else
		newsnap->xip = NULL;

245 246
	/*
	 * Setup subXID array. Don't bother to copy it if it had overflowed,
B
Bruce Momjian 已提交
247 248 249
	 * though, because it's not used anywhere in that case. Except if it's a
	 * snapshot taken during recovery; all the top-level XIDs are in subxip as
	 * well in that case, so we mustn't lose them.
250 251 252
	 */
	if (snapshot->subxcnt > 0 &&
		(!snapshot->suboverflowed || snapshot->takenDuringRecovery))
253 254 255 256 257 258 259 260 261 262 263 264 265
	{
		newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff);
		memcpy(newsnap->subxip, snapshot->subxip,
			   snapshot->subxcnt * sizeof(TransactionId));
	}
	else
		newsnap->subxip = NULL;

	return newsnap;
}

/*
 * FreeSnapshot
266 267 268 269 270 271 272
 *		Free the memory associated with a snapshot.
 */
static void
FreeSnapshot(Snapshot snapshot)
{
	Assert(snapshot->regd_count == 0);
	Assert(snapshot->active_count == 0);
273
	Assert(snapshot->copied);
274 275 276 277 278 279

	pfree(snapshot);
}

/*
 * PushActiveSnapshot
280
 *		Set the given snapshot as the current active snapshot
281
 *
282 283
 * If the passed snapshot is a statically-allocated one, or it is possibly
 * subject to a future command counter update, create a new long-lived copy
B
Bruce Momjian 已提交
284
 * with active refcount=1.	Otherwise, only increment the refcount.
285 286 287 288
 */
void
PushActiveSnapshot(Snapshot snap)
{
289
	ActiveSnapshotElt *newactive;
290 291 292 293

	Assert(snap != InvalidSnapshot);

	newactive = MemoryContextAlloc(TopTransactionContext, sizeof(ActiveSnapshotElt));
294 295

	/*
B
Bruce Momjian 已提交
296 297
	 * Checking SecondarySnapshot is probably useless here, but it seems
	 * better to be sure.
298 299 300 301 302 303
	 */
	if (snap == CurrentSnapshot || snap == SecondarySnapshot || !snap->copied)
		newactive->as_snap = CopySnapshot(snap);
	else
		newactive->as_snap = snap;

304 305 306 307 308 309 310 311 312
	newactive->as_next = ActiveSnapshot;
	newactive->as_level = GetCurrentTransactionNestLevel();

	newactive->as_snap->active_count++;

	ActiveSnapshot = newactive;
}

/*
313 314 315 316 317 318
 * PushCopiedSnapshot
 *		As above, except forcibly copy the presented snapshot.
 *
 * This should be used when the ActiveSnapshot has to be modifiable, for
 * example if the caller intends to call UpdateActiveSnapshotCommandId.
 * The new snapshot will be released when popped from the stack.
319 320
 */
void
321
PushCopiedSnapshot(Snapshot snapshot)
322
{
323 324
	PushActiveSnapshot(CopySnapshot(snapshot));
}
325

326 327 328 329 330 331 332 333 334 335 336 337
/*
 * UpdateActiveSnapshotCommandId
 *
 * Update the current CID of the active snapshot.  This can only be applied
 * to a snapshot that is not referenced elsewhere.
 */
void
UpdateActiveSnapshotCommandId(void)
{
	Assert(ActiveSnapshot != NULL);
	Assert(ActiveSnapshot->as_snap->active_count == 1);
	Assert(ActiveSnapshot->as_snap->regd_count == 0);
338

339
	ActiveSnapshot->as_snap->curcid = GetCurrentCommandId(false);
340 341 342 343
}

/*
 * PopActiveSnapshot
344
 *
345 346
 * Remove the topmost snapshot from the active snapshot stack, decrementing the
 * reference count, and free it if this was the last reference.
347 348
 */
void
349
PopActiveSnapshot(void)
350
{
351
	ActiveSnapshotElt *newstack;
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

	newstack = ActiveSnapshot->as_next;

	Assert(ActiveSnapshot->as_snap->active_count > 0);

	ActiveSnapshot->as_snap->active_count--;

	if (ActiveSnapshot->as_snap->active_count == 0 &&
		ActiveSnapshot->as_snap->regd_count == 0)
		FreeSnapshot(ActiveSnapshot->as_snap);

	pfree(ActiveSnapshot);
	ActiveSnapshot = newstack;

	SnapshotResetXmin();
367 368 369
}

/*
370
 * GetActiveSnapshot
371
 *		Return the topmost snapshot in the Active stack.
372 373 374 375 376 377 378 379 380 381 382
 */
Snapshot
GetActiveSnapshot(void)
{
	Assert(ActiveSnapshot != NULL);

	return ActiveSnapshot->as_snap;
}

/*
 * ActiveSnapshotSet
383
 *		Return whether there is at least one snapshot in the Active stack
384 385 386 387 388 389 390 391 392
 */
bool
ActiveSnapshotSet(void)
{
	return ActiveSnapshot != NULL;
}

/*
 * RegisterSnapshot
393
 *		Register a snapshot as being in use by the current resource owner
394 395 396 397 398 399
 *
 * If InvalidSnapshot is passed, it is not registered.
 */
Snapshot
RegisterSnapshot(Snapshot snapshot)
{
400 401 402 403 404 405 406 407
	if (snapshot == InvalidSnapshot)
		return InvalidSnapshot;

	return RegisterSnapshotOnOwner(snapshot, CurrentResourceOwner);
}

/*
 * RegisterSnapshotOnOwner
408
 *		As above, but use the specified resource owner
409 410 411 412
 */
Snapshot
RegisterSnapshotOnOwner(Snapshot snapshot, ResourceOwner owner)
{
413
	Snapshot	snap;
414 415 416 417 418

	if (snapshot == InvalidSnapshot)
		return InvalidSnapshot;

	/* Static snapshot?  Create a persistent copy */
419
	snap = snapshot->copied ? snapshot : CopySnapshot(snapshot);
420

421
	/* and tell resowner.c about it */
422
	ResourceOwnerEnlargeSnapshots(owner);
423
	snap->regd_count++;
424
	ResourceOwnerRememberSnapshot(owner, snap);
425

426
	RegisteredSnapshots++;
427

428
	return snap;
429 430 431 432 433
}

/*
 * UnregisterSnapshot
 *
434 435 436
 * Decrement the reference count of a snapshot, remove the corresponding
 * reference from CurrentResourceOwner, and free the snapshot if no more
 * references remain.
437 438 439
 */
void
UnregisterSnapshot(Snapshot snapshot)
440 441 442 443 444 445 446 447 448
{
	if (snapshot == NULL)
		return;

	UnregisterSnapshotFromOwner(snapshot, CurrentResourceOwner);
}

/*
 * UnregisterSnapshotFromOwner
449
 *		As above, but use the specified resource owner
450 451 452
 */
void
UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
453
{
454
	if (snapshot == NULL)
455 456
		return;

457 458
	Assert(snapshot->regd_count > 0);
	Assert(RegisteredSnapshots > 0);
459

460
	ResourceOwnerForgetSnapshot(owner, snapshot);
461 462 463 464 465
	RegisteredSnapshots--;
	if (--snapshot->regd_count == 0 && snapshot->active_count == 0)
	{
		FreeSnapshot(snapshot);
		SnapshotResetXmin();
466 467 468 469 470 471 472 473 474 475 476 477 478
	}
}

/*
 * SnapshotResetXmin
 *
 * If there are no more snapshots, we can reset our PGPROC->xmin to InvalidXid.
 * Note we can do this without locking because we assume that storing an Xid
 * is atomic.
 */
static void
SnapshotResetXmin(void)
{
479
	if (RegisteredSnapshots == 0 && ActiveSnapshot == NULL)
480 481 482 483 484
		MyProc->xmin = InvalidTransactionId;
}

/*
 * AtSubCommit_Snapshot
485 486
 */
void
487
AtSubCommit_Snapshot(int level)
488
{
489
	ActiveSnapshotElt *active;
490

491
	/*
492 493
	 * Relabel the active snapshots set in this subtransaction as though they
	 * are owned by the parent subxact.
494
	 */
495 496 497 498 499 500 501 502 503 504
	for (active = ActiveSnapshot; active != NULL; active = active->as_next)
	{
		if (active->as_level < level)
			break;
		active->as_level = level - 1;
	}
}

/*
 * AtSubAbort_Snapshot
505
 *		Clean up snapshots after a subtransaction abort
506 507 508 509 510 511 512
 */
void
AtSubAbort_Snapshot(int level)
{
	/* Forget the active snapshots set by this subtransaction */
	while (ActiveSnapshot && ActiveSnapshot->as_level >= level)
	{
513
		ActiveSnapshotElt *next;
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538

		next = ActiveSnapshot->as_next;

		/*
		 * Decrement the snapshot's active count.  If it's still registered or
		 * marked as active by an outer subtransaction, we can't free it yet.
		 */
		Assert(ActiveSnapshot->as_snap->active_count >= 1);
		ActiveSnapshot->as_snap->active_count -= 1;

		if (ActiveSnapshot->as_snap->active_count == 0 &&
			ActiveSnapshot->as_snap->regd_count == 0)
			FreeSnapshot(ActiveSnapshot->as_snap);

		/* and free the stack element */
		pfree(ActiveSnapshot);

		ActiveSnapshot = next;
	}

	SnapshotResetXmin();
}

/*
 * AtEOXact_Snapshot
539
 *		Snapshot manager's cleanup function for end of transaction
540 541 542 543
 */
void
AtEOXact_Snapshot(bool isCommit)
{
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
	/*
	 * In transaction-snapshot mode we must release our privately-managed
	 * reference to the transaction snapshot.  We must decrement
	 * RegisteredSnapshots to keep the check below happy.  But we don't bother
	 * to do FreeSnapshot, for two reasons: the memory will go away with
	 * TopTransactionContext anyway, and if someone has left the snapshot
	 * stacked as active, we don't want the code below to be chasing through
	 * a dangling pointer.
	 */
	if (FirstXactSnapshot != NULL)
	{
		Assert(FirstXactSnapshot->regd_count > 0);
		Assert(RegisteredSnapshots > 0);
		RegisteredSnapshots--;
	}
	FirstXactSnapshot = NULL;

561 562 563
	/* On commit, complain about leftover snapshots */
	if (isCommit)
	{
564
		ActiveSnapshotElt *active;
565

566 567 568 569
		if (RegisteredSnapshots != 0)
			elog(WARNING, "%d registered snapshots seem to remain after cleanup",
				 RegisteredSnapshots);

570 571
		/* complain about unpopped active snapshots */
		for (active = ActiveSnapshot; active != NULL; active = active->as_next)
572
			elog(WARNING, "snapshot %p still active", active);
573 574 575
	}

	/*
576
	 * And reset our state.  We don't need to free the memory explicitly --
577 578 579
	 * it'll go away with TopTransactionContext.
	 */
	ActiveSnapshot = NULL;
580
	RegisteredSnapshots = 0;
581 582 583 584 585

	CurrentSnapshot = NULL;
	SecondarySnapshot = NULL;

	FirstSnapshotSet = false;
586 587

	SnapshotResetXmin();
588
}