PostgreSQL Source Code  git master
txid.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  * txid.c
3  *
4  * Export internal transaction IDs to user level.
5  *
6  * Note that only top-level transaction IDs are ever converted to TXID.
7  * This is important because TXIDs 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  *
13  * Copyright (c) 2003-2020, PostgreSQL Global Development Group
14  * Author: Jan Wieck, Afilias USA INC.
15  * 64-bit txids: Marko Kreen, Skype Technologies
16  *
17  * src/backend/utils/adt/txid.c
18  *
19  *-------------------------------------------------------------------------
20  */
21 
22 #include "postgres.h"
23 
24 #include "access/clog.h"
25 #include "access/transam.h"
26 #include "access/xact.h"
27 #include "access/xlog.h"
28 #include "funcapi.h"
29 #include "lib/qunique.h"
30 #include "libpq/pqformat.h"
31 #include "miscadmin.h"
32 #include "postmaster/postmaster.h"
33 #include "storage/lwlock.h"
34 #include "utils/builtins.h"
35 #include "utils/memutils.h"
36 #include "utils/snapmgr.h"
37 
38 /* txid will be signed int8 in database, so must limit to 63 bits */
39 #define MAX_TXID ((uint64) PG_INT64_MAX)
40 
41 /* Use unsigned variant internally */
42 typedef uint64 txid;
43 
44 /* sprintf format code for uint64 */
45 #define TXID_FMT UINT64_FORMAT
46 
47 /*
48  * If defined, use bsearch() function for searching for txids in snapshots
49  * that have more than the specified number of values.
50  */
51 #define USE_BSEARCH_IF_NXIP_GREATER 30
52 
53 
54 /*
55  * Snapshot containing 8byte txids.
56  */
57 typedef struct
58 {
59  /*
60  * 4-byte length hdr, should not be touched directly.
61  *
62  * Explicit embedding is ok as we want always correct alignment anyway.
63  */
65 
66  uint32 nxip; /* number of txids in xip array */
69  /* in-progress txids, xmin <= xip[i] < xmax: */
70  txid xip[FLEXIBLE_ARRAY_MEMBER];
71 } TxidSnapshot;
72 
73 #define TXID_SNAPSHOT_SIZE(nxip) \
74  (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
75 #define TXID_SNAPSHOT_MAX_NXIP \
76  ((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid))
77 
78 /*
79  * Epoch values from xact.c
80  */
81 typedef struct
82 {
85 } TxidEpoch;
86 
87 
88 /*
89  * Fetch epoch data from xact.c.
90  */
91 static void
93 {
95 
96  state->last_xid = XidFromFullTransactionId(fullXid);
97  state->epoch = EpochFromFullTransactionId(fullXid);
98 }
99 
100 /*
101  * Helper to get a TransactionId from a 64-bit xid with wraparound detection.
102  *
103  * It is an ERROR if the xid is in the future. Otherwise, returns true if
104  * the transaction is still new enough that we can determine whether it
105  * committed and false otherwise. If *extracted_xid is not NULL, it is set
106  * to the low 32 bits of the transaction ID (i.e. the actual XID, without the
107  * epoch).
108  *
109  * The caller must hold CLogTruncationLock since it's dealing with arbitrary
110  * XIDs, and must continue to hold it until it's done with any clog lookups
111  * relating to those XIDs.
112  */
113 static bool
114 TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid)
115 {
116  uint32 xid_epoch = (uint32) (xid_with_epoch >> 32);
117  TransactionId xid = (TransactionId) xid_with_epoch;
118  uint32 now_epoch;
119  TransactionId now_epoch_next_xid;
120  FullTransactionId now_fullxid;
121 
122  now_fullxid = ReadNextFullTransactionId();
123  now_epoch_next_xid = XidFromFullTransactionId(now_fullxid);
124  now_epoch = EpochFromFullTransactionId(now_fullxid);
125 
126  if (extracted_xid != NULL)
127  *extracted_xid = xid;
128 
129  if (!TransactionIdIsValid(xid))
130  return false;
131 
132  /* For non-normal transaction IDs, we can ignore the epoch. */
133  if (!TransactionIdIsNormal(xid))
134  return true;
135 
136  /* If the transaction ID is in the future, throw an error. */
137  if (xid_with_epoch >= U64FromFullTransactionId(now_fullxid))
138  ereport(ERROR,
139  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
140  errmsg("transaction ID %s is in the future",
141  psprintf(UINT64_FORMAT, xid_with_epoch))));
142 
143  /*
144  * ShmemVariableCache->oldestClogXid is protected by CLogTruncationLock,
145  * but we don't acquire that lock here. Instead, we require the caller to
146  * acquire it, because the caller is presumably going to look up the
147  * returned XID. If we took and released the lock within this function, a
148  * CLOG truncation could occur before the caller finished with the XID.
149  */
150  Assert(LWLockHeldByMe(CLogTruncationLock));
151 
152  /*
153  * If the transaction ID has wrapped around, it's definitely too old to
154  * determine the commit status. Otherwise, we can compare it to
155  * ShmemVariableCache->oldestClogXid to determine whether the relevant
156  * CLOG entry is guaranteed to still exist.
157  */
158  if (xid_epoch + 1 < now_epoch
159  || (xid_epoch + 1 == now_epoch && xid < now_epoch_next_xid)
161  return false;
162 
163  return true;
164 }
165 
166 /*
167  * do a TransactionId -> txid conversion for an XID near the given epoch
168  */
169 static txid
171 {
172  uint64 epoch;
173 
174  /* return special xid's as-is */
175  if (!TransactionIdIsNormal(xid))
176  return (txid) xid;
177 
178  /* xid can be on either side when near wrap-around */
179  epoch = (uint64) state->epoch;
180  if (xid > state->last_xid &&
181  TransactionIdPrecedes(xid, state->last_xid))
182  epoch--;
183  else if (xid < state->last_xid &&
184  TransactionIdFollows(xid, state->last_xid))
185  epoch++;
186 
187  return (epoch << 32) | xid;
188 }
189 
190 /*
191  * txid comparator for qsort/bsearch
192  */
193 static int
194 cmp_txid(const void *aa, const void *bb)
195 {
196  txid a = *(const txid *) aa;
197  txid b = *(const txid *) bb;
198 
199  if (a < b)
200  return -1;
201  if (a > b)
202  return 1;
203  return 0;
204 }
205 
206 /*
207  * Sort a snapshot's txids, so we can use bsearch() later. Also remove
208  * any duplicates.
209  *
210  * For consistency of on-disk representation, we always sort even if bsearch
211  * will not be used.
212  */
213 static void
215 {
216  if (snap->nxip > 1)
217  {
218  qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid);
219  snap->nxip = qunique(snap->xip, snap->nxip, sizeof(txid), cmp_txid);
220  }
221 }
222 
223 /*
224  * check txid visibility.
225  */
226 static bool
228 {
229  if (value < snap->xmin)
230  return true;
231  else if (value >= snap->xmax)
232  return false;
233 #ifdef USE_BSEARCH_IF_NXIP_GREATER
234  else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
235  {
236  void *res;
237 
238  res = bsearch(&value, snap->xip, snap->nxip, sizeof(txid), cmp_txid);
239  /* if found, transaction is still in progress */
240  return (res) ? false : true;
241  }
242 #endif
243  else
244  {
245  uint32 i;
246 
247  for (i = 0; i < snap->nxip; i++)
248  {
249  if (value == snap->xip[i])
250  return false;
251  }
252  return true;
253  }
254 }
255 
256 /*
257  * helper functions to use StringInfo for TxidSnapshot creation.
258  */
259 
260 static StringInfo
261 buf_init(txid xmin, txid xmax)
262 {
263  TxidSnapshot snap;
264  StringInfo buf;
265 
266  snap.xmin = xmin;
267  snap.xmax = xmax;
268  snap.nxip = 0;
269 
270  buf = makeStringInfo();
271  appendBinaryStringInfo(buf, (char *) &snap, TXID_SNAPSHOT_SIZE(0));
272  return buf;
273 }
274 
275 static void
277 {
278  TxidSnapshot *snap = (TxidSnapshot *) buf->data;
279 
280  /* do this before possible realloc */
281  snap->nxip++;
282 
283  appendBinaryStringInfo(buf, (char *) &xid, sizeof(xid));
284 }
285 
286 static TxidSnapshot *
288 {
289  TxidSnapshot *snap = (TxidSnapshot *) buf->data;
290 
291  SET_VARSIZE(snap, buf->len);
292 
293  /* buf is not needed anymore */
294  buf->data = NULL;
295  pfree(buf);
296 
297  return snap;
298 }
299 
300 /*
301  * simple number parser.
302  *
303  * We return 0 on error, which is invalid value for txid.
304  */
305 static txid
306 str2txid(const char *s, const char **endp)
307 {
308  txid val = 0;
309  txid cutoff = MAX_TXID / 10;
310  txid cutlim = MAX_TXID % 10;
311 
312  for (; *s; s++)
313  {
314  unsigned d;
315 
316  if (*s < '0' || *s > '9')
317  break;
318  d = *s - '0';
319 
320  /*
321  * check for overflow
322  */
323  if (val > cutoff || (val == cutoff && d > cutlim))
324  {
325  val = 0;
326  break;
327  }
328 
329  val = val * 10 + d;
330  }
331  if (endp)
332  *endp = s;
333  return val;
334 }
335 
336 /*
337  * parse snapshot from cstring
338  */
339 static TxidSnapshot *
340 parse_snapshot(const char *str)
341 {
342  txid xmin;
343  txid xmax;
344  txid last_val = 0,
345  val;
346  const char *str_start = str;
347  const char *endp;
348  StringInfo buf;
349 
350  xmin = str2txid(str, &endp);
351  if (*endp != ':')
352  goto bad_format;
353  str = endp + 1;
354 
355  xmax = str2txid(str, &endp);
356  if (*endp != ':')
357  goto bad_format;
358  str = endp + 1;
359 
360  /* it should look sane */
361  if (xmin == 0 || xmax == 0 || xmin > xmax)
362  goto bad_format;
363 
364  /* allocate buffer */
365  buf = buf_init(xmin, xmax);
366 
367  /* loop over values */
368  while (*str != '\0')
369  {
370  /* read next value */
371  val = str2txid(str, &endp);
372  str = endp;
373 
374  /* require the input to be in order */
375  if (val < xmin || val >= xmax || val < last_val)
376  goto bad_format;
377 
378  /* skip duplicates */
379  if (val != last_val)
380  buf_add_txid(buf, val);
381  last_val = val;
382 
383  if (*str == ',')
384  str++;
385  else if (*str != '\0')
386  goto bad_format;
387  }
388 
389  return buf_finalize(buf);
390 
391 bad_format:
392  ereport(ERROR,
393  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
394  errmsg("invalid input syntax for type %s: \"%s\"",
395  "txid_snapshot", str_start)));
396  return NULL; /* keep compiler quiet */
397 }
398 
399 /*
400  * Public functions.
401  *
402  * txid_current() and txid_current_snapshot() are the only ones that
403  * communicate with core xid machinery. All the others work on data
404  * returned by them.
405  */
406 
407 /*
408  * txid_current() returns int8
409  *
410  * Return the current toplevel transaction ID as TXID
411  * If the current transaction does not have one, one is assigned.
412  *
413  * This value has the epoch as the high 32 bits and the 32-bit xid
414  * as the low 32 bits.
415  */
416 Datum
418 {
419  txid val;
421 
422  /*
423  * Must prevent during recovery because if an xid is not assigned we try
424  * to assign one, which would fail. Programs already rely on this function
425  * to always return a valid current xid, so we should not change this to
426  * return NULL or similar invalid xid.
427  */
428  PreventCommandDuringRecovery("txid_current()");
429 
430  load_xid_epoch(&state);
431 
432  val = convert_xid(GetTopTransactionId(), &state);
433 
434  PG_RETURN_INT64(val);
435 }
436 
437 /*
438  * Same as txid_current() but doesn't assign a new xid if there isn't one
439  * yet.
440  */
441 Datum
443 {
444  txid val;
447 
448  if (topxid == InvalidTransactionId)
449  PG_RETURN_NULL();
450 
451  load_xid_epoch(&state);
452 
453  val = convert_xid(topxid, &state);
454 
455  PG_RETURN_INT64(val);
456 }
457 
458 /*
459  * txid_current_snapshot() returns txid_snapshot
460  *
461  * Return current snapshot in TXID format
462  *
463  * Note that only top-transaction XIDs are included in the snapshot.
464  */
465 Datum
467 {
468  TxidSnapshot *snap;
469  uint32 nxip,
470  i;
472  Snapshot cur;
473 
474  cur = GetActiveSnapshot();
475  if (cur == NULL)
476  elog(ERROR, "no active snapshot set");
477 
478  load_xid_epoch(&state);
479 
480  /*
481  * Compile-time limits on the procarray (MAX_BACKENDS processes plus
482  * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large.
483  */
485  "possible overflow in txid_current_snapshot()");
486 
487  /* allocate */
488  nxip = cur->xcnt;
489  snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
490 
491  /* fill */
492  snap->xmin = convert_xid(cur->xmin, &state);
493  snap->xmax = convert_xid(cur->xmax, &state);
494  snap->nxip = nxip;
495  for (i = 0; i < nxip; i++)
496  snap->xip[i] = convert_xid(cur->xip[i], &state);
497 
498  /*
499  * We want them guaranteed to be in ascending order. This also removes
500  * any duplicate xids. Normally, an XID can only be assigned to one
501  * backend, but when preparing a transaction for two-phase commit, there
502  * is a transient state when both the original backend and the dummy
503  * PGPROC entry reserved for the prepared transaction hold the same XID.
504  */
505  sort_snapshot(snap);
506 
507  /* set size after sorting, because it may have removed duplicate xips */
508  SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(snap->nxip));
509 
510  PG_RETURN_POINTER(snap);
511 }
512 
513 /*
514  * txid_snapshot_in(cstring) returns txid_snapshot
515  *
516  * input function for type txid_snapshot
517  */
518 Datum
520 {
521  char *str = PG_GETARG_CSTRING(0);
522  TxidSnapshot *snap;
523 
524  snap = parse_snapshot(str);
525 
526  PG_RETURN_POINTER(snap);
527 }
528 
529 /*
530  * txid_snapshot_out(txid_snapshot) returns cstring
531  *
532  * output function for type txid_snapshot
533  */
534 Datum
536 {
539  uint32 i;
540 
541  initStringInfo(&str);
542 
543  appendStringInfo(&str, TXID_FMT ":", snap->xmin);
544  appendStringInfo(&str, TXID_FMT ":", snap->xmax);
545 
546  for (i = 0; i < snap->nxip; i++)
547  {
548  if (i > 0)
549  appendStringInfoChar(&str, ',');
550  appendStringInfo(&str, TXID_FMT, snap->xip[i]);
551  }
552 
553  PG_RETURN_CSTRING(str.data);
554 }
555 
556 /*
557  * txid_snapshot_recv(internal) returns txid_snapshot
558  *
559  * binary input function for type txid_snapshot
560  *
561  * format: int4 nxip, int8 xmin, int8 xmax, int8 xip
562  */
563 Datum
565 {
567  TxidSnapshot *snap;
568  txid last = 0;
569  int nxip;
570  int i;
571  txid xmin,
572  xmax;
573 
574  /* load and validate nxip */
575  nxip = pq_getmsgint(buf, 4);
576  if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
577  goto bad_format;
578 
579  xmin = pq_getmsgint64(buf);
580  xmax = pq_getmsgint64(buf);
581  if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID)
582  goto bad_format;
583 
584  snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
585  snap->xmin = xmin;
586  snap->xmax = xmax;
587 
588  for (i = 0; i < nxip; i++)
589  {
590  txid cur = pq_getmsgint64(buf);
591 
592  if (cur < last || cur < xmin || cur >= xmax)
593  goto bad_format;
594 
595  /* skip duplicate xips */
596  if (cur == last)
597  {
598  i--;
599  nxip--;
600  continue;
601  }
602 
603  snap->xip[i] = cur;
604  last = cur;
605  }
606  snap->nxip = nxip;
607  SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip));
608  PG_RETURN_POINTER(snap);
609 
610 bad_format:
611  ereport(ERROR,
612  (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
613  errmsg("invalid external txid_snapshot data")));
614  PG_RETURN_POINTER(NULL); /* keep compiler quiet */
615 }
616 
617 /*
618  * txid_snapshot_send(txid_snapshot) returns bytea
619  *
620  * binary output function for type txid_snapshot
621  *
622  * format: int4 nxip, int8 xmin, int8 xmax, int8 xip
623  */
624 Datum
626 {
629  uint32 i;
630 
631  pq_begintypsend(&buf);
632  pq_sendint32(&buf, snap->nxip);
633  pq_sendint64(&buf, snap->xmin);
634  pq_sendint64(&buf, snap->xmax);
635  for (i = 0; i < snap->nxip; i++)
636  pq_sendint64(&buf, snap->xip[i]);
638 }
639 
640 /*
641  * txid_visible_in_snapshot(int8, txid_snapshot) returns bool
642  *
643  * is txid visible in snapshot ?
644  */
645 Datum
647 {
650 
651  PG_RETURN_BOOL(is_visible_txid(value, snap));
652 }
653 
654 /*
655  * txid_snapshot_xmin(txid_snapshot) returns int8
656  *
657  * return snapshot's xmin
658  */
659 Datum
661 {
663 
664  PG_RETURN_INT64(snap->xmin);
665 }
666 
667 /*
668  * txid_snapshot_xmax(txid_snapshot) returns int8
669  *
670  * return snapshot's xmax
671  */
672 Datum
674 {
676 
677  PG_RETURN_INT64(snap->xmax);
678 }
679 
680 /*
681  * txid_snapshot_xip(txid_snapshot) returns setof int8
682  *
683  * return in-progress TXIDs in snapshot.
684  */
685 Datum
687 {
688  FuncCallContext *fctx;
689  TxidSnapshot *snap;
690  txid value;
691 
692  /* on first call initialize fctx and get copy of snapshot */
693  if (SRF_IS_FIRSTCALL())
694  {
696 
697  fctx = SRF_FIRSTCALL_INIT();
698 
699  /* make a copy of user snapshot */
701  memcpy(snap, arg, VARSIZE(arg));
702 
703  fctx->user_fctx = snap;
704  }
705 
706  /* return values one-by-one */
707  fctx = SRF_PERCALL_SETUP();
708  snap = fctx->user_fctx;
709  if (fctx->call_cntr < snap->nxip)
710  {
711  value = snap->xip[fctx->call_cntr];
712  SRF_RETURN_NEXT(fctx, Int64GetDatum(value));
713  }
714  else
715  {
716  SRF_RETURN_DONE(fctx);
717  }
718 }
719 
720 /*
721  * Report the status of a recent transaction ID, or null for wrapped,
722  * truncated away or otherwise too old XIDs.
723  *
724  * The passed epoch-qualified xid is treated as a normal xid, not a
725  * multixact id.
726  *
727  * If it points to a committed subxact the result is the subxact status even
728  * though the parent xact may still be in progress or may have aborted.
729  */
730 Datum
732 {
733  const char *status;
734  uint64 xid_with_epoch = PG_GETARG_INT64(0);
735  TransactionId xid;
736 
737  /*
738  * We must protect against concurrent truncation of clog entries to avoid
739  * an I/O error on SLRU lookup.
740  */
741  LWLockAcquire(CLogTruncationLock, LW_SHARED);
742  if (TransactionIdInRecentPast(xid_with_epoch, &xid))
743  {
745 
747  status = "in progress";
748  else if (TransactionIdDidCommit(xid))
749  status = "committed";
750  else if (TransactionIdDidAbort(xid))
751  status = "aborted";
752  else
753  {
754  /*
755  * The xact is not marked as either committed or aborted in clog.
756  *
757  * It could be a transaction that ended without updating clog or
758  * writing an abort record due to a crash. We can safely assume
759  * it's aborted if it isn't committed and is older than our
760  * snapshot xmin.
761  *
762  * Otherwise it must be in-progress (or have been at the time we
763  * checked commit/abort status).
764  */
765  if (TransactionIdPrecedes(xid, GetActiveSnapshot()->xmin))
766  status = "aborted";
767  else
768  status = "in progress";
769  }
770  }
771  else
772  {
773  status = NULL;
774  }
775  LWLockRelease(CLogTruncationLock);
776 
777  if (status == NULL)
778  PG_RETURN_NULL();
779  else
781 }
static void load_xid_epoch(TxidEpoch *state)
Definition: txid.c:92
uint64 call_cntr
Definition: funcapi.h:65
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
txid xip[FLEXIBLE_ARRAY_MEMBER]
Definition: txid.c:70
int32 __varsz
Definition: txid.c:64
static void buf_add_txid(StringInfo buf, txid xid)
Definition: txid.c:276
Definition: txid.c:81
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:514
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:853
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1842
static TxidSnapshot * buf_finalize(StringInfo buf)
Definition: txid.c:287
#define VARSIZE(PTR)
Definition: postgres.h:303
#define PG_RETURN_INT64(x)
Definition: fmgr.h:357
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:282
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
static void sort_snapshot(TxidSnapshot *snap)
Definition: txid.c:214
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
StringInfo makeStringInfo(void)
Definition: stringinfo.c:41
StringInfoData * StringInfo
Definition: stringinfo.h:44
#define USE_BSEARCH_IF_NXIP_GREATER
Definition: txid.c:51
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
static struct @145 value
struct cursor * cur
Definition: ecpg.c:28
Datum txid_snapshot_xip(PG_FUNCTION_ARGS)
Definition: txid.c:686
int errcode(int sqlerrcode)
Definition: elog.c:608
Datum txid_snapshot_xmin(PG_FUNCTION_ARGS)
Definition: txid.c:660
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:271
#define false
Definition: c.h:317
TransactionId GetTopTransactionId(void)
Definition: xact.c:394
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:360
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:153
txid xmin
Definition: txid.c:67
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
TransactionId last_xid
Definition: txid.c:83
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:286
signed int int32
Definition: c.h:347
#define XidFromFullTransactionId(x)
Definition: transam.h:48
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1726
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:288
uint64 txid
Definition: txid.c:42
Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS)
Definition: txid.c:646
static void pq_sendint32(StringInfo buf, uint32 i)
Definition: pqformat.h:145
Datum txid_snapshot_recv(PG_FUNCTION_ARGS)
Definition: txid.c:564
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:849
static txid convert_xid(TransactionId xid, const TxidEpoch *state)
Definition: txid.c:170
#define TXID_FMT
Definition: txid.c:45
void pfree(void *pointer)
Definition: mcxt.c:1056
#define PG_GETARG_VARLENA_P(n)
Definition: fmgr.h:281
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define ERROR
Definition: elog.h:43
void PreventCommandDuringRecovery(const char *cmdname)
Definition: utility.c:442
#define MAX_BACKENDS
Definition: postmaster.h:75
static TxidSnapshot * parse_snapshot(const char *str)
Definition: txid.c:340
static bool TransactionIdInRecentPast(uint64 xid_with_epoch, TransactionId *extracted_xid)
Definition: txid.c:114
Datum txid_current(PG_FUNCTION_ARGS)
Definition: txid.c:417
static char * buf
Definition: pg_test_fsync.c:67
TransactionId oldestClogXid
Definition: transam.h:188
VariableCache ShmemVariableCache
Definition: varsup.c:34
static int cmp_txid(const void *aa, const void *bb)
Definition: txid.c:194
#define InvalidTransactionId
Definition: transam.h:31
unsigned int uint32
Definition: c.h:359
TransactionId xmax
Definition: snapshot.h:158
TransactionId xmin
Definition: snapshot.h:157
Datum txid_snapshot_xmax(PG_FUNCTION_ARGS)
Definition: txid.c:673
TransactionId GetTopTransactionIdIfAny(void)
Definition: xact.c:409
static bool is_visible_txid(txid value, const TxidSnapshot *snap)
Definition: txid.c:227
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1699
uint32 epoch
Definition: txid.c:84
static StringInfo buf_init(txid xmin, txid xmax)
Definition: txid.c:261
#define ereport(elevel, rest)
Definition: elog.h:141
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
Datum txid_current_snapshot(PG_FUNCTION_ARGS)
Definition: txid.c:466
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
TransactionId * xip
Definition: snapshot.h:168
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
static txid str2txid(const char *s, const char **endp)
Definition: txid.c:306
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
uintptr_t Datum
Definition: postgres.h:367
#define TXID_SNAPSHOT_SIZE(nxip)
Definition: txid.c:73
#define EpochFromFullTransactionId(x)
Definition: transam.h:47
Datum txid_snapshot_out(PG_FUNCTION_ARGS)
Definition: txid.c:535
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:361
text * cstring_to_text(const char *s)
Definition: varlena.c:171
#define Assert(condition)
Definition: c.h:739
Definition: regguts.h:298
Datum txid_status(PG_FUNCTION_ARGS)
Definition: txid.c:731
#define U64FromFullTransactionId(x)
Definition: transam.h:49
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:352
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1122
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
Definition: qunique.h:21
#define MAX_TXID
Definition: txid.c:39
void * user_fctx
Definition: funcapi.h:82
Datum txid_snapshot_send(PG_FUNCTION_ARGS)
Definition: txid.c:625
uint32 xcnt
Definition: snapshot.h:169
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:796
Datum txid_current_if_assigned(PG_FUNCTION_ARGS)
Definition: txid.c:442
#define elog(elevel,...)
Definition: elog.h:228
static const unsigned __int64 epoch
Definition: gettimeofday.c:34
int i
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:455
uint32 nxip
Definition: txid.c:66
void * arg
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:272
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition: pqformat.c:417
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
txid xmax
Definition: txid.c:68
#define qsort(a, b, c, d)
Definition: port.h:491
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
#define TXID_SNAPSHOT_MAX_NXIP
Definition: txid.c:75
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define PG_GETARG_INT64(n)
Definition: fmgr.h:277
#define UINT64_FORMAT
Definition: c.h:402
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:335
Datum txid_snapshot_in(PG_FUNCTION_ARGS)
Definition: txid.c:519
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:306
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:284