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