PostgreSQL Source Code git master
Loading...
Searching...
No Matches
xid8funcs.c File Reference
#include "postgres.h"
#include "access/transam.h"
#include "access/xact.h"
#include "funcapi.h"
#include "lib/qunique.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "storage/lwlock.h"
#include "storage/procarray.h"
#include "storage/procnumber.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/xid8.h"
#include "varatt.h"
Include dependency graph for xid8funcs.c:

Go to the source code of this file.

Data Structures

struct  pg_snapshot
 

Macros

#define USE_BSEARCH_IF_NXIP_GREATER   30
 
#define PG_SNAPSHOT_SIZE(nxip)    (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))
 
#define PG_SNAPSHOT_MAX_NXIP    ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
 

Functions

 StaticAssertDecl (MAX_BACKENDS *2<=PG_SNAPSHOT_MAX_NXIP, "possible overflow in pg_current_snapshot()")
 
static bool TransactionIdInRecentPast (FullTransactionId fxid, TransactionId *extracted_xid)
 
static int cmp_fxid (const void *aa, const void *bb)
 
static void sort_snapshot (pg_snapshot *snap)
 
static bool is_visible_fxid (FullTransactionId value, const pg_snapshot *snap)
 
static StringInfo buf_init (FullTransactionId xmin, FullTransactionId xmax)
 
static void buf_add_txid (StringInfo buf, FullTransactionId fxid)
 
static pg_snapshotbuf_finalize (StringInfo buf)
 
static pg_snapshotparse_snapshot (const char *str, Node *escontext)
 
Datum pg_current_xact_id (PG_FUNCTION_ARGS)
 
Datum pg_current_xact_id_if_assigned (PG_FUNCTION_ARGS)
 
Datum pg_current_snapshot (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_in (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_out (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_recv (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_send (PG_FUNCTION_ARGS)
 
Datum pg_visible_in_snapshot (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_xmin (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_xmax (PG_FUNCTION_ARGS)
 
Datum pg_snapshot_xip (PG_FUNCTION_ARGS)
 
Datum pg_xact_status (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ PG_SNAPSHOT_MAX_NXIP

#define PG_SNAPSHOT_MAX_NXIP    ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))

Definition at line 73 of file xid8funcs.c.

98{
103
105
106 if (extracted_xid != NULL)
107 *extracted_xid = xid;
108
109 if (!TransactionIdIsValid(xid))
110 return false;
111
112 /* For non-normal transaction IDs, we can ignore the epoch. */
113 if (!TransactionIdIsNormal(xid))
114 return true;
115
116 /* If the transaction ID is in the future, throw an error. */
120 errmsg("transaction ID %" PRIu64 " is in the future",
122
123 /*
124 * TransamVariables->oldestClogXid is protected by XactTruncationLock, but
125 * we don't acquire that lock here. Instead, we require the caller to
126 * acquire it, because the caller is presumably going to look up the
127 * returned XID. If we took and released the lock within this function, a
128 * CLOG truncation could occur before the caller finished with the XID.
129 */
131
132 /*
133 * If fxid is not older than TransamVariables->oldestClogXid, the relevant
134 * CLOG entry is guaranteed to still exist.
135 *
136 * TransamVariables->oldestXid governs allowable XIDs. Usually,
137 * oldestClogXid==oldestXid. It's also possible for oldestClogXid to
138 * follow oldestXid, in which case oldestXid might advance after our
139 * ReadNextFullTransactionId() call. If oldestXid has advanced, that
140 * advancement reinstated the usual oldestClogXid==oldestXid. Whether or
141 * not that happened, oldestClogXid is allowable relative to now_fullxid.
142 */
147}
148
149/*
150 * txid comparator for qsort/bsearch
151 */
152static int
153cmp_fxid(const void *aa, const void *bb)
154{
157
159 return -1;
161 return 1;
162 return 0;
163}
164
165/*
166 * Sort a snapshot's txids, so we can use bsearch() later. Also remove
167 * any duplicates.
168 *
169 * For consistency of on-disk representation, we always sort even if bsearch
170 * will not be used.
171 */
172static void
174{
175 if (snap->nxip > 1)
176 {
177 qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
178 snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
179 cmp_fxid);
180 }
181}
182
183/*
184 * check fxid visibility.
185 */
186static bool
188{
190 return true;
191 else if (!FullTransactionIdPrecedes(value, snap->xmax))
192 return false;
193#ifdef USE_BSEARCH_IF_NXIP_GREATER
194 else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
195 {
196 const void *res;
197
198 res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
199 cmp_fxid);
200 /* if found, transaction is still in progress */
201 return (res) ? false : true;
202 }
203#endif
204 else
205 {
206 uint32 i;
207
208 for (i = 0; i < snap->nxip; i++)
209 {
211 return false;
212 }
213 return true;
214 }
215}
216
217/*
218 * helper functions to use StringInfo for pg_snapshot creation.
219 */
220
221static StringInfo
223{
226
227 snap.xmin = xmin;
228 snap.xmax = xmax;
229 snap.nxip = 0;
230
233 return buf;
234}
235
236static void
238{
239 pg_snapshot *snap = (pg_snapshot *) buf->data;
240
241 /* do this before possible realloc */
242 snap->nxip++;
243
244 appendBinaryStringInfo(buf, &fxid, sizeof(fxid));
245}
246
247static pg_snapshot *
249{
250 pg_snapshot *snap = (pg_snapshot *) buf->data;
251
252 SET_VARSIZE(snap, buf->len);
253
254 /* buf is not needed anymore */
255 buf->data = NULL;
256 pfree(buf);
257
258 return snap;
259}
260
261/*
262 * parse snapshot from cstring
263 */
264static pg_snapshot *
265parse_snapshot(const char *str, Node *escontext)
266{
271 const char *str_start = str;
272 char *endp;
274
276 if (*endp != ':')
277 goto bad_format;
278 str = endp + 1;
279
281 if (*endp != ':')
282 goto bad_format;
283 str = endp + 1;
284
285 /* it should look sane */
286 if (!FullTransactionIdIsValid(xmin) ||
288 FullTransactionIdPrecedes(xmax, xmin))
289 goto bad_format;
290
291 /* allocate buffer */
292 buf = buf_init(xmin, xmax);
293
294 /* loop over values */
295 while (*str != '\0')
296 {
297 /* read next value */
299 str = endp;
300
301 /* require the input to be in order */
302 if (FullTransactionIdPrecedes(val, xmin) ||
305 goto bad_format;
306
307 /* skip duplicates */
310 last_val = val;
311
312 if (*str == ',')
313 str++;
314 else if (*str != '\0')
315 goto bad_format;
316 }
317
318 return buf_finalize(buf);
319
321 ereturn(escontext, NULL,
323 errmsg("invalid input syntax for type %s: \"%s\"",
324 "pg_snapshot", str_start)));
325}
326
327/*
328 * pg_current_xact_id() returns xid8
329 *
330 * Return the current toplevel full transaction ID.
331 * If the current transaction does not have one, one is assigned.
332 */
333Datum
335{
336 /*
337 * Must prevent during recovery because if an xid is not assigned we try
338 * to assign one, which would fail. Programs already rely on this function
339 * to always return a valid current xid, so we should not change this to
340 * return NULL or similar invalid xid.
341 */
342 PreventCommandDuringRecovery("pg_current_xact_id()");
343
345}
346
347/*
348 * Same as pg_current_xact_id() but doesn't assign a new xid if there
349 * isn't one yet.
350 */
351Datum
353{
355
358
360}
361
362/*
363 * pg_current_snapshot() returns pg_snapshot
364 *
365 * Return current snapshot
366 *
367 * Note that only top-transaction XIDs are included in the snapshot.
368 */
369Datum
371{
373 uint32 nxip,
374 i;
377
379 if (cur == NULL)
380 elog(ERROR, "no active snapshot set");
381
382 /* allocate */
383 nxip = cur->xcnt;
385
386 /*
387 * Fill. This is the current backend's active snapshot, so MyProc->xmin
388 * is <= all these XIDs. As long as that remains so, oldestXid can't
389 * advance past any of these XIDs. Hence, these XIDs remain allowable
390 * relative to next_fxid.
391 */
392 snap->xmin = FullTransactionIdFromAllowableAt(next_fxid, cur->xmin);
393 snap->xmax = FullTransactionIdFromAllowableAt(next_fxid, cur->xmax);
394 snap->nxip = nxip;
395 for (i = 0; i < nxip; i++)
396 snap->xip[i] =
397 FullTransactionIdFromAllowableAt(next_fxid, cur->xip[i]);
398
399 /*
400 * We want them guaranteed to be in ascending order. This also removes
401 * any duplicate xids. Normally, an XID can only be assigned to one
402 * backend, but when preparing a transaction for two-phase commit, there
403 * is a transient state when both the original backend and the dummy
404 * PGPROC entry reserved for the prepared transaction hold the same XID.
405 */
407
408 /* set size after sorting, because it may have removed duplicate xips */
410
412}
413
414/*
415 * pg_snapshot_in(cstring) returns pg_snapshot
416 *
417 * input function for type pg_snapshot
418 */
419Datum
421{
422 char *str = PG_GETARG_CSTRING(0);
424
425 snap = parse_snapshot(str, fcinfo->context);
426
428}
429
430/*
431 * pg_snapshot_out(pg_snapshot) returns cstring
432 *
433 * output function for type pg_snapshot
434 */
435Datum
437{
440 uint32 i;
441
443
448
449 for (i = 0; i < snap->nxip; i++)
450 {
451 if (i > 0)
455 }
456
458}
459
460/*
461 * pg_snapshot_recv(internal) returns pg_snapshot
462 *
463 * binary input function for type pg_snapshot
464 *
465 * format: int4 nxip, int8 xmin, int8 xmax, int8 xip
466 */
467Datum
469{
473 int nxip;
474 int i;
477
478 /* load and validate nxip */
479 nxip = pq_getmsgint(buf, 4);
481 goto bad_format;
482
485 if (!FullTransactionIdIsValid(xmin) ||
487 FullTransactionIdPrecedes(xmax, xmin))
488 goto bad_format;
489
491 snap->xmin = xmin;
492 snap->xmax = xmax;
493
494 for (i = 0; i < nxip; i++)
495 {
498
499 if (FullTransactionIdPrecedes(cur, last) ||
502 goto bad_format;
503
504 /* skip duplicate xips */
505 if (FullTransactionIdEquals(cur, last))
506 {
507 i--;
508 nxip--;
509 continue;
510 }
511
512 snap->xip[i] = cur;
513 last = cur;
514 }
515 snap->nxip = nxip;
518
522 errmsg("invalid external pg_snapshot data")));
523 PG_RETURN_POINTER(NULL); /* keep compiler quiet */
524}
525
526/*
527 * pg_snapshot_send(pg_snapshot) returns bytea
528 *
529 * binary output function for type pg_snapshot
530 *
531 * format: int4 nxip, u64 xmin, u64 xmax, u64 xip...
532 */
533Datum
535{
538 uint32 i;
539
541 pq_sendint32(&buf, snap->nxip);
544 for (i = 0; i < snap->nxip; i++)
547}
548
549/*
550 * pg_visible_in_snapshot(xid8, pg_snapshot) returns bool
551 *
552 * is txid visible in snapshot ?
553 */
554Datum
556{
559
561}
562
563/*
564 * pg_snapshot_xmin(pg_snapshot) returns xid8
565 *
566 * return snapshot's xmin
567 */
568Datum
570{
572
574}
575
576/*
577 * pg_snapshot_xmax(pg_snapshot) returns xid8
578 *
579 * return snapshot's xmax
580 */
581Datum
583{
585
587}
588
589/*
590 * pg_snapshot_xip(pg_snapshot) returns setof xid8
591 *
592 * return in-progress xid8s in snapshot.
593 */
594Datum
596{
600
601 /* on first call initialize fctx and get copy of snapshot */
602 if (SRF_IS_FIRSTCALL())
603 {
605
607
608 /* make a copy of user snapshot */
609 snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
611
612 fctx->user_fctx = snap;
613 }
614
615 /* return values one-by-one */
617 snap = fctx->user_fctx;
618 if (fctx->call_cntr < snap->nxip)
619 {
620 value = snap->xip[fctx->call_cntr];
622 }
623 else
624 {
626 }
627}
628
629/*
630 * Report the status of a recent transaction ID, or null for wrapped,
631 * truncated away or otherwise too old XIDs.
632 *
633 * The passed epoch-qualified xid is treated as a normal xid, not a
634 * multixact id.
635 *
636 * If it points to a committed subxact the result is the subxact status even
637 * though the parent xact may still be in progress or may have aborted.
638 */
639Datum
641{
642 const char *status;
644 TransactionId xid;
645
646 /*
647 * We must protect against concurrent truncation of clog entries to avoid
648 * an I/O error on SLRU lookup.
649 */
651 if (TransactionIdInRecentPast(fxid, &xid))
652 {
654
655 /*
656 * Like when doing visibility checks on a row, check whether the
657 * transaction is still in progress before looking into the CLOG.
658 * Otherwise we would incorrectly return "committed" for a transaction
659 * that is committing and has already updated the CLOG, but hasn't
660 * removed its XID from the proc array yet. (See comment on that race
661 * condition at the top of heapam_visibility.c)
662 */
664 status = "in progress";
665 else if (TransactionIdDidCommit(xid))
666 status = "committed";
667 else
668 {
669 /* it must have aborted or crashed */
670 status = "aborted";
671 }
672 }
673 else
674 {
675 status = NULL;
676 }
678
679 if (status == NULL)
681 else
683}
#define Assert(condition)
Definition c.h:873
int64_t int64
Definition c.h:543
#define UINT64_FORMAT
Definition c.h:565
uint64_t uint64
Definition c.h:547
uint32_t uint32
Definition c.h:546
uint32 TransactionId
Definition c.h:666
struct cursor * cur
Definition ecpg.c:29
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ereturn(context, dummy_value,...)
Definition elog.h:278
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define PG_GETARG_VARLENA_P(n)
Definition fmgr.h:288
#define PG_RETURN_BYTEA_P(x)
Definition fmgr.h:373
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_RETURN_CSTRING(x)
Definition fmgr.h:364
#define PG_GETARG_CSTRING(n)
Definition fmgr.h:278
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
#define PG_RETURN_POINTER(x)
Definition fmgr.h:363
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
const char * str
#define false
long val
Definition informix.c:689
static struct @172 value
int b
Definition isn.c:74
int a
Definition isn.c:73
int i
Definition isn.c:77
bool LWLockHeldByMe(LWLock *lock)
Definition lwlock.c:1911
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1176
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1793
@ LW_SHARED
Definition lwlock.h:113
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc(Size size)
Definition mcxt.c:1387
void * arg
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define qsort(a, b, c, d)
Definition port.h:495
uint64_t Datum
Definition postgres.h:70
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition pqformat.c:414
void pq_begintypsend(StringInfo buf)
Definition pqformat.c:325
int64 pq_getmsgint64(StringInfo msg)
Definition pqformat.c:452
bytea * pq_endtypsend(StringInfo buf)
Definition pqformat.c:345
static void pq_sendint32(StringInfo buf, uint32 i)
Definition pqformat.h:144
static void pq_sendint64(StringInfo buf, uint64 i)
Definition pqformat.h:152
static int fb(int x)
bool TransactionIdIsInProgress(TransactionId xid)
Definition procarray.c:1399
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
Definition qunique.h:21
Snapshot GetActiveSnapshot(void)
Definition snapmgr.c:800
struct StringInfoData * StringInfo
Definition string.h:15
StringInfo makeStringInfo(void)
Definition stringinfo.c:72
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition stringinfo.c:281
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition nodes.h:135
TransactionId oldestClogXid
Definition transam.h:253
bool TransactionIdDidCommit(TransactionId transactionId)
Definition transam.c:126
#define FullTransactionIdEquals(a, b)
Definition transam.h:50
static FullTransactionId FullTransactionIdFromAllowableAt(FullTransactionId nextFullXid, TransactionId xid)
Definition transam.h:443
#define U64FromFullTransactionId(x)
Definition transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition transam.h:81
#define FullTransactionIdFollowsOrEquals(a, b)
Definition transam.h:54
#define XidFromFullTransactionId(x)
Definition transam.h:48
#define TransactionIdIsValid(xid)
Definition transam.h:41
#define TransactionIdIsNormal(xid)
Definition transam.h:42
#define InvalidFullTransactionId
Definition transam.h:56
#define FullTransactionIdPrecedes(a, b)
Definition transam.h:51
#define FullTransactionIdIsValid(x)
Definition transam.h:55
void PreventCommandDuringRecovery(const char *cmdname)
Definition utility.c:443
static Size VARSIZE(const void *PTR)
Definition varatt.h:298
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432
text * cstring_to_text(const char *s)
Definition varlena.c:181
FullTransactionId ReadNextFullTransactionId(void)
Definition varsup.c:288
TransamVariablesData * TransamVariables
Definition varsup.c:34
FullTransactionId GetTopFullTransactionId(void)
Definition xact.c:484
FullTransactionId GetTopFullTransactionIdIfAny(void)
Definition xact.c:500
#define PG_GETARG_FULLTRANSACTIONID(X)
Definition xid8.h:29
static Datum FullTransactionIdGetDatum(FullTransactionId X)
Definition xid8.h:24
#define PG_RETURN_FULLTRANSACTIONID(X)
Definition xid8.h:30
static bool TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
Definition xid8funcs.c:98
Datum pg_snapshot_send(PG_FUNCTION_ARGS)
Definition xid8funcs.c:535
static pg_snapshot * buf_finalize(StringInfo buf)
Definition xid8funcs.c:249
Datum pg_current_xact_id_if_assigned(PG_FUNCTION_ARGS)
Definition xid8funcs.c:353
static StringInfo buf_init(FullTransactionId xmin, FullTransactionId xmax)
Definition xid8funcs.c:223
static bool is_visible_fxid(FullTransactionId value, const pg_snapshot *snap)
Definition xid8funcs.c:188
static int cmp_fxid(const void *aa, const void *bb)
Definition xid8funcs.c:154
#define USE_BSEARCH_IF_NXIP_GREATER
Definition xid8funcs.c:49
Datum pg_snapshot_out(PG_FUNCTION_ARGS)
Definition xid8funcs.c:437
#define PG_SNAPSHOT_SIZE(nxip)
Definition xid8funcs.c:71
#define PG_SNAPSHOT_MAX_NXIP
Definition xid8funcs.c:73
Datum pg_current_xact_id(PG_FUNCTION_ARGS)
Definition xid8funcs.c:335
static pg_snapshot * parse_snapshot(const char *str, Node *escontext)
Definition xid8funcs.c:266
Datum pg_snapshot_recv(PG_FUNCTION_ARGS)
Definition xid8funcs.c:469
Datum pg_snapshot_in(PG_FUNCTION_ARGS)
Definition xid8funcs.c:421
Datum pg_xact_status(PG_FUNCTION_ARGS)
Definition xid8funcs.c:641
Datum pg_current_snapshot(PG_FUNCTION_ARGS)
Definition xid8funcs.c:371
static void buf_add_txid(StringInfo buf, FullTransactionId fxid)
Definition xid8funcs.c:238
Datum pg_snapshot_xmin(PG_FUNCTION_ARGS)
Definition xid8funcs.c:570
Datum pg_snapshot_xip(PG_FUNCTION_ARGS)
Definition xid8funcs.c:596
static void sort_snapshot(pg_snapshot *snap)
Definition xid8funcs.c:174
Datum pg_visible_in_snapshot(PG_FUNCTION_ARGS)
Definition xid8funcs.c:556
Datum pg_snapshot_xmax(PG_FUNCTION_ARGS)
Definition xid8funcs.c:583

◆ PG_SNAPSHOT_SIZE

#define PG_SNAPSHOT_SIZE (   nxip)     (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))

Definition at line 71 of file xid8funcs.c.

◆ USE_BSEARCH_IF_NXIP_GREATER

#define USE_BSEARCH_IF_NXIP_GREATER   30

Definition at line 49 of file xid8funcs.c.

Function Documentation

◆ buf_add_txid()

static void buf_add_txid ( StringInfo  buf,
FullTransactionId  fxid 
)
static

Definition at line 238 of file xid8funcs.c.

239{
240 pg_snapshot *snap = (pg_snapshot *) buf->data;
241
242 /* do this before possible realloc */
243 snap->nxip++;
244
245 appendBinaryStringInfo(buf, &fxid, sizeof(fxid));
246}

References appendBinaryStringInfo(), buf, and fb().

Referenced by parse_snapshot().

◆ buf_finalize()

static pg_snapshot * buf_finalize ( StringInfo  buf)
static

Definition at line 249 of file xid8funcs.c.

250{
251 pg_snapshot *snap = (pg_snapshot *) buf->data;
252
253 SET_VARSIZE(snap, buf->len);
254
255 /* buf is not needed anymore */
256 buf->data = NULL;
257 pfree(buf);
258
259 return snap;
260}

References buf, fb(), pfree(), and SET_VARSIZE().

Referenced by parse_snapshot().

◆ buf_init()

static StringInfo buf_init ( FullTransactionId  xmin,
FullTransactionId  xmax 
)
static

Definition at line 223 of file xid8funcs.c.

224{
227
228 snap.xmin = xmin;
229 snap.xmax = xmax;
230 snap.nxip = 0;
231
234 return buf;
235}

References appendBinaryStringInfo(), buf, fb(), makeStringInfo(), and PG_SNAPSHOT_SIZE.

Referenced by parse_snapshot().

◆ cmp_fxid()

static int cmp_fxid ( const void aa,
const void bb 
)
static

Definition at line 154 of file xid8funcs.c.

155{
158
160 return -1;
162 return 1;
163 return 0;
164}

References a, b, fb(), and FullTransactionIdPrecedes.

Referenced by is_visible_fxid(), and sort_snapshot().

◆ is_visible_fxid()

static bool is_visible_fxid ( FullTransactionId  value,
const pg_snapshot snap 
)
static

Definition at line 188 of file xid8funcs.c.

189{
191 return true;
192 else if (!FullTransactionIdPrecedes(value, snap->xmax))
193 return false;
194#ifdef USE_BSEARCH_IF_NXIP_GREATER
195 else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
196 {
197 const void *res;
198
199 res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
200 cmp_fxid);
201 /* if found, transaction is still in progress */
202 return (res) ? false : true;
203 }
204#endif
205 else
206 {
207 uint32 i;
208
209 for (i = 0; i < snap->nxip; i++)
210 {
212 return false;
213 }
214 return true;
215 }
216}

References cmp_fxid(), false, fb(), FullTransactionIdEquals, FullTransactionIdPrecedes, i, USE_BSEARCH_IF_NXIP_GREATER, and value.

Referenced by pg_visible_in_snapshot().

◆ parse_snapshot()

static pg_snapshot * parse_snapshot ( const char str,
Node escontext 
)
static

Definition at line 266 of file xid8funcs.c.

267{
272 const char *str_start = str;
273 char *endp;
275
277 if (*endp != ':')
278 goto bad_format;
279 str = endp + 1;
280
282 if (*endp != ':')
283 goto bad_format;
284 str = endp + 1;
285
286 /* it should look sane */
287 if (!FullTransactionIdIsValid(xmin) ||
289 FullTransactionIdPrecedes(xmax, xmin))
290 goto bad_format;
291
292 /* allocate buffer */
293 buf = buf_init(xmin, xmax);
294
295 /* loop over values */
296 while (*str != '\0')
297 {
298 /* read next value */
300 str = endp;
301
302 /* require the input to be in order */
303 if (FullTransactionIdPrecedes(val, xmin) ||
306 goto bad_format;
307
308 /* skip duplicates */
311 last_val = val;
312
313 if (*str == ',')
314 str++;
315 else if (*str != '\0')
316 goto bad_format;
317 }
318
319 return buf_finalize(buf);
320
322 ereturn(escontext, NULL,
324 errmsg("invalid input syntax for type %s: \"%s\"",
325 "pg_snapshot", str_start)));
326}

References buf, buf_add_txid(), buf_finalize(), buf_init(), ereturn, errcode(), errmsg(), fb(), FullTransactionIdEquals, FullTransactionIdFollowsOrEquals, FullTransactionIdFromU64(), FullTransactionIdIsValid, FullTransactionIdPrecedes, InvalidFullTransactionId, str, and val.

Referenced by pg_snapshot_in().

◆ pg_current_snapshot()

Datum pg_current_snapshot ( PG_FUNCTION_ARGS  )

Definition at line 371 of file xid8funcs.c.

372{
374 uint32 nxip,
375 i;
378
380 if (cur == NULL)
381 elog(ERROR, "no active snapshot set");
382
383 /* allocate */
384 nxip = cur->xcnt;
386
387 /*
388 * Fill. This is the current backend's active snapshot, so MyProc->xmin
389 * is <= all these XIDs. As long as that remains so, oldestXid can't
390 * advance past any of these XIDs. Hence, these XIDs remain allowable
391 * relative to next_fxid.
392 */
393 snap->xmin = FullTransactionIdFromAllowableAt(next_fxid, cur->xmin);
394 snap->xmax = FullTransactionIdFromAllowableAt(next_fxid, cur->xmax);
395 snap->nxip = nxip;
396 for (i = 0; i < nxip; i++)
397 snap->xip[i] =
398 FullTransactionIdFromAllowableAt(next_fxid, cur->xip[i]);
399
400 /*
401 * We want them guaranteed to be in ascending order. This also removes
402 * any duplicate xids. Normally, an XID can only be assigned to one
403 * backend, but when preparing a transaction for two-phase commit, there
404 * is a transient state when both the original backend and the dummy
405 * PGPROC entry reserved for the prepared transaction hold the same XID.
406 */
408
409 /* set size after sorting, because it may have removed duplicate xips */
411
413}

References cur, elog, ERROR, fb(), FullTransactionIdFromAllowableAt(), GetActiveSnapshot(), i, palloc(), PG_RETURN_POINTER, PG_SNAPSHOT_SIZE, ReadNextFullTransactionId(), SET_VARSIZE(), and sort_snapshot().

◆ pg_current_xact_id()

Datum pg_current_xact_id ( PG_FUNCTION_ARGS  )

Definition at line 335 of file xid8funcs.c.

336{
337 /*
338 * Must prevent during recovery because if an xid is not assigned we try
339 * to assign one, which would fail. Programs already rely on this function
340 * to always return a valid current xid, so we should not change this to
341 * return NULL or similar invalid xid.
342 */
343 PreventCommandDuringRecovery("pg_current_xact_id()");
344
346}

References GetTopFullTransactionId(), PG_RETURN_FULLTRANSACTIONID, and PreventCommandDuringRecovery().

◆ pg_current_xact_id_if_assigned()

◆ pg_snapshot_in()

Datum pg_snapshot_in ( PG_FUNCTION_ARGS  )

Definition at line 421 of file xid8funcs.c.

422{
423 char *str = PG_GETARG_CSTRING(0);
425
426 snap = parse_snapshot(str, fcinfo->context);
427
429}

References fb(), parse_snapshot(), PG_GETARG_CSTRING, PG_RETURN_POINTER, and str.

◆ pg_snapshot_out()

◆ pg_snapshot_recv()

Datum pg_snapshot_recv ( PG_FUNCTION_ARGS  )

Definition at line 469 of file xid8funcs.c.

470{
474 int nxip;
475 int i;
478
479 /* load and validate nxip */
480 nxip = pq_getmsgint(buf, 4);
482 goto bad_format;
483
486 if (!FullTransactionIdIsValid(xmin) ||
488 FullTransactionIdPrecedes(xmax, xmin))
489 goto bad_format;
490
492 snap->xmin = xmin;
493 snap->xmax = xmax;
494
495 for (i = 0; i < nxip; i++)
496 {
499
500 if (FullTransactionIdPrecedes(cur, last) ||
503 goto bad_format;
504
505 /* skip duplicate xips */
506 if (FullTransactionIdEquals(cur, last))
507 {
508 i--;
509 nxip--;
510 continue;
511 }
512
513 snap->xip[i] = cur;
514 last = cur;
515 }
516 snap->nxip = nxip;
519
523 errmsg("invalid external pg_snapshot data")));
524 PG_RETURN_POINTER(NULL); /* keep compiler quiet */
525}

References buf, cur, ereport, errcode(), errmsg(), ERROR, fb(), FullTransactionIdEquals, FullTransactionIdFromU64(), FullTransactionIdIsValid, FullTransactionIdPrecedes, i, InvalidFullTransactionId, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, PG_SNAPSHOT_MAX_NXIP, PG_SNAPSHOT_SIZE, pq_getmsgint(), pq_getmsgint64(), and SET_VARSIZE().

◆ pg_snapshot_send()

◆ pg_snapshot_xip()

Datum pg_snapshot_xip ( PG_FUNCTION_ARGS  )

Definition at line 596 of file xid8funcs.c.

597{
601
602 /* on first call initialize fctx and get copy of snapshot */
603 if (SRF_IS_FIRSTCALL())
604 {
606
608
609 /* make a copy of user snapshot */
610 snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
612
613 fctx->user_fctx = snap;
614 }
615
616 /* return values one-by-one */
618 snap = fctx->user_fctx;
619 if (fctx->call_cntr < snap->nxip)
620 {
621 value = snap->xip[fctx->call_cntr];
623 }
624 else
625 {
627 }
628}

References arg, fb(), FullTransactionIdGetDatum(), MemoryContextAlloc(), PG_GETARG_VARLENA_P, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, value, and VARSIZE().

◆ pg_snapshot_xmax()

Datum pg_snapshot_xmax ( PG_FUNCTION_ARGS  )

Definition at line 583 of file xid8funcs.c.

References fb(), PG_GETARG_VARLENA_P, and PG_RETURN_FULLTRANSACTIONID.

◆ pg_snapshot_xmin()

Datum pg_snapshot_xmin ( PG_FUNCTION_ARGS  )

Definition at line 570 of file xid8funcs.c.

References fb(), PG_GETARG_VARLENA_P, and PG_RETURN_FULLTRANSACTIONID.

◆ pg_visible_in_snapshot()

◆ pg_xact_status()

Datum pg_xact_status ( PG_FUNCTION_ARGS  )

Definition at line 641 of file xid8funcs.c.

642{
643 const char *status;
645 TransactionId xid;
646
647 /*
648 * We must protect against concurrent truncation of clog entries to avoid
649 * an I/O error on SLRU lookup.
650 */
652 if (TransactionIdInRecentPast(fxid, &xid))
653 {
655
656 /*
657 * Like when doing visibility checks on a row, check whether the
658 * transaction is still in progress before looking into the CLOG.
659 * Otherwise we would incorrectly return "committed" for a transaction
660 * that is committing and has already updated the CLOG, but hasn't
661 * removed its XID from the proc array yet. (See comment on that race
662 * condition at the top of heapam_visibility.c)
663 */
665 status = "in progress";
666 else if (TransactionIdDidCommit(xid))
667 status = "committed";
668 else
669 {
670 /* it must have aborted or crashed */
671 status = "aborted";
672 }
673 }
674 else
675 {
676 status = NULL;
677 }
679
680 if (status == NULL)
682 else
684}

References Assert, cstring_to_text(), fb(), LW_SHARED, LWLockAcquire(), LWLockRelease(), PG_GETARG_FULLTRANSACTIONID, PG_RETURN_NULL, PG_RETURN_TEXT_P, TransactionIdDidCommit(), TransactionIdInRecentPast(), TransactionIdIsInProgress(), and TransactionIdIsValid.

◆ sort_snapshot()

static void sort_snapshot ( pg_snapshot snap)
static

Definition at line 174 of file xid8funcs.c.

175{
176 if (snap->nxip > 1)
177 {
178 qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
179 snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
180 cmp_fxid);
181 }
182}

References cmp_fxid(), fb(), qsort, and qunique().

Referenced by pg_current_snapshot().

◆ StaticAssertDecl()

StaticAssertDecl ( MAX_BACKENDS *2<=  PG_SNAPSHOT_MAX_NXIP,
"possible overflow in pg_current_snapshot()"   
)

◆ TransactionIdInRecentPast()

static bool TransactionIdInRecentPast ( FullTransactionId  fxid,
TransactionId extracted_xid 
)
static

Definition at line 98 of file xid8funcs.c.

99{
104
106
107 if (extracted_xid != NULL)
108 *extracted_xid = xid;
109
110 if (!TransactionIdIsValid(xid))
111 return false;
112
113 /* For non-normal transaction IDs, we can ignore the epoch. */
114 if (!TransactionIdIsNormal(xid))
115 return true;
116
117 /* If the transaction ID is in the future, throw an error. */
121 errmsg("transaction ID %" PRIu64 " is in the future",
123
124 /*
125 * TransamVariables->oldestClogXid is protected by XactTruncationLock, but
126 * we don't acquire that lock here. Instead, we require the caller to
127 * acquire it, because the caller is presumably going to look up the
128 * returned XID. If we took and released the lock within this function, a
129 * CLOG truncation could occur before the caller finished with the XID.
130 */
132
133 /*
134 * If fxid is not older than TransamVariables->oldestClogXid, the relevant
135 * CLOG entry is guaranteed to still exist.
136 *
137 * TransamVariables->oldestXid governs allowable XIDs. Usually,
138 * oldestClogXid==oldestXid. It's also possible for oldestClogXid to
139 * follow oldestXid, in which case oldestXid might advance after our
140 * ReadNextFullTransactionId() call. If oldestXid has advanced, that
141 * advancement reinstated the usual oldestClogXid==oldestXid. Whether or
142 * not that happened, oldestClogXid is allowable relative to now_fullxid.
143 */
148}

References Assert, ereport, errcode(), errmsg(), ERROR, fb(), FullTransactionIdFromAllowableAt(), FullTransactionIdPrecedes, LWLockHeldByMe(), TransamVariablesData::oldestClogXid, ReadNextFullTransactionId(), TransactionIdIsNormal, TransactionIdIsValid, TransamVariables, U64FromFullTransactionId, and XidFromFullTransactionId.

Referenced by pg_xact_status().