/* * txid_snapshot_recv(internal) returns txid_snapshot * * binary input function for type txid_snapshot * * format: int4 nxip, int8 xmin, int8 xmax, int8 xip */ Datum txid_snapshot_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); TxidSnapshot *snap; txid last = 0; int nxip; int i; txid xmin, xmax; /* load and validate nxip */ nxip = pq_getmsgint(buf, 4); if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP) 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; for (i = 0; i < nxip; i++) { txid cur = pq_getmsgint64(buf); if (cur < last || cur < xmin || cur >= xmax) goto bad_format; /* skip duplicate xips */ if (cur == last) { i--; nxip--; continue; } snap->xip[i] = cur; last = cur; } snap->nxip = nxip; SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip)); PG_RETURN_POINTER(snap); bad_format: ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("invalid external txid_snapshot data"))); PG_RETURN_POINTER(NULL); /* keep compiler quiet */ }
/* * txid_snapshot_recv(internal) returns txid_snapshot * * binary input function for type txid_snapshot * * format: int4 nxip, int8 xmin, int8 xmax, int8 xip */ Datum txid_snapshot_recv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); TxidSnapshot *snap; txid last = 0; int nxip; int i; txid xmin, xmax; /* load and validate nxip */ nxip = pq_getmsgint(buf, 4); if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP) 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 = static_cast<TxidSnapshot *>(palloc(TXID_SNAPSHOT_SIZE(nxip))); snap->xmin = xmin; snap->xmax = xmax; for (i = 0; i < nxip; i++) { txid cur = pq_getmsgint64(buf); if (cur < last || cur < xmin || cur >= xmax) goto bad_format; /* skip duplicate xips */ if (cur == last) { i--; nxip--; continue; } snap->xip[i] = cur; last = cur; } snap->nxip = nxip; SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(nxip)); PG_RETURN_POINTER(snap); bad_format: elog(ERROR, "invalid snapshot data"); return (Datum) NULL; }
/* * txid_snapshot_recv(internal) returns txid_snapshot * * binary input function for type txid_snapshot * * format: int4 nxip, int8 xmin, int8 xmax, int8 xip */ Datum txid_snapshot_recv(PG_FUNCTION_ARGS) { 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; }
/* * txid_current_snapshot() returns txid_snapshot * * Return current snapshot in TXID format * * Note that only top-transaction XIDs are included in the snapshot. */ Datum txid_current_snapshot(PG_FUNCTION_ARGS) { 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); }
/* * txid_current_snapshot() returns txid_snapshot * * Return current snapshot in TXID format * * Note that only top-transaction XIDs are included in the snapshot. */ Datum txid_current_snapshot(PG_FUNCTION_ARGS) { TxidSnapshot *snap; uint32 nxip, i; TxidEpoch state; Snapshot cur; cur = GetActiveSnapshot(); if (cur == NULL) elog(ERROR, "no active snapshot set"); load_xid_epoch(&state); /* * Compile-time limits on the procarray (MAX_BACKENDS processes plus * MAX_BACKENDS prepared transactions) guarantee nxip won't be too large. */ StaticAssertStmt(MAX_BACKENDS * 2 <= TXID_SNAPSHOT_MAX_NXIP, "possible overflow in txid_current_snapshot()"); /* allocate */ nxip = cur->xcnt; snap = palloc(TXID_SNAPSHOT_SIZE(nxip)); /* 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. This also removes * any duplicate xids. Normally, an XID can only be assigned to one * backend, but when preparing a transaction for two-phase commit, there * is a transient state when both the original backend and the dummy * PGPROC entry reserved for the prepared transaction hold the same XID. */ sort_snapshot(snap); /* set size after sorting, because it may have removed duplicate xips */ SET_VARSIZE(snap, TXID_SNAPSHOT_SIZE(snap->nxip)); PG_RETURN_POINTER(snap); }
static StringInfo buf_init(txid xmin, txid xmax) { 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; }