1 /*-------------------------------------------------------------------------
2  *
3  * transam.c
4  *	  postgres transaction (commit) log interface routines
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/access/transam/transam.c
12  *
13  * NOTES
14  *	  This file contains the high level access-method interface to the
15  *	  transaction system.
16  *
17  *-------------------------------------------------------------------------
18  */
19 
20 #include "postgres.h"
21 
22 #include "access/clog.h"
23 #include "access/subtrans.h"
24 #include "access/transam.h"
25 #include "utils/snapmgr.h"
26 
27 /*
28  * Single-item cache for results of TransactionLogFetch.  It's worth having
29  * such a cache because we frequently find ourselves repeatedly checking the
30  * same XID, for example when scanning a table just after a bulk insert,
31  * update, or delete.
32  */
33 static TransactionId cachedFetchXid = InvalidTransactionId;
34 static XidStatus cachedFetchXidStatus;
35 static XLogRecPtr cachedCommitLSN;
36 
37 /* Local functions */
38 static XidStatus TransactionLogFetch(TransactionId transactionId);
39 
40 
41 /* ----------------------------------------------------------------
42  *		Postgres log access method interface
43  *
44  *		TransactionLogFetch
45  * ----------------------------------------------------------------
46  */
47 
48 /*
49  * TransactionLogFetch --- fetch commit status of specified transaction id
50  */
51 static XidStatus
TransactionLogFetch(TransactionId transactionId)52 TransactionLogFetch(TransactionId transactionId)
53 {
54 	XidStatus	xidstatus;
55 	XLogRecPtr	xidlsn;
56 
57 	/*
58 	 * Before going to the commit log manager, check our single item cache to
59 	 * see if we didn't just check the transaction status a moment ago.
60 	 */
61 	if (TransactionIdEquals(transactionId, cachedFetchXid))
62 		return cachedFetchXidStatus;
63 
64 	/*
65 	 * Also, check to see if the transaction ID is a permanent one.
66 	 */
67 	if (!TransactionIdIsNormal(transactionId))
68 	{
69 		if (TransactionIdEquals(transactionId, BootstrapTransactionId))
70 			return TRANSACTION_STATUS_COMMITTED;
71 		if (TransactionIdEquals(transactionId, FrozenTransactionId))
72 			return TRANSACTION_STATUS_COMMITTED;
73 		return TRANSACTION_STATUS_ABORTED;
74 	}
75 
76 	/*
77 	 * Get the transaction status.
78 	 */
79 	xidstatus = TransactionIdGetStatus(transactionId, &xidlsn);
80 
81 	/*
82 	 * Cache it, but DO NOT cache status for unfinished or sub-committed
83 	 * transactions!  We only cache status that is guaranteed not to change.
84 	 */
85 	if (xidstatus != TRANSACTION_STATUS_IN_PROGRESS &&
86 		xidstatus != TRANSACTION_STATUS_SUB_COMMITTED)
87 	{
88 		cachedFetchXid = transactionId;
89 		cachedFetchXidStatus = xidstatus;
90 		cachedCommitLSN = xidlsn;
91 	}
92 
93 	return xidstatus;
94 }
95 
96 /* ----------------------------------------------------------------
97  *						Interface functions
98  *
99  *		TransactionIdDidCommit
100  *		TransactionIdDidAbort
101  *		========
102  *		   these functions test the transaction status of
103  *		   a specified transaction id.
104  *
105  *		TransactionIdCommitTree
106  *		TransactionIdAsyncCommitTree
107  *		TransactionIdAbortTree
108  *		========
109  *		   these functions set the transaction status of the specified
110  *		   transaction tree.
111  *
112  * See also TransactionIdIsInProgress, which once was in this module
113  * but now lives in procarray.c.
114  * ----------------------------------------------------------------
115  */
116 
117 /*
118  * TransactionIdDidCommit
119  *		True iff transaction associated with the identifier did commit.
120  *
121  * Note:
122  *		Assumes transaction identifier is valid and exists in clog.
123  */
124 bool							/* true if given transaction committed */
TransactionIdDidCommit(TransactionId transactionId)125 TransactionIdDidCommit(TransactionId transactionId)
126 {
127 	XidStatus	xidstatus;
128 
129 	xidstatus = TransactionLogFetch(transactionId);
130 
131 	/*
132 	 * If it's marked committed, it's committed.
133 	 */
134 	if (xidstatus == TRANSACTION_STATUS_COMMITTED)
135 		return true;
136 
137 	/*
138 	 * If it's marked subcommitted, we have to check the parent recursively.
139 	 * However, if it's older than TransactionXmin, we can't look at
140 	 * pg_subtrans; instead assume that the parent crashed without cleaning up
141 	 * its children.
142 	 *
143 	 * Originally we Assert'ed that the result of SubTransGetParent was not
144 	 * zero. However with the introduction of prepared transactions, there can
145 	 * be a window just after database startup where we do not have complete
146 	 * knowledge in pg_subtrans of the transactions after TransactionXmin.
147 	 * StartupSUBTRANS() has ensured that any missing information will be
148 	 * zeroed.  Since this case should not happen under normal conditions, it
149 	 * seems reasonable to emit a WARNING for it.
150 	 */
151 	if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
152 	{
153 		TransactionId parentXid;
154 
155 		if (TransactionIdPrecedes(transactionId, TransactionXmin))
156 			return false;
157 		parentXid = SubTransGetParent(transactionId);
158 		if (!TransactionIdIsValid(parentXid))
159 		{
160 			elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
161 				 transactionId);
162 			return false;
163 		}
164 		return TransactionIdDidCommit(parentXid);
165 	}
166 
167 	/*
168 	 * It's not committed.
169 	 */
170 	return false;
171 }
172 
173 /*
174  * TransactionIdDidAbort
175  *		True iff transaction associated with the identifier did abort.
176  *
177  * Note:
178  *		Assumes transaction identifier is valid and exists in clog.
179  */
180 bool							/* true if given transaction aborted */
TransactionIdDidAbort(TransactionId transactionId)181 TransactionIdDidAbort(TransactionId transactionId)
182 {
183 	XidStatus	xidstatus;
184 
185 	xidstatus = TransactionLogFetch(transactionId);
186 
187 	/*
188 	 * If it's marked aborted, it's aborted.
189 	 */
190 	if (xidstatus == TRANSACTION_STATUS_ABORTED)
191 		return true;
192 
193 	/*
194 	 * If it's marked subcommitted, we have to check the parent recursively.
195 	 * However, if it's older than TransactionXmin, we can't look at
196 	 * pg_subtrans; instead assume that the parent crashed without cleaning up
197 	 * its children.
198 	 */
199 	if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
200 	{
201 		TransactionId parentXid;
202 
203 		if (TransactionIdPrecedes(transactionId, TransactionXmin))
204 			return true;
205 		parentXid = SubTransGetParent(transactionId);
206 		if (!TransactionIdIsValid(parentXid))
207 		{
208 			/* see notes in TransactionIdDidCommit */
209 			elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
210 				 transactionId);
211 			return true;
212 		}
213 		return TransactionIdDidAbort(parentXid);
214 	}
215 
216 	/*
217 	 * It's not aborted.
218 	 */
219 	return false;
220 }
221 
222 /*
223  * TransactionIdIsKnownCompleted
224  *		True iff transaction associated with the identifier is currently
225  *		known to have either committed or aborted.
226  *
227  * This does NOT look into pg_xact but merely probes our local cache
228  * (and so it's not named TransactionIdDidComplete, which would be the
229  * appropriate name for a function that worked that way).  The intended
230  * use is just to short-circuit TransactionIdIsInProgress calls when doing
231  * repeated tqual.c checks for the same XID.  If this isn't extremely fast
232  * then it will be counterproductive.
233  *
234  * Note:
235  *		Assumes transaction identifier is valid.
236  */
237 bool
TransactionIdIsKnownCompleted(TransactionId transactionId)238 TransactionIdIsKnownCompleted(TransactionId transactionId)
239 {
240 	if (TransactionIdEquals(transactionId, cachedFetchXid))
241 	{
242 		/* If it's in the cache at all, it must be completed. */
243 		return true;
244 	}
245 
246 	return false;
247 }
248 
249 /*
250  * TransactionIdCommitTree
251  *		Marks the given transaction and children as committed
252  *
253  * "xid" is a toplevel transaction commit, and the xids array contains its
254  * committed subtransactions.
255  *
256  * This commit operation is not guaranteed to be atomic, but if not, subxids
257  * are correctly marked subcommit first.
258  */
259 void
TransactionIdCommitTree(TransactionId xid,int nxids,TransactionId * xids)260 TransactionIdCommitTree(TransactionId xid, int nxids, TransactionId *xids)
261 {
262 	TransactionIdSetTreeStatus(xid, nxids, xids,
263 							   TRANSACTION_STATUS_COMMITTED,
264 							   InvalidXLogRecPtr);
265 }
266 
267 /*
268  * TransactionIdAsyncCommitTree
269  *		Same as above, but for async commits.  The commit record LSN is needed.
270  */
271 void
TransactionIdAsyncCommitTree(TransactionId xid,int nxids,TransactionId * xids,XLogRecPtr lsn)272 TransactionIdAsyncCommitTree(TransactionId xid, int nxids, TransactionId *xids,
273 							 XLogRecPtr lsn)
274 {
275 	TransactionIdSetTreeStatus(xid, nxids, xids,
276 							   TRANSACTION_STATUS_COMMITTED, lsn);
277 }
278 
279 /*
280  * TransactionIdAbortTree
281  *		Marks the given transaction and children as aborted.
282  *
283  * "xid" is a toplevel transaction commit, and the xids array contains its
284  * committed subtransactions.
285  *
286  * We don't need to worry about the non-atomic behavior, since any onlookers
287  * will consider all the xacts as not-yet-committed anyway.
288  */
289 void
TransactionIdAbortTree(TransactionId xid,int nxids,TransactionId * xids)290 TransactionIdAbortTree(TransactionId xid, int nxids, TransactionId *xids)
291 {
292 	TransactionIdSetTreeStatus(xid, nxids, xids,
293 							   TRANSACTION_STATUS_ABORTED, InvalidXLogRecPtr);
294 }
295 
296 /*
297  * TransactionIdPrecedes --- is id1 logically < id2?
298  */
299 bool
TransactionIdPrecedes(TransactionId id1,TransactionId id2)300 TransactionIdPrecedes(TransactionId id1, TransactionId id2)
301 {
302 	/*
303 	 * If either ID is a permanent XID then we can just do unsigned
304 	 * comparison.  If both are normal, do a modulo-2^32 comparison.
305 	 */
306 	int32		diff;
307 
308 	if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
309 		return (id1 < id2);
310 
311 	diff = (int32) (id1 - id2);
312 	return (diff < 0);
313 }
314 
315 /*
316  * TransactionIdPrecedesOrEquals --- is id1 logically <= id2?
317  */
318 bool
TransactionIdPrecedesOrEquals(TransactionId id1,TransactionId id2)319 TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
320 {
321 	int32		diff;
322 
323 	if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
324 		return (id1 <= id2);
325 
326 	diff = (int32) (id1 - id2);
327 	return (diff <= 0);
328 }
329 
330 /*
331  * TransactionIdFollows --- is id1 logically > id2?
332  */
333 bool
TransactionIdFollows(TransactionId id1,TransactionId id2)334 TransactionIdFollows(TransactionId id1, TransactionId id2)
335 {
336 	int32		diff;
337 
338 	if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
339 		return (id1 > id2);
340 
341 	diff = (int32) (id1 - id2);
342 	return (diff > 0);
343 }
344 
345 /*
346  * TransactionIdFollowsOrEquals --- is id1 logically >= id2?
347  */
348 bool
TransactionIdFollowsOrEquals(TransactionId id1,TransactionId id2)349 TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
350 {
351 	int32		diff;
352 
353 	if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
354 		return (id1 >= id2);
355 
356 	diff = (int32) (id1 - id2);
357 	return (diff >= 0);
358 }
359 
360 
361 /*
362  * TransactionIdLatest --- get latest XID among a main xact and its children
363  */
364 TransactionId
TransactionIdLatest(TransactionId mainxid,int nxids,const TransactionId * xids)365 TransactionIdLatest(TransactionId mainxid,
366 					int nxids, const TransactionId *xids)
367 {
368 	TransactionId result;
369 
370 	/*
371 	 * In practice it is highly likely that the xids[] array is sorted, and so
372 	 * we could save some cycles by just taking the last child XID, but this
373 	 * probably isn't so performance-critical that it's worth depending on
374 	 * that assumption.  But just to show we're not totally stupid, scan the
375 	 * array back-to-front to avoid useless assignments.
376 	 */
377 	result = mainxid;
378 	while (--nxids >= 0)
379 	{
380 		if (TransactionIdPrecedes(result, xids[nxids]))
381 			result = xids[nxids];
382 	}
383 	return result;
384 }
385 
386 
387 /*
388  * TransactionIdGetCommitLSN
389  *
390  * This function returns an LSN that is late enough to be able
391  * to guarantee that if we flush up to the LSN returned then we
392  * will have flushed the transaction's commit record to disk.
393  *
394  * The result is not necessarily the exact LSN of the transaction's
395  * commit record!  For example, for long-past transactions (those whose
396  * clog pages already migrated to disk), we'll return InvalidXLogRecPtr.
397  * Also, because we group transactions on the same clog page to conserve
398  * storage, we might return the LSN of a later transaction that falls into
399  * the same group.
400  */
401 XLogRecPtr
TransactionIdGetCommitLSN(TransactionId xid)402 TransactionIdGetCommitLSN(TransactionId xid)
403 {
404 	XLogRecPtr	result;
405 
406 	/*
407 	 * Currently, all uses of this function are for xids that were just
408 	 * reported to be committed by TransactionLogFetch, so we expect that
409 	 * checking TransactionLogFetch's cache will usually succeed and avoid an
410 	 * extra trip to shared memory.
411 	 */
412 	if (TransactionIdEquals(xid, cachedFetchXid))
413 		return cachedCommitLSN;
414 
415 	/* Special XIDs are always known committed */
416 	if (!TransactionIdIsNormal(xid))
417 		return InvalidXLogRecPtr;
418 
419 	/*
420 	 * Get the transaction status.
421 	 */
422 	(void) TransactionIdGetStatus(xid, &result);
423 
424 	return result;
425 }
426