PostgreSQL Source Code  git master
xid8funcs.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  * xid8funcs.c
3  *
4  * Export internal transaction IDs to user level.
5  *
6  * Note that only top-level transaction IDs are exposed to user sessions.
7  * This is important because xid8s frequently persist beyond the global
8  * xmin horizon, or may even be shipped to other machines, so we cannot
9  * rely on being able to correlate subtransaction IDs with their parents
10  * via functions such as SubTransGetTopmostTransaction().
11  *
12  * These functions are used to support the txid_XXX functions and the newer
13  * pg_current_xact_id, pg_current_snapshot and related fmgr functions, since
14  * the only difference between them is whether they expose xid8 or int8 values
15  * to users. The txid_XXX variants should eventually be dropped.
16  *
17  *
18  * Copyright (c) 2003-2024, PostgreSQL Global Development Group
19  * Author: Jan Wieck, Afilias USA INC.
20  * 64-bit txids: Marko Kreen, Skype Technologies
21  *
22  * src/backend/utils/adt/xid8funcs.c
23  *
24  *-------------------------------------------------------------------------
25  */
26 
27 #include "postgres.h"
28 
29 #include "access/transam.h"
30 #include "access/xact.h"
31 #include "funcapi.h"
32 #include "lib/qunique.h"
33 #include "libpq/pqformat.h"
34 #include "miscadmin.h"
35 #include "postmaster/postmaster.h"
36 #include "storage/lwlock.h"
37 #include "storage/procarray.h"
38 #include "utils/builtins.h"
39 #include "utils/memutils.h"
40 #include "utils/snapmgr.h"
41 #include "utils/xid8.h"
42 
43 
44 /*
45  * If defined, use bsearch() function for searching for xid8s in snapshots
46  * that have more than the specified number of values.
47  */
48 #define USE_BSEARCH_IF_NXIP_GREATER 30
49 
50 
51 /*
52  * Snapshot containing FullTransactionIds.
53  */
54 typedef struct
55 {
56  /*
57  * 4-byte length hdr, should not be touched directly.
58  *
59  * Explicit embedding is ok as we want always correct alignment anyway.
60  */
62 
63  uint32 nxip; /* number of fxids in xip array */
66  /* in-progress fxids, xmin <= xip[i] < xmax: */
68 } pg_snapshot;
69 
70 #define PG_SNAPSHOT_SIZE(nxip) \
71  (offsetof(pg_snapshot, xip) + sizeof(FullTransactionId) * (nxip))
72 #define PG_SNAPSHOT_MAX_NXIP \
73  ((MaxAllocSize - offsetof(pg_snapshot, xip)) / sizeof(FullTransactionId))
74 
75 /*
76  * Compile-time limits on the procarray (MAX_BACKENDS processes plus
77  * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
78  */
80  "possible overflow in pg_current_snapshot()");
81 
82 
83 /*
84  * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
85  *
86  * It is an ERROR if the xid is in the future. Otherwise, returns true if
87  * the transaction is still new enough that we can determine whether it
88  * committed and false otherwise. If *extracted_xid is not NULL, it is set
89  * to the low 32 bits of the transaction ID (i.e. the actual XID, without the
90  * epoch).
91  *
92  * The caller must hold XactTruncationLock since it's dealing with arbitrary
93  * XIDs, and must continue to hold it until it's done with any clog lookups
94  * relating to those XIDs.
95  */
96 static bool
98 {
100  uint32 now_epoch;
101  TransactionId now_epoch_next_xid;
102  FullTransactionId now_fullxid;
103  TransactionId oldest_xid;
104  FullTransactionId oldest_fxid;
105 
106  now_fullxid = ReadNextFullTransactionId();
107  now_epoch_next_xid = XidFromFullTransactionId(now_fullxid);
108  now_epoch = EpochFromFullTransactionId(now_fullxid);
109 
110  if (extracted_xid != NULL)
111  *extracted_xid = xid;
112 
113  if (!TransactionIdIsValid(xid))
114  return false;
115 
116  /* For non-normal transaction IDs, we can ignore the epoch. */
117  if (!TransactionIdIsNormal(xid))
118  return true;
119 
120  /* If the transaction ID is in the future, throw an error. */
121  if (!FullTransactionIdPrecedes(fxid, now_fullxid))
122  ereport(ERROR,
123  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
124  errmsg("transaction ID %llu is in the future",
125  (unsigned long long) U64FromFullTransactionId(fxid))));
126 
127  /*
128  * TransamVariables->oldestClogXid is protected by XactTruncationLock, but
129  * we don't acquire that lock here. Instead, we require the caller to
130  * acquire it, because the caller is presumably going to look up the
131  * returned XID. If we took and released the lock within this function, a
132  * CLOG truncation could occur before the caller finished with the XID.
133  */
134  Assert(LWLockHeldByMe(XactTruncationLock));
135 
136  /*
137  * If fxid is not older than TransamVariables->oldestClogXid, the relevant
138  * CLOG entry is guaranteed to still exist. Convert
139  * TransamVariables->oldestClogXid into a FullTransactionId to compare it
140  * with fxid. Determine the right epoch knowing that oldest_fxid
141  * shouldn't be more than 2^31 older than now_fullxid.
142  */
143  oldest_xid = TransamVariables->oldestClogXid;
144  Assert(TransactionIdPrecedesOrEquals(oldest_xid, now_epoch_next_xid));
145  if (oldest_xid <= now_epoch_next_xid)
146  {
147  oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch, oldest_xid);
148  }
149  else
150  {
151  Assert(now_epoch > 0);
152  oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch - 1, oldest_xid);
153  }
154  return !FullTransactionIdPrecedes(fxid, oldest_fxid);
155 }
156 
157 /*
158  * Convert a TransactionId obtained from a snapshot held by the caller to a
159  * FullTransactionId. Use next_fxid as a reference FullTransactionId, so that
160  * we can compute the high order bits. It must have been obtained by the
161  * caller with ReadNextFullTransactionId() after the snapshot was created.
162  */
163 static FullTransactionId
165 {
166  TransactionId next_xid = XidFromFullTransactionId(next_fxid);
168 
169  /* Special transaction ID. */
170  if (!TransactionIdIsNormal(xid))
171  return FullTransactionIdFromEpochAndXid(0, xid);
172 
173  /*
174  * The 64 bit result must be <= next_fxid, since next_fxid hadn't been
175  * issued yet when the snapshot was created. Every TransactionId in the
176  * snapshot must therefore be from the same epoch as next_fxid, or the
177  * epoch before. We know this because next_fxid is never allow to get
178  * more than one epoch ahead of the TransactionIds in any snapshot.
179  */
180  if (xid > next_xid)
181  epoch--;
182 
184 }
185 
186 /*
187  * txid comparator for qsort/bsearch
188  */
189 static int
190 cmp_fxid(const void *aa, const void *bb)
191 {
192  FullTransactionId a = *(const FullTransactionId *) aa;
193  FullTransactionId b = *(const FullTransactionId *) bb;
194 
196  return -1;
198  return 1;
199  return 0;
200 }
201 
202 /*
203  * Sort a snapshot's txids, so we can use bsearch() later. Also remove
204  * any duplicates.
205  *
206  * For consistency of on-disk representation, we always sort even if bsearch
207  * will not be used.
208  */
209 static void
211 {
212  if (snap->nxip > 1)
213  {
214  qsort(snap->xip, snap->nxip, sizeof(FullTransactionId), cmp_fxid);
215  snap->nxip = qunique(snap->xip, snap->nxip, sizeof(FullTransactionId),
216  cmp_fxid);
217  }
218 }
219 
220 /*
221  * check fxid visibility.
222  */
223 static bool
225 {
227  return true;
228  else if (!FullTransactionIdPrecedes(value, snap->xmax))
229  return false;
230 #ifdef USE_BSEARCH_IF_NXIP_GREATER
231  else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
232  {
233  void *res;
234 
235  res = bsearch(&value, snap->xip, snap->nxip, sizeof(FullTransactionId),
236  cmp_fxid);
237  /* if found, transaction is still in progress */
238  return (res) ? false : true;
239  }
240 #endif
241  else
242  {
243  uint32 i;
244 
245  for (i = 0; i < snap->nxip; i++)
246  {
247  if (FullTransactionIdEquals(value, snap->xip[i]))
248  return false;
249  }
250  return true;
251  }
252 }
253 
254 /*
255  * helper functions to use StringInfo for pg_snapshot creation.
256  */
257 
258 static StringInfo
260 {
261  pg_snapshot snap;
262  StringInfo buf;
263 
264  snap.xmin = xmin;
265  snap.xmax = xmax;
266  snap.nxip = 0;
267 
268  buf = makeStringInfo();
270  return buf;
271 }
272 
273 static void
275 {
276  pg_snapshot *snap = (pg_snapshot *) buf->data;
277 
278  /* do this before possible realloc */
279  snap->nxip++;
280 
281  appendBinaryStringInfo(buf, &fxid, sizeof(fxid));
282 }
283 
284 static pg_snapshot *
286 {
287  pg_snapshot *snap = (pg_snapshot *) buf->data;
288 
289  SET_VARSIZE(snap, buf->len);
290 
291  /* buf is not needed anymore */
292  buf->data = NULL;
293  pfree(buf);
294 
295  return snap;
296 }
297 
298 /*
299  * parse snapshot from cstring
300  */
301 static pg_snapshot *
302 parse_snapshot(const char *str, Node *escontext)
303 {
304  FullTransactionId xmin;
305  FullTransactionId xmax;
308  const char *str_start = str;
309  char *endp;
310  StringInfo buf;
311 
312  xmin = FullTransactionIdFromU64(strtou64(str, &endp, 10));
313  if (*endp != ':')
314  goto bad_format;
315  str = endp + 1;
316 
317  xmax = FullTransactionIdFromU64(strtou64(str, &endp, 10));
318  if (*endp != ':')
319  goto bad_format;
320  str = endp + 1;
321 
322  /* it should look sane */
323  if (!FullTransactionIdIsValid(xmin) ||
324  !FullTransactionIdIsValid(xmax) ||
325  FullTransactionIdPrecedes(xmax, xmin))
326  goto bad_format;
327 
328  /* allocate buffer */
329  buf = buf_init(xmin, xmax);
330 
331  /* loop over values */
332  while (*str != '\0')
333  {
334  /* read next value */
335  val = FullTransactionIdFromU64(strtou64(str, &endp, 10));
336  str = endp;
337 
338  /* require the input to be in order */
339  if (FullTransactionIdPrecedes(val, xmin) ||
341  FullTransactionIdPrecedes(val, last_val))
342  goto bad_format;
343 
344  /* skip duplicates */
345  if (!FullTransactionIdEquals(val, last_val))
346  buf_add_txid(buf, val);
347  last_val = val;
348 
349  if (*str == ',')
350  str++;
351  else if (*str != '\0')
352  goto bad_format;
353  }
354 
355  return buf_finalize(buf);
356 
357 bad_format:
358  ereturn(escontext, NULL,
359  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
360  errmsg("invalid input syntax for type %s: \"%s\"",
361  "pg_snapshot", str_start)));
362 }
363 
364 /*
365  * pg_current_xact_id() returns xid8
366  *
367  * Return the current toplevel full transaction ID.
368  * If the current transaction does not have one, one is assigned.
369  */
370 Datum
372 {
373  /*
374  * Must prevent during recovery because if an xid is not assigned we try
375  * to assign one, which would fail. Programs already rely on this function
376  * to always return a valid current xid, so we should not change this to
377  * return NULL or similar invalid xid.
378  */
379  PreventCommandDuringRecovery("pg_current_xact_id()");
380 
382 }
383 
384 /*
385  * Same as pg_current_xact_id() but doesn't assign a new xid if there
386  * isn't one yet.
387  */
388 Datum
390 {
392 
393  if (!FullTransactionIdIsValid(topfxid))
394  PG_RETURN_NULL();
395 
397 }
398 
399 /*
400  * pg_current_snapshot() returns pg_snapshot
401  *
402  * Return current snapshot
403  *
404  * Note that only top-transaction XIDs are included in the snapshot.
405  */
406 Datum
408 {
409  pg_snapshot *snap;
410  uint32 nxip,
411  i;
412  Snapshot cur;
414 
416  if (cur == NULL)
417  elog(ERROR, "no active snapshot set");
418 
419  /* allocate */
420  nxip = cur->xcnt;
421  snap = palloc(PG_SNAPSHOT_SIZE(nxip));
422 
423  /* fill */
424  snap->xmin = widen_snapshot_xid(cur->xmin, next_fxid);
425  snap->xmax = widen_snapshot_xid(cur->xmax, next_fxid);
426  snap->nxip = nxip;
427  for (i = 0; i < nxip; i++)
428  snap->xip[i] = widen_snapshot_xid(cur->xip[i], next_fxid);
429 
430  /*
431  * We want them guaranteed to be in ascending order. This also removes
432  * any duplicate xids. Normally, an XID can only be assigned to one
433  * backend, but when preparing a transaction for two-phase commit, there
434  * is a transient state when both the original backend and the dummy
435  * PGPROC entry reserved for the prepared transaction hold the same XID.
436  */
437  sort_snapshot(snap);
438 
439  /* set size after sorting, because it may have removed duplicate xips */
440  SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(snap->nxip));
441 
442  PG_RETURN_POINTER(snap);
443 }
444 
445 /*
446  * pg_snapshot_in(cstring) returns pg_snapshot
447  *
448  * input function for type pg_snapshot
449  */
450 Datum
452 {
453  char *str = PG_GETARG_CSTRING(0);
454  pg_snapshot *snap;
455 
456  snap = parse_snapshot(str, fcinfo->context);
457 
458  PG_RETURN_POINTER(snap);
459 }
460 
461 /*
462  * pg_snapshot_out(pg_snapshot) returns cstring
463  *
464  * output function for type pg_snapshot
465  */
466 Datum
468 {
471  uint32 i;
472 
474 
479 
480  for (i = 0; i < snap->nxip; i++)
481  {
482  if (i > 0)
483  appendStringInfoChar(&str, ',');
485  U64FromFullTransactionId(snap->xip[i]));
486  }
487 
488  PG_RETURN_CSTRING(str.data);
489 }
490 
491 /*
492  * pg_snapshot_recv(internal) returns pg_snapshot
493  *
494  * binary input function for type pg_snapshot
495  *
496  * format: int4 nxip, int8 xmin, int8 xmax, int8 xip
497  */
498 Datum
500 {
502  pg_snapshot *snap;
504  int nxip;
505  int i;
506  FullTransactionId xmin;
507  FullTransactionId xmax;
508 
509  /* load and validate nxip */
510  nxip = pq_getmsgint(buf, 4);
511  if (nxip < 0 || nxip > PG_SNAPSHOT_MAX_NXIP)
512  goto bad_format;
513 
514  xmin = FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
515  xmax = FullTransactionIdFromU64((uint64) pq_getmsgint64(buf));
516  if (!FullTransactionIdIsValid(xmin) ||
517  !FullTransactionIdIsValid(xmax) ||
518  FullTransactionIdPrecedes(xmax, xmin))
519  goto bad_format;
520 
521  snap = palloc(PG_SNAPSHOT_SIZE(nxip));
522  snap->xmin = xmin;
523  snap->xmax = xmax;
524 
525  for (i = 0; i < nxip; i++)
526  {
529 
530  if (FullTransactionIdPrecedes(cur, last) ||
533  goto bad_format;
534 
535  /* skip duplicate xips */
536  if (FullTransactionIdEquals(cur, last))
537  {
538  i--;
539  nxip--;
540  continue;
541  }
542 
543  snap->xip[i] = cur;
544  last = cur;
545  }
546  snap->nxip = nxip;
547  SET_VARSIZE(snap, PG_SNAPSHOT_SIZE(nxip));
548  PG_RETURN_POINTER(snap);
549 
550 bad_format:
551  ereport(ERROR,
552  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
553  errmsg("invalid external pg_snapshot data")));
554  PG_RETURN_POINTER(NULL); /* keep compiler quiet */
555 }
556 
557 /*
558  * pg_snapshot_send(pg_snapshot) returns bytea
559  *
560  * binary output function for type pg_snapshot
561  *
562  * format: int4 nxip, u64 xmin, u64 xmax, u64 xip...
563  */
564 Datum
566 {
569  uint32 i;
570 
572  pq_sendint32(&buf, snap->nxip);
573  pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xmin));
574  pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xmax));
575  for (i = 0; i < snap->nxip; i++)
576  pq_sendint64(&buf, (int64) U64FromFullTransactionId(snap->xip[i]));
578 }
579 
580 /*
581  * pg_visible_in_snapshot(xid8, pg_snapshot) returns bool
582  *
583  * is txid visible in snapshot ?
584  */
585 Datum
587 {
590 
592 }
593 
594 /*
595  * pg_snapshot_xmin(pg_snapshot) returns xid8
596  *
597  * return snapshot's xmin
598  */
599 Datum
601 {
603 
605 }
606 
607 /*
608  * pg_snapshot_xmax(pg_snapshot) returns xid8
609  *
610  * return snapshot's xmax
611  */
612 Datum
614 {
616 
618 }
619 
620 /*
621  * pg_snapshot_xip(pg_snapshot) returns setof xid8
622  *
623  * return in-progress xid8s in snapshot.
624  */
625 Datum
627 {
628  FuncCallContext *fctx;
629  pg_snapshot *snap;
631 
632  /* on first call initialize fctx and get copy of snapshot */
633  if (SRF_IS_FIRSTCALL())
634  {
636 
637  fctx = SRF_FIRSTCALL_INIT();
638 
639  /* make a copy of user snapshot */
641  memcpy(snap, arg, VARSIZE(arg));
642 
643  fctx->user_fctx = snap;
644  }
645 
646  /* return values one-by-one */
647  fctx = SRF_PERCALL_SETUP();
648  snap = fctx->user_fctx;
649  if (fctx->call_cntr < snap->nxip)
650  {
651  value = snap->xip[fctx->call_cntr];
653  }
654  else
655  {
656  SRF_RETURN_DONE(fctx);
657  }
658 }
659 
660 /*
661  * Report the status of a recent transaction ID, or null for wrapped,
662  * truncated away or otherwise too old XIDs.
663  *
664  * The passed epoch-qualified xid is treated as a normal xid, not a
665  * multixact id.
666  *
667  * If it points to a committed subxact the result is the subxact status even
668  * though the parent xact may still be in progress or may have aborted.
669  */
670 Datum
672 {
673  const char *status;
675  TransactionId xid;
676 
677  /*
678  * We must protect against concurrent truncation of clog entries to avoid
679  * an I/O error on SLRU lookup.
680  */
681  LWLockAcquire(XactTruncationLock, LW_SHARED);
682  if (TransactionIdInRecentPast(fxid, &xid))
683  {
685 
686  /*
687  * Like when doing visibility checks on a row, check whether the
688  * transaction is still in progress before looking into the CLOG.
689  * Otherwise we would incorrectly return "committed" for a transaction
690  * that is committing and has already updated the CLOG, but hasn't
691  * removed its XID from the proc array yet. (See comment on that race
692  * condition at the top of heapam_visibility.c)
693  */
694  if (TransactionIdIsInProgress(xid))
695  status = "in progress";
696  else if (TransactionIdDidCommit(xid))
697  status = "committed";
698  else
699  {
700  /* it must have aborted or crashed */
701  status = "aborted";
702  }
703  }
704  else
705  {
706  status = NULL;
707  }
708  LWLockRelease(XactTruncationLock);
709 
710  if (status == NULL)
711  PG_RETURN_NULL();
712  else
714 }
unsigned int uint32
Definition: c.h:506
signed int int32
Definition: c.h:494
#define Assert(condition)
Definition: c.h:858
#define FLEXIBLE_ARRAY_MEMBER
Definition: c.h:398
#define UINT64_FORMAT
Definition: c.h:549
#define strtou64(str, endptr, base)
Definition: c.h:1298
uint32 TransactionId
Definition: c.h:652
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_GETARG_VARLENA_P(n)
Definition: fmgr.h:287
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#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
long val
Definition: informix.c:670
static struct @155 value
int b
Definition: isn.c:70
return false
Definition: isn.c:131
int a
Definition: isn.c:69
int i
Definition: isn.c:73
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1895
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_SHARED
Definition: lwlock.h:115
void pfree(void *pointer)
Definition: mcxt.c:1520
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1180
void * palloc(Size size)
Definition: mcxt.c:1316
void * arg
static char * buf
Definition: pg_test_fsync.c:73
#define qsort(a, b, c, d)
Definition: port.h:449
uintptr_t Datum
Definition: postgres.h:64
#define MAX_BACKENDS
Definition: postmaster.h:95
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:415
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:326
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:453
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:346
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:144
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:152
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:1390
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:770
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:233
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:194
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
StringInfoData * StringInfo
Definition: stringinfo.h:54
void * user_fctx
Definition: funcapi.h:82
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
Definition: nodes.h:129
TransactionId oldestClogXid
Definition: transam.h:253
FullTransactionId xip[FLEXIBLE_ARRAY_MEMBER]
Definition: xid8funcs.c:67
int32 __varsz
Definition: xid8funcs.c:61
FullTransactionId xmax
Definition: xid8funcs.c:65
uint32 nxip
Definition: xid8funcs.c:63
FullTransactionId xmin
Definition: xid8funcs.c:64
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299
#define FullTransactionIdEquals(a, b)
Definition: transam.h:50
#define EpochFromFullTransactionId(x)
Definition: transam.h:47
#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
static FullTransactionId FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
Definition: transam.h:71
#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:441
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279
text * cstring_to_text(const char *s)
Definition: varlena.c:184
FullTransactionId ReadNextFullTransactionId(void)
Definition: varsup.c:288
TransamVariablesData * TransamVariables
Definition: varsup.c:34
static const unsigned __int64 epoch
FullTransactionId GetTopFullTransactionId(void)
Definition: xact.c:480
FullTransactionId GetTopFullTransactionIdIfAny(void)
Definition: xact.c:496
#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:97
Datum pg_snapshot_send(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:565
Datum pg_current_xact_id_if_assigned(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:389
static StringInfo buf_init(FullTransactionId xmin, FullTransactionId xmax)
Definition: xid8funcs.c:259
static bool is_visible_fxid(FullTransactionId value, const pg_snapshot *snap)
Definition: xid8funcs.c:224
static int cmp_fxid(const void *aa, const void *bb)
Definition: xid8funcs.c:190
#define USE_BSEARCH_IF_NXIP_GREATER
Definition: xid8funcs.c:48
Datum pg_snapshot_out(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:467
#define PG_SNAPSHOT_SIZE(nxip)
Definition: xid8funcs.c:70
#define PG_SNAPSHOT_MAX_NXIP
Definition: xid8funcs.c:72
Datum pg_current_xact_id(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:371
Datum pg_snapshot_recv(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:499
static pg_snapshot * parse_snapshot(const char *str, Node *escontext)
Definition: xid8funcs.c:302
Datum pg_snapshot_in(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:451
static pg_snapshot * buf_finalize(StringInfo buf)
Definition: xid8funcs.c:285
Datum pg_xact_status(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:671
Datum pg_current_snapshot(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:407
static void buf_add_txid(StringInfo buf, FullTransactionId fxid)
Definition: xid8funcs.c:274
Datum pg_snapshot_xmin(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:600
Datum pg_snapshot_xip(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:626
static void sort_snapshot(pg_snapshot *snap)
Definition: xid8funcs.c:210
Datum pg_visible_in_snapshot(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:586
StaticAssertDecl(MAX_BACKENDS *2<=PG_SNAPSHOT_MAX_NXIP, "possible overflow in pg_current_snapshot()")
static FullTransactionId widen_snapshot_xid(TransactionId xid, FullTransactionId next_fxid)
Definition: xid8funcs.c:164
Datum pg_snapshot_xmax(PG_FUNCTION_ARGS)
Definition: xid8funcs.c:613