#include "postgres.h"
#include "access/transam.h"
#include "access/xact.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "libpq/pqformat.h"
#include "utils/builtins.h"
#include "utils/snapmgr.h"
Go to the source code of this file.
Data Structures | |
struct | TxidSnapshot |
struct | TxidEpoch |
Defines | |
#define | MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF) |
#define | TXID_FMT UINT64_FORMAT |
#define | USE_BSEARCH_IF_NXIP_GREATER 30 |
#define | TXID_SNAPSHOT_SIZE(nxip) (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip)) |
Typedefs | |
typedef uint64 | txid |
Functions | |
static void | load_xid_epoch (TxidEpoch *state) |
static txid | convert_xid (TransactionId xid, const TxidEpoch *state) |
static int | cmp_txid (const void *aa, const void *bb) |
static void | sort_snapshot (TxidSnapshot *snap) |
static bool | is_visible_txid (txid value, const TxidSnapshot *snap) |
static StringInfo | buf_init (txid xmin, txid xmax) |
static void | buf_add_txid (StringInfo buf, txid xid) |
static TxidSnapshot * | buf_finalize (StringInfo buf) |
static txid | str2txid (const char *s, const char **endp) |
static TxidSnapshot * | parse_snapshot (const char *str) |
Datum | txid_current (PG_FUNCTION_ARGS) |
Datum | txid_current_snapshot (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_in (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_out (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_recv (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_send (PG_FUNCTION_ARGS) |
Datum | txid_visible_in_snapshot (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_xmin (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_xmax (PG_FUNCTION_ARGS) |
Datum | txid_snapshot_xip (PG_FUNCTION_ARGS) |
#define MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF) |
Definition at line 34 of file txid.c.
Referenced by str2txid(), and txid_snapshot_recv().
#define TXID_FMT UINT64_FORMAT |
Definition at line 40 of file txid.c.
Referenced by txid_snapshot_out().
#define TXID_SNAPSHOT_SIZE | ( | nxip | ) | (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip)) |
Definition at line 67 of file txid.c.
Referenced by buf_init(), txid_current_snapshot(), and txid_snapshot_recv().
#define USE_BSEARCH_IF_NXIP_GREATER 30 |
Definition at line 46 of file txid.c.
Referenced by is_visible_txid().
static void buf_add_txid | ( | StringInfo | buf, | |
txid | xid | |||
) | [static] |
Definition at line 195 of file txid.c.
References appendBinaryStringInfo(), StringInfoData::data, and TxidSnapshot::nxip.
Referenced by parse_snapshot().
{ TxidSnapshot *snap = (TxidSnapshot *) buf->data; /* do this before possible realloc */ snap->nxip++; appendBinaryStringInfo(buf, (char *) &xid, sizeof(xid)); }
static TxidSnapshot* buf_finalize | ( | StringInfo | buf | ) | [static] |
Definition at line 206 of file txid.c.
References StringInfoData::data, StringInfoData::len, pfree(), and SET_VARSIZE.
Referenced by parse_snapshot().
{ TxidSnapshot *snap = (TxidSnapshot *) buf->data; SET_VARSIZE(snap, buf->len); /* buf is not needed anymore */ buf->data = NULL; pfree(buf); return snap; }
static StringInfo buf_init | ( | txid | xmin, | |
txid | xmax | |||
) | [static] |
Definition at line 180 of file txid.c.
References appendBinaryStringInfo(), buf, makeStringInfo(), TxidSnapshot::nxip, TXID_SNAPSHOT_SIZE, TxidSnapshot::xmax, and TxidSnapshot::xmin.
Referenced by parse_snapshot().
{ TxidSnapshot snap; StringInfo buf; snap.xmin = xmin; snap.xmax = xmax; snap.nxip = 0; buf = makeStringInfo(); appendBinaryStringInfo(buf, (char *) &snap, TXID_SNAPSHOT_SIZE(0)); return buf; }
static int cmp_txid | ( | const void * | aa, | |
const void * | bb | |||
) | [static] |
Definition at line 117 of file txid.c.
Referenced by is_visible_txid(), and sort_snapshot().
static txid convert_xid | ( | TransactionId | xid, | |
const TxidEpoch * | state | |||
) | [static] |
Definition at line 93 of file txid.c.
References TxidEpoch::epoch, epoch, TxidEpoch::last_xid, TransactionIdFollows(), TransactionIdIsNormal, and TransactionIdPrecedes().
Referenced by txid_current(), and txid_current_snapshot().
{ uint64 epoch; /* return special xid's as-is */ if (!TransactionIdIsNormal(xid)) return (txid) xid; /* xid can be on either side when near wrap-around */ epoch = (uint64) state->epoch; if (xid > state->last_xid && TransactionIdPrecedes(xid, state->last_xid)) epoch--; else if (xid < state->last_xid && TransactionIdFollows(xid, state->last_xid)) epoch++; return (epoch << 32) | xid; }
static bool is_visible_txid | ( | txid | value, | |
const TxidSnapshot * | snap | |||
) | [static] |
Definition at line 146 of file txid.c.
References cmp_txid(), i, TxidSnapshot::nxip, USE_BSEARCH_IF_NXIP_GREATER, TxidSnapshot::xip, and TxidSnapshot::xmax.
Referenced by txid_visible_in_snapshot().
{ if (value < snap->xmin) return true; else if (value >= snap->xmax) return false; #ifdef USE_BSEARCH_IF_NXIP_GREATER else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER) { void *res; res = bsearch(&value, snap->xip, snap->nxip, sizeof(txid), cmp_txid); /* if found, transaction is still in progress */ return (res) ? false : true; } #endif else { uint32 i; for (i = 0; i < snap->nxip; i++) { if (value == snap->xip[i]) return false; } return true; } }
static void load_xid_epoch | ( | TxidEpoch * | state | ) | [static] |
Definition at line 84 of file txid.c.
References TxidEpoch::epoch, GetNextXidAndEpoch(), and TxidEpoch::last_xid.
Referenced by txid_current(), and txid_current_snapshot().
{ GetNextXidAndEpoch(&state->last_xid, &state->epoch); }
static TxidSnapshot* parse_snapshot | ( | const char * | str | ) | [static] |
Definition at line 259 of file txid.c.
References buf, buf_add_txid(), buf_finalize(), buf_init(), elog, ERROR, str2txid(), and val.
Referenced by txid_snapshot_in().
{ txid xmin; txid xmax; txid last_val = 0, val; const char *str_start = str; const char *endp; StringInfo buf; xmin = str2txid(str, &endp); if (*endp != ':') goto bad_format; str = endp + 1; xmax = str2txid(str, &endp); if (*endp != ':') goto bad_format; str = endp + 1; /* it should look sane */ if (xmin == 0 || xmax == 0 || xmin > xmax) goto bad_format; /* allocate buffer */ buf = buf_init(xmin, xmax); /* loop over values */ while (*str != '\0') { /* read next value */ val = str2txid(str, &endp); str = endp; /* require the input to be in order */ if (val < xmin || val >= xmax || val <= last_val) goto bad_format; buf_add_txid(buf, val); last_val = val; if (*str == ',') str++; else if (*str != '\0') goto bad_format; } return buf_finalize(buf); bad_format: elog(ERROR, "invalid input for txid_snapshot: \"%s\"", str_start); return NULL; }
static void sort_snapshot | ( | TxidSnapshot * | snap | ) | [static] |
Definition at line 136 of file txid.c.
References cmp_txid(), TxidSnapshot::nxip, qsort, and TxidSnapshot::xip.
Referenced by txid_current_snapshot().
static txid str2txid | ( | const char * | s, | |
const char ** | endp | |||
) | [static] |
Definition at line 225 of file txid.c.
Referenced by parse_snapshot().
{ txid val = 0; txid cutoff = MAX_TXID / 10; txid cutlim = MAX_TXID % 10; for (; *s; s++) { unsigned d; if (*s < '0' || *s > '9') break; d = *s - '0'; /* * check for overflow */ if (val > cutoff || (val == cutoff && d > cutlim)) { val = 0; break; } val = val * 10 + d; } if (endp) *endp = s; return val; }
Datum txid_current | ( | PG_FUNCTION_ARGS | ) |
Definition at line 328 of file txid.c.
References convert_xid(), GetTopTransactionId(), load_xid_epoch(), PG_RETURN_INT64, PreventCommandDuringRecovery(), and val.
{ txid val; TxidEpoch state; /* * Must prevent during recovery because if an xid is not assigned we try * to assign one, which would fail. Programs already rely on this function * to always return a valid current xid, so we should not change this to * return NULL or similar invalid xid. */ PreventCommandDuringRecovery("txid_current()"); load_xid_epoch(&state); val = convert_xid(GetTopTransactionId(), &state); PG_RETURN_INT64(val); }
Datum txid_current_snapshot | ( | PG_FUNCTION_ARGS | ) |
Definition at line 356 of file txid.c.
References convert_xid(), cur, elog, ERROR, GetActiveSnapshot(), i, load_xid_epoch(), NULL, TxidSnapshot::nxip, palloc(), PG_RETURN_POINTER, SET_VARSIZE, sort_snapshot(), TXID_SNAPSHOT_SIZE, SnapshotData::xcnt, SnapshotData::xip, TxidSnapshot::xip, SnapshotData::xmax, TxidSnapshot::xmax, SnapshotData::xmin, and TxidSnapshot::xmin.
{ TxidSnapshot *snap; uint32 nxip, i, size; TxidEpoch state; Snapshot cur; cur = GetActiveSnapshot(); if (cur == NULL) elog(ERROR, "no active snapshot set"); load_xid_epoch(&state); /* allocate */ nxip = cur->xcnt; size = TXID_SNAPSHOT_SIZE(nxip); snap = palloc(size); SET_VARSIZE(snap, size); /* fill */ snap->xmin = convert_xid(cur->xmin, &state); snap->xmax = convert_xid(cur->xmax, &state); snap->nxip = nxip; for (i = 0; i < nxip; i++) snap->xip[i] = convert_xid(cur->xip[i], &state); /* we want them guaranteed to be in ascending order */ sort_snapshot(snap); PG_RETURN_POINTER(snap); }
Datum txid_snapshot_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 396 of file txid.c.
References parse_snapshot(), PG_GETARG_CSTRING, and PG_RETURN_POINTER.
{ char *str = PG_GETARG_CSTRING(0); TxidSnapshot *snap; snap = parse_snapshot(str); PG_RETURN_POINTER(snap); }
Datum txid_snapshot_out | ( | PG_FUNCTION_ARGS | ) |
Definition at line 412 of file txid.c.
References appendStringInfo(), appendStringInfoChar(), StringInfoData::data, i, initStringInfo(), TxidSnapshot::nxip, PG_GETARG_VARLENA_P, PG_RETURN_CSTRING, TXID_FMT, TxidSnapshot::xip, TxidSnapshot::xmax, and TxidSnapshot::xmin.
{ TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); StringInfoData str; uint32 i; initStringInfo(&str); appendStringInfo(&str, TXID_FMT ":", snap->xmin); appendStringInfo(&str, TXID_FMT ":", snap->xmax); for (i = 0; i < snap->nxip; i++) { if (i > 0) appendStringInfoChar(&str, ','); appendStringInfo(&str, TXID_FMT, snap->xip[i]); } PG_RETURN_CSTRING(str.data); }
Datum txid_snapshot_recv | ( | PG_FUNCTION_ARGS | ) |
Definition at line 441 of file txid.c.
References buf, cur, StringInfoData::cursor, elog, ERROR, i, StringInfoData::len, MAX_TXID, TxidSnapshot::nxip, palloc(), PG_GETARG_POINTER, PG_RETURN_POINTER, pq_getmsgint(), pq_getmsgint64(), SET_VARSIZE, TXID_SNAPSHOT_SIZE, TxidSnapshot::xip, TxidSnapshot::xmax, and TxidSnapshot::xmin.
{ StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); TxidSnapshot *snap; txid last = 0; int nxip; int i; int avail; int expect; txid xmin, xmax; /* * load nxip and check for nonsense. * * (nxip > avail) check is against int overflows in 'expect'. */ nxip = pq_getmsgint(buf, 4); avail = buf->len - buf->cursor; expect = 8 + 8 + nxip * 8; if (nxip < 0 || nxip > avail || expect > avail) goto bad_format; xmin = pq_getmsgint64(buf); xmax = pq_getmsgint64(buf); if (xmin == 0 || xmax == 0 || xmin > xmax || xmax > MAX_TXID) goto bad_format; snap = palloc(TXID_SNAPSHOT_SIZE(nxip)); snap->xmin = xmin; snap->xmax = xmax; snap->nxip = nxip; SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip)); for (i = 0; i < nxip; i++) { txid cur = pq_getmsgint64(buf); if (cur <= last || cur < xmin || cur >= xmax) goto bad_format; snap->xip[i] = cur; last = cur; } PG_RETURN_POINTER(snap); bad_format: elog(ERROR, "invalid snapshot data"); return (Datum) NULL; }
Datum txid_snapshot_send | ( | PG_FUNCTION_ARGS | ) |
Definition at line 499 of file txid.c.
References buf, i, TxidSnapshot::nxip, PG_GETARG_VARLENA_P, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint(), pq_sendint64(), TxidSnapshot::xip, TxidSnapshot::xmax, and TxidSnapshot::xmin.
{ TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); StringInfoData buf; uint32 i; pq_begintypsend(&buf); pq_sendint(&buf, snap->nxip, 4); pq_sendint64(&buf, snap->xmin); pq_sendint64(&buf, snap->xmax); for (i = 0; i < snap->nxip; i++) pq_sendint64(&buf, snap->xip[i]); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); }
Datum txid_snapshot_xip | ( | PG_FUNCTION_ARGS | ) |
Definition at line 560 of file txid.c.
References arg, FuncCallContext::call_cntr, Int64GetDatum(), MemoryContextAlloc(), FuncCallContext::multi_call_memory_ctx, TxidSnapshot::nxip, PG_GETARG_VARLENA_P, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, FuncCallContext::user_fctx, value, VARSIZE, and TxidSnapshot::xip.
{ FuncCallContext *fctx; TxidSnapshot *snap; txid value; /* on first call initialize snap_state and get copy of snapshot */ if (SRF_IS_FIRSTCALL()) { TxidSnapshot *arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); fctx = SRF_FIRSTCALL_INIT(); /* make a copy of user snapshot */ snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg)); memcpy(snap, arg, VARSIZE(arg)); fctx->user_fctx = snap; } /* return values one-by-one */ fctx = SRF_PERCALL_SETUP(); snap = fctx->user_fctx; if (fctx->call_cntr < snap->nxip) { value = snap->xip[fctx->call_cntr]; SRF_RETURN_NEXT(fctx, Int64GetDatum(value)); } else { SRF_RETURN_DONE(fctx); } }
Datum txid_snapshot_xmax | ( | PG_FUNCTION_ARGS | ) |
Definition at line 547 of file txid.c.
References PG_GETARG_VARLENA_P, PG_RETURN_INT64, and TxidSnapshot::xmax.
{ TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); PG_RETURN_INT64(snap->xmax); }
Datum txid_snapshot_xmin | ( | PG_FUNCTION_ARGS | ) |
Definition at line 534 of file txid.c.
References PG_GETARG_VARLENA_P, PG_RETURN_INT64, and TxidSnapshot::xmin.
{ TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0); PG_RETURN_INT64(snap->xmin); }
Datum txid_visible_in_snapshot | ( | PG_FUNCTION_ARGS | ) |
Definition at line 520 of file txid.c.
References is_visible_txid(), PG_GETARG_INT64, PG_GETARG_VARLENA_P, PG_RETURN_BOOL, and value.
{ txid value = PG_GETARG_INT64(0); TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1); PG_RETURN_BOOL(is_visible_txid(value, snap)); }