mirror of
https://github.com/postgres/postgres.git
synced 2025-06-02 00:01:40 -04:00
Code review for txid patch: add binary I/O functions, avoid dependence
on SerializableSnapshot, minor other cleanup. Marko Kreen, some further editorialization by me.
This commit is contained in:
parent
1246fcd02a
commit
d77717bae7
@ -1,3 +1,4 @@
|
|||||||
|
# $PostgreSQL: pgsql/contrib/txid/Makefile,v 1.2 2007/10/11 19:54:17 tgl Exp $
|
||||||
|
|
||||||
MODULES = txid
|
MODULES = txid
|
||||||
DATA_built = txid.sql
|
DATA_built = txid.sql
|
||||||
@ -5,7 +6,6 @@ DATA = uninstall_txid.sql
|
|||||||
DOCS = README.txid
|
DOCS = README.txid
|
||||||
REGRESS = txid
|
REGRESS = txid
|
||||||
|
|
||||||
|
|
||||||
ifdef USE_PGXS
|
ifdef USE_PGXS
|
||||||
PG_CONFIG = pg_config
|
PG_CONFIG = pg_config
|
||||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||||
@ -16,11 +16,3 @@ top_builddir = ../..
|
|||||||
include $(top_builddir)/src/Makefile.global
|
include $(top_builddir)/src/Makefile.global
|
||||||
include $(top_srcdir)/contrib/contrib-global.mk
|
include $(top_srcdir)/contrib/contrib-global.mk
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
test: install
|
|
||||||
$(MAKE) installcheck || { less regression.diffs; exit 1; }
|
|
||||||
|
|
||||||
ack:
|
|
||||||
cp results/* expected/
|
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
txid - export transaction IDs to user level
|
||||||
|
===========================================
|
||||||
|
|
||||||
txid - export transaction id's to user level
|
The goal is to make PostgreSQL's internal transaction ID and snapshot
|
||||||
============================================
|
|
||||||
|
|
||||||
The goal is to make PostgreSQL internal transaction ID and snapshot
|
|
||||||
data usable externally. This allows very efficient queue
|
data usable externally. This allows very efficient queue
|
||||||
implementation done inside database.
|
implementation done inside database.
|
||||||
|
|
||||||
@ -32,7 +31,7 @@ txid_snapshot_xmax( snap ) returns int8
|
|||||||
txid_snapshot_xip( snap ) setof int8
|
txid_snapshot_xip( snap ) setof int8
|
||||||
|
|
||||||
List of in-progress TXID's in snapshot, that are invisible.
|
List of in-progress TXID's in snapshot, that are invisible.
|
||||||
Values are between xmin and xmax.
|
Values are between xmin (inclusive) and xmax (exclusive).
|
||||||
|
|
||||||
txid_visible_in_snapshot(id, snap) returns bool
|
txid_visible_in_snapshot(id, snap) returns bool
|
||||||
|
|
||||||
@ -73,8 +72,8 @@ fetching possible txids below snap1.xmax explicitly:
|
|||||||
AND NOT txid_visible_in_snapshot(ev_txid, :snap1)
|
AND NOT txid_visible_in_snapshot(ev_txid, :snap1)
|
||||||
AND txid_visible_in_snapshot(ev_txid, :snap2);
|
AND txid_visible_in_snapshot(ev_txid, :snap2);
|
||||||
|
|
||||||
Note that although the above queries work, the PostgreSQL fails to
|
Note that although the above queries work, PostgreSQL fails to
|
||||||
plan them correctly. For actual usage the values for txid_snapshot_xmin,
|
plan them efficiently. For actual usage the values for txid_snapshot_xmin,
|
||||||
txid_snapshot_xmax and txid_snapshot_xip should be filled in directly,
|
txid_snapshot_xmax and txid_snapshot_xip should be filled in directly,
|
||||||
only then will they use index.
|
only then will they use index.
|
||||||
|
|
||||||
@ -92,20 +91,16 @@ To see example code for that it's best to see pgq.batch_event_sql() function in
|
|||||||
Dumping and restoring data containing TXIDs.
|
Dumping and restoring data containing TXIDs.
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
[towrite: reason for epoch increase]
|
When reloading TXID data you will typically want to be sure that the current
|
||||||
|
XID counter is beyond the reloaded data. The easiest way to do this is to
|
||||||
|
increase the XID epoch to beyond the largest one in the input data.
|
||||||
|
|
||||||
You can look at current epoch with query:
|
You can look at current epoch with queries such as:
|
||||||
|
|
||||||
SELECT txid_current() >> 32 as epoch;
|
SELECT MAX(txid) >> 32 as epoch FROM ...;
|
||||||
|
|
||||||
So new epoch should be:
|
|
||||||
|
|
||||||
SELECT (txid_current() >> 32) + 1 as newepoch;
|
|
||||||
|
|
||||||
Epoch can be changed with pg_resetxlog command:
|
Epoch can be changed with pg_resetxlog command:
|
||||||
|
|
||||||
pg_resetxlog -e NEWEPOCH DATADIR
|
pg_resetxlog -e NEWEPOCH DATADIR
|
||||||
|
|
||||||
Database needs to be shut down for that moment.
|
Database needs to be shut down for that moment.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,12 +1,21 @@
|
|||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
* txid.c
|
* txid.c
|
||||||
*
|
*
|
||||||
* Export backend internal tranasction id's to user level.
|
* Export internal transaction IDs to user level.
|
||||||
|
*
|
||||||
|
* Note that only top-level transaction IDs are ever converted to TXID.
|
||||||
|
* This is important because TXIDs frequently persist beyond the global
|
||||||
|
* xmin horizon, or may even be shipped to other machines, so we cannot
|
||||||
|
* rely on being able to correlate subtransaction IDs with their parents
|
||||||
|
* via functions such as SubTransGetTopmostTransaction().
|
||||||
|
*
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
||||||
* Author: Jan Wieck, Afilias USA INC.
|
* Author: Jan Wieck, Afilias USA INC.
|
||||||
*
|
|
||||||
* 64-bit txids: Marko Kreen, Skype Technologies
|
* 64-bit txids: Marko Kreen, Skype Technologies
|
||||||
|
*
|
||||||
|
* $PostgreSQL: pgsql/contrib/txid/txid.c,v 1.4 2007/10/11 19:54:17 tgl Exp $
|
||||||
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -15,32 +24,33 @@
|
|||||||
#include "access/transam.h"
|
#include "access/transam.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
|
#include "libpq/pqformat.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef PG_MODULE_MAGIC
|
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef INT64_IS_BUSTED
|
#ifdef INT64_IS_BUSTED
|
||||||
#error txid needs working int64
|
#error txid needs working int64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* txid will be signed int8 in database */
|
/* txid will be signed int8 in database, so must limit to 63 bits */
|
||||||
#define MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF)
|
#define MAX_TXID UINT64CONST(0x7FFFFFFFFFFFFFFF)
|
||||||
|
|
||||||
/*
|
|
||||||
* If defined, use bsearch() function for searching
|
|
||||||
* txid's inside snapshots that have more than given values.
|
|
||||||
*/
|
|
||||||
#define USE_BSEARCH_IF_NXIP_GREATER 30
|
|
||||||
|
|
||||||
/* format code for uint64 to appendStringInfo */
|
|
||||||
#define TXID_FMT UINT64_FORMAT
|
|
||||||
|
|
||||||
/* Use unsigned variant internally */
|
/* Use unsigned variant internally */
|
||||||
typedef uint64 txid;
|
typedef uint64 txid;
|
||||||
|
|
||||||
|
/* sprintf format code for uint64 */
|
||||||
|
#define TXID_FMT UINT64_FORMAT
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Snapshot for 8byte txids.
|
* If defined, use bsearch() function for searching for txids in snapshots
|
||||||
|
* that have more than the specified number of values.
|
||||||
|
*/
|
||||||
|
#define USE_BSEARCH_IF_NXIP_GREATER 30
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Snapshot containing 8byte txids.
|
||||||
*/
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -55,22 +65,27 @@ typedef struct
|
|||||||
uint32 nxip; /* number of txids in xip array */
|
uint32 nxip; /* number of txids in xip array */
|
||||||
txid xmin;
|
txid xmin;
|
||||||
txid xmax;
|
txid xmax;
|
||||||
txid xip[1]; /* in-progress txids */
|
txid xip[1]; /* in-progress txids, xmin <= xip[i] < xmax */
|
||||||
} TxidSnapshot;
|
} TxidSnapshot;
|
||||||
|
|
||||||
#define TXID_SNAPSHOT_SIZE(nxip) (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
|
#define TXID_SNAPSHOT_SIZE(nxip) \
|
||||||
|
(offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Epoch values from backend.
|
* Epoch values from xact.c
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct
|
||||||
uint64 last_value;
|
{
|
||||||
uint64 epoch;
|
TransactionId last_xid;
|
||||||
|
uint32 epoch;
|
||||||
} TxidEpoch;
|
} TxidEpoch;
|
||||||
|
|
||||||
|
|
||||||
/* public functions */
|
/* public functions */
|
||||||
Datum txid_snapshot_in(PG_FUNCTION_ARGS);
|
Datum txid_snapshot_in(PG_FUNCTION_ARGS);
|
||||||
Datum txid_snapshot_out(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_current(PG_FUNCTION_ARGS);
|
Datum txid_current(PG_FUNCTION_ARGS);
|
||||||
Datum txid_current_snapshot(PG_FUNCTION_ARGS);
|
Datum txid_current_snapshot(PG_FUNCTION_ARGS);
|
||||||
Datum txid_snapshot_xmin(PG_FUNCTION_ARGS);
|
Datum txid_snapshot_xmin(PG_FUNCTION_ARGS);
|
||||||
@ -81,6 +96,8 @@ Datum txid_visible_in_snapshot(PG_FUNCTION_ARGS);
|
|||||||
/* public function tags */
|
/* public function tags */
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_in);
|
PG_FUNCTION_INFO_V1(txid_snapshot_in);
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_out);
|
PG_FUNCTION_INFO_V1(txid_snapshot_out);
|
||||||
|
PG_FUNCTION_INFO_V1(txid_snapshot_recv);
|
||||||
|
PG_FUNCTION_INFO_V1(txid_snapshot_send);
|
||||||
PG_FUNCTION_INFO_V1(txid_current);
|
PG_FUNCTION_INFO_V1(txid_current);
|
||||||
PG_FUNCTION_INFO_V1(txid_current_snapshot);
|
PG_FUNCTION_INFO_V1(txid_current_snapshot);
|
||||||
PG_FUNCTION_INFO_V1(txid_snapshot_xmin);
|
PG_FUNCTION_INFO_V1(txid_snapshot_xmin);
|
||||||
@ -88,8 +105,18 @@ PG_FUNCTION_INFO_V1(txid_snapshot_xmax);
|
|||||||
PG_FUNCTION_INFO_V1(txid_snapshot_xip);
|
PG_FUNCTION_INFO_V1(txid_snapshot_xip);
|
||||||
PG_FUNCTION_INFO_V1(txid_visible_in_snapshot);
|
PG_FUNCTION_INFO_V1(txid_visible_in_snapshot);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do a TransactionId -> txid conversion
|
* Fetch epoch data from xact.c.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
load_xid_epoch(TxidEpoch *state)
|
||||||
|
{
|
||||||
|
GetNextXidAndEpoch(&state->last_xid, &state->epoch);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* do a TransactionId -> txid conversion for an XID near the given epoch
|
||||||
*/
|
*/
|
||||||
static txid
|
static txid
|
||||||
convert_xid(TransactionId xid, const TxidEpoch *state)
|
convert_xid(TransactionId xid, const TxidEpoch *state)
|
||||||
@ -97,53 +124,42 @@ convert_xid(TransactionId xid, const TxidEpoch *state)
|
|||||||
uint64 epoch;
|
uint64 epoch;
|
||||||
|
|
||||||
/* return special xid's as-is */
|
/* return special xid's as-is */
|
||||||
if (xid < FirstNormalTransactionId)
|
if (!TransactionIdIsNormal(xid))
|
||||||
return 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++;
|
||||||
|
|
||||||
/* xid can on both sides on wrap-around */
|
|
||||||
epoch = state->epoch;
|
|
||||||
if (TransactionIdPrecedes(xid, state->last_value)) {
|
|
||||||
if (xid > state->last_value)
|
|
||||||
epoch--;
|
|
||||||
} else if (TransactionIdFollows(xid, state->last_value)) {
|
|
||||||
if (xid < state->last_value)
|
|
||||||
epoch++;
|
|
||||||
}
|
|
||||||
return (epoch << 32) | xid;
|
return (epoch << 32) | xid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch epoch data from backend.
|
* txid comparator for qsort/bsearch
|
||||||
*/
|
|
||||||
static void
|
|
||||||
load_xid_epoch(TxidEpoch *state)
|
|
||||||
{
|
|
||||||
TransactionId xid;
|
|
||||||
uint32 epoch;
|
|
||||||
|
|
||||||
GetNextXidAndEpoch(&xid, &epoch);
|
|
||||||
|
|
||||||
state->epoch = epoch;
|
|
||||||
state->last_value = xid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* compare txid in memory.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cmp_txid(const void *aa, const void *bb)
|
cmp_txid(const void *aa, const void *bb)
|
||||||
{
|
{
|
||||||
const uint64 *a = aa;
|
txid a = *(const txid *) aa;
|
||||||
const uint64 *b = bb;
|
txid b = *(const txid *) bb;
|
||||||
if (*a < *b)
|
|
||||||
|
if (a < b)
|
||||||
return -1;
|
return -1;
|
||||||
if (*a > *b)
|
if (a > b)
|
||||||
return 1;
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* order txids, for bsearch().
|
* sort a snapshot's txids, so we can use bsearch() later.
|
||||||
|
*
|
||||||
|
* For consistency of on-disk representation, we always sort even if bsearch
|
||||||
|
* will not be used.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sort_snapshot(TxidSnapshot *snap)
|
sort_snapshot(TxidSnapshot *snap)
|
||||||
@ -166,13 +182,16 @@ is_visible_txid(txid value, const TxidSnapshot *snap)
|
|||||||
else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
|
else if (snap->nxip > USE_BSEARCH_IF_NXIP_GREATER)
|
||||||
{
|
{
|
||||||
void *res;
|
void *res;
|
||||||
|
|
||||||
res = bsearch(&value, snap->xip, snap->nxip, sizeof(txid), cmp_txid);
|
res = bsearch(&value, snap->xip, snap->nxip, sizeof(txid), cmp_txid);
|
||||||
|
/* if found, transaction is still in progress */
|
||||||
return (res) ? false : true;
|
return (res) ? false : true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i;
|
uint32 i;
|
||||||
|
|
||||||
for (i = 0; i < snap->nxip; i++)
|
for (i = 0; i < snap->nxip; i++)
|
||||||
{
|
{
|
||||||
if (value == snap->xip[i])
|
if (value == snap->xip[i])
|
||||||
@ -206,7 +225,7 @@ buf_add_txid(StringInfo buf, txid xid)
|
|||||||
{
|
{
|
||||||
TxidSnapshot *snap = (TxidSnapshot *)buf->data;
|
TxidSnapshot *snap = (TxidSnapshot *)buf->data;
|
||||||
|
|
||||||
/* do it before possible realloc */
|
/* do this before possible realloc */
|
||||||
snap->nxip++;
|
snap->nxip++;
|
||||||
|
|
||||||
appendBinaryStringInfo(buf, (char *)&xid, sizeof(xid));
|
appendBinaryStringInfo(buf, (char *)&xid, sizeof(xid));
|
||||||
@ -216,6 +235,7 @@ static TxidSnapshot *
|
|||||||
buf_finalize(StringInfo buf)
|
buf_finalize(StringInfo buf)
|
||||||
{
|
{
|
||||||
TxidSnapshot *snap = (TxidSnapshot *)buf->data;
|
TxidSnapshot *snap = (TxidSnapshot *)buf->data;
|
||||||
|
|
||||||
SET_VARSIZE(snap, buf->len);
|
SET_VARSIZE(snap, buf->len);
|
||||||
|
|
||||||
/* buf is not needed anymore */
|
/* buf is not needed anymore */
|
||||||
@ -319,13 +339,17 @@ bad_format:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public functions
|
* Public functions.
|
||||||
|
*
|
||||||
|
* txid_current() and txid_current_snapshot() are the only ones that
|
||||||
|
* communicate with core xid machinery. All the others work on data
|
||||||
|
* returned by them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* txid_current() returns int8
|
* txid_current() returns int8
|
||||||
*
|
*
|
||||||
* Return the current transaction ID
|
* Return the current toplevel transaction ID as TXID
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
txid_current(PG_FUNCTION_ARGS)
|
txid_current(PG_FUNCTION_ARGS)
|
||||||
@ -343,19 +367,21 @@ txid_current(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* txid_current_snapshot() returns txid_snapshot
|
* txid_current_snapshot() returns txid_snapshot
|
||||||
*
|
*
|
||||||
* Return current snapshot
|
* Return current snapshot in TXID format
|
||||||
|
*
|
||||||
|
* Note that only top-transaction XIDs are included in the snapshot.
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
txid_current_snapshot(PG_FUNCTION_ARGS)
|
txid_current_snapshot(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TxidSnapshot *snap;
|
TxidSnapshot *snap;
|
||||||
unsigned nxip, i, size;
|
uint32 nxip, i, size;
|
||||||
TxidEpoch state;
|
TxidEpoch state;
|
||||||
Snapshot cur;
|
Snapshot cur;
|
||||||
|
|
||||||
cur = SerializableSnapshot;
|
cur = ActiveSnapshot;
|
||||||
if (cur == NULL)
|
if (cur == NULL)
|
||||||
elog(ERROR, "get_current_snapshot: SerializableSnapshot == NULL");
|
elog(ERROR, "txid_current_snapshot: ActiveSnapshot == NULL");
|
||||||
|
|
||||||
load_xid_epoch(&state);
|
load_xid_epoch(&state);
|
||||||
|
|
||||||
@ -372,7 +398,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
|
|||||||
for (i = 0; i < nxip; i++)
|
for (i = 0; i < nxip; i++)
|
||||||
snap->xip[i] = convert_xid(cur->xip[i], &state);
|
snap->xip[i] = convert_xid(cur->xip[i], &state);
|
||||||
|
|
||||||
/* we want them guaranteed ascending order */
|
/* we want them guaranteed to be in ascending order */
|
||||||
sort_snapshot(snap);
|
sort_snapshot(snap);
|
||||||
|
|
||||||
PG_RETURN_POINTER(snap);
|
PG_RETURN_POINTER(snap);
|
||||||
@ -386,8 +412,8 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
txid_snapshot_in(PG_FUNCTION_ARGS)
|
txid_snapshot_in(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TxidSnapshot *snap;
|
|
||||||
char *str = PG_GETARG_CSTRING(0);
|
char *str = PG_GETARG_CSTRING(0);
|
||||||
|
TxidSnapshot *snap;
|
||||||
|
|
||||||
snap = parse_snapshot(str);
|
snap = parse_snapshot(str);
|
||||||
|
|
||||||
@ -402,11 +428,9 @@ txid_snapshot_in(PG_FUNCTION_ARGS)
|
|||||||
Datum
|
Datum
|
||||||
txid_snapshot_out(PG_FUNCTION_ARGS)
|
txid_snapshot_out(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TxidSnapshot *snap;
|
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
||||||
StringInfoData str;
|
StringInfoData str;
|
||||||
int i;
|
uint32 i;
|
||||||
|
|
||||||
snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
|
||||||
|
|
||||||
initStringInfo(&str);
|
initStringInfo(&str);
|
||||||
|
|
||||||
@ -415,16 +439,92 @@ txid_snapshot_out(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
for (i = 0; i < snap->nxip; i++)
|
for (i = 0; i < snap->nxip; i++)
|
||||||
{
|
{
|
||||||
appendStringInfo(&str, "%s" TXID_FMT,
|
if (i > 0)
|
||||||
((i > 0) ? "," : ""),
|
appendStringInfoChar(&str, ',');
|
||||||
snap->xip[i]);
|
appendStringInfo(&str, TXID_FMT, snap->xip[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_FREE_IF_COPY(snap, 0);
|
|
||||||
|
|
||||||
PG_RETURN_CSTRING(str.data);
|
PG_RETURN_CSTRING(str.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_snapshot_send(txid_snapshot) returns bytea
|
||||||
|
*
|
||||||
|
* binary output function for type txid_snapshot
|
||||||
|
*
|
||||||
|
* format: int4 nxip, int8 xmin, int8 xmax, int8 xip
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
txid_snapshot_send(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* txid_visible_in_snapshot(int8, txid_snapshot) returns bool
|
* txid_visible_in_snapshot(int8, txid_snapshot) returns bool
|
||||||
@ -436,12 +536,8 @@ txid_visible_in_snapshot(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
txid value = PG_GETARG_INT64(0);
|
txid value = PG_GETARG_INT64(0);
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1);
|
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(1);
|
||||||
int res;
|
|
||||||
|
|
||||||
res = is_visible_txid(value, snap) ? true : false;
|
PG_RETURN_BOOL(is_visible_txid(value, snap));
|
||||||
|
|
||||||
PG_FREE_IF_COPY(snap, 1);
|
|
||||||
PG_RETURN_BOOL(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -453,9 +549,8 @@ Datum
|
|||||||
txid_snapshot_xmin(PG_FUNCTION_ARGS)
|
txid_snapshot_xmin(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
||||||
txid res = snap->xmin;
|
|
||||||
PG_FREE_IF_COPY(snap, 0);
|
PG_RETURN_INT64(snap->xmin);
|
||||||
PG_RETURN_INT64(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -467,9 +562,8 @@ Datum
|
|||||||
txid_snapshot_xmax(PG_FUNCTION_ARGS)
|
txid_snapshot_xmax(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
TxidSnapshot *snap = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
||||||
txid res = snap->xmax;
|
|
||||||
PG_FREE_IF_COPY(snap, 0);
|
PG_RETURN_INT64(snap->xmax);
|
||||||
PG_RETURN_INT64(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -486,15 +580,13 @@ txid_snapshot_xip(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* on first call initialize snap_state and get copy of snapshot */
|
/* on first call initialize snap_state and get copy of snapshot */
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL()) {
|
||||||
TxidSnapshot *arg;
|
TxidSnapshot *arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
||||||
|
|
||||||
fctx = SRF_FIRSTCALL_INIT();
|
fctx = SRF_FIRSTCALL_INIT();
|
||||||
|
|
||||||
/* make a copy of user snapshot */
|
/* make a copy of user snapshot */
|
||||||
arg = (TxidSnapshot *) PG_GETARG_VARLENA_P(0);
|
|
||||||
snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
|
snap = MemoryContextAlloc(fctx->multi_call_memory_ctx, VARSIZE(arg));
|
||||||
memcpy(snap, arg, VARSIZE(arg));
|
memcpy(snap, arg, VARSIZE(arg));
|
||||||
PG_FREE_IF_COPY(arg, 0);
|
|
||||||
|
|
||||||
fctx->user_fctx = snap;
|
fctx->user_fctx = snap;
|
||||||
}
|
}
|
||||||
@ -509,4 +601,3 @@ txid_snapshot_xip(PG_FUNCTION_ARGS)
|
|||||||
SRF_RETURN_DONE(fctx);
|
SRF_RETURN_DONE(fctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,21 +5,38 @@
|
|||||||
--
|
--
|
||||||
-- Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
-- Copyright (c) 2003-2007, PostgreSQL Global Development Group
|
||||||
-- Author: Jan Wieck, Afilias USA INC.
|
-- Author: Jan Wieck, Afilias USA INC.
|
||||||
--
|
|
||||||
-- 64-bit txids: Marko Kreen, Skype Technologies
|
-- 64-bit txids: Marko Kreen, Skype Technologies
|
||||||
|
--
|
||||||
|
-- $PostgreSQL: pgsql/contrib/txid/txid.sql.in,v 1.2 2007/10/11 19:54:17 tgl Exp $
|
||||||
|
--
|
||||||
-- ----------
|
-- ----------
|
||||||
|
|
||||||
|
-- Adjust this setting to control where the objects get created.
|
||||||
|
SET search_path = public;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- A special transaction snapshot data type for faster visibility checks
|
-- A special transaction snapshot data type for faster visibility checks
|
||||||
--
|
--
|
||||||
CREATE OR REPLACE FUNCTION txid_snapshot_in(cstring)
|
CREATE TYPE txid_snapshot;
|
||||||
|
|
||||||
|
CREATE FUNCTION txid_snapshot_in(cstring)
|
||||||
RETURNS txid_snapshot
|
RETURNS txid_snapshot
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C
|
AS 'MODULE_PATHNAME' LANGUAGE C
|
||||||
IMMUTABLE STRICT;
|
IMMUTABLE STRICT;
|
||||||
CREATE OR REPLACE FUNCTION txid_snapshot_out(txid_snapshot)
|
CREATE FUNCTION txid_snapshot_out(txid_snapshot)
|
||||||
RETURNS cstring
|
RETURNS cstring
|
||||||
AS 'MODULE_PATHNAME' LANGUAGE C
|
AS 'MODULE_PATHNAME' LANGUAGE C
|
||||||
IMMUTABLE STRICT;
|
IMMUTABLE STRICT;
|
||||||
|
CREATE FUNCTION txid_snapshot_recv(internal)
|
||||||
|
RETURNS txid_snapshot
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C
|
||||||
|
IMMUTABLE STRICT;
|
||||||
|
CREATE FUNCTION txid_snapshot_send(txid_snapshot)
|
||||||
|
RETURNS bytea
|
||||||
|
AS 'MODULE_PATHNAME' LANGUAGE C
|
||||||
|
IMMUTABLE STRICT;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- The data type itself
|
-- The data type itself
|
||||||
@ -27,42 +44,44 @@ CREATE OR REPLACE FUNCTION txid_snapshot_out(txid_snapshot)
|
|||||||
CREATE TYPE txid_snapshot (
|
CREATE TYPE txid_snapshot (
|
||||||
INPUT = txid_snapshot_in,
|
INPUT = txid_snapshot_in,
|
||||||
OUTPUT = txid_snapshot_out,
|
OUTPUT = txid_snapshot_out,
|
||||||
|
RECEIVE = txid_snapshot_recv,
|
||||||
|
SEND = txid_snapshot_send,
|
||||||
INTERNALLENGTH = variable,
|
INTERNALLENGTH = variable,
|
||||||
STORAGE = extended,
|
STORAGE = extended,
|
||||||
ALIGNMENT = double
|
ALIGNMENT = double
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION txid_current()
|
--
|
||||||
|
-- Functions for txid
|
||||||
|
--
|
||||||
|
CREATE FUNCTION txid_current()
|
||||||
RETURNS bigint
|
RETURNS bigint
|
||||||
AS 'MODULE_PATHNAME', 'txid_current' LANGUAGE C
|
AS 'MODULE_PATHNAME', 'txid_current' LANGUAGE C
|
||||||
STABLE;
|
STABLE;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION txid_current_snapshot()
|
CREATE FUNCTION txid_current_snapshot()
|
||||||
RETURNS txid_snapshot
|
RETURNS txid_snapshot
|
||||||
AS 'MODULE_PATHNAME', 'txid_current_snapshot' LANGUAGE C
|
AS 'MODULE_PATHNAME', 'txid_current_snapshot' LANGUAGE C
|
||||||
STABLE;
|
STABLE;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION txid_snapshot_xmin(txid_snapshot)
|
CREATE FUNCTION txid_snapshot_xmin(txid_snapshot)
|
||||||
RETURNS bigint
|
RETURNS bigint
|
||||||
AS 'MODULE_PATHNAME', 'txid_snapshot_xmin' LANGUAGE C
|
AS 'MODULE_PATHNAME', 'txid_snapshot_xmin' LANGUAGE C
|
||||||
IMMUTABLE STRICT;
|
IMMUTABLE STRICT;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION txid_snapshot_xmax(txid_snapshot)
|
CREATE FUNCTION txid_snapshot_xmax(txid_snapshot)
|
||||||
RETURNS bigint
|
RETURNS bigint
|
||||||
AS 'MODULE_PATHNAME', 'txid_snapshot_xmax' LANGUAGE C
|
AS 'MODULE_PATHNAME', 'txid_snapshot_xmax' LANGUAGE C
|
||||||
IMMUTABLE STRICT;
|
IMMUTABLE STRICT;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION txid_snapshot_xip(txid_snapshot)
|
CREATE FUNCTION txid_snapshot_xip(txid_snapshot)
|
||||||
RETURNS setof bigint
|
RETURNS setof bigint
|
||||||
AS 'MODULE_PATHNAME', 'txid_snapshot_xip' LANGUAGE C
|
AS 'MODULE_PATHNAME', 'txid_snapshot_xip' LANGUAGE C
|
||||||
IMMUTABLE STRICT;
|
IMMUTABLE STRICT;
|
||||||
|
|
||||||
|
CREATE FUNCTION txid_visible_in_snapshot(bigint, txid_snapshot)
|
||||||
--
|
|
||||||
-- Special comparision functions for visibility checks
|
|
||||||
--
|
|
||||||
CREATE OR REPLACE FUNCTION txid_visible_in_snapshot(bigint, txid_snapshot)
|
|
||||||
RETURNS boolean
|
RETURNS boolean
|
||||||
AS 'MODULE_PATHNAME', 'txid_visible_in_snapshot' LANGUAGE C
|
AS 'MODULE_PATHNAME', 'txid_visible_in_snapshot' LANGUAGE C
|
||||||
IMMUTABLE STRICT;
|
IMMUTABLE STRICT;
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
SET search_path = public;
|
||||||
|
|
||||||
DROP FUNCTION txid_current();
|
DROP FUNCTION txid_current();
|
||||||
DROP FUNCTION txid_current_snapshot();
|
DROP FUNCTION txid_current_snapshot();
|
||||||
@ -6,10 +6,6 @@ DROP FUNCTION txid_snapshot_xmin(txid_snapshot);
|
|||||||
DROP FUNCTION txid_snapshot_xmax(txid_snapshot);
|
DROP FUNCTION txid_snapshot_xmax(txid_snapshot);
|
||||||
DROP FUNCTION txid_snapshot_xip(txid_snapshot);
|
DROP FUNCTION txid_snapshot_xip(txid_snapshot);
|
||||||
DROP FUNCTION txid_visible_in_snapshot(bigint, txid_snapshot);
|
DROP FUNCTION txid_visible_in_snapshot(bigint, txid_snapshot);
|
||||||
DROP FUNCTION txid_not_visible_in_snapshot(bigint, txid_snapshot);
|
|
||||||
|
|
||||||
DROP TYPE txid_snapshot cascade;
|
|
||||||
-- need cascade to drop those:
|
|
||||||
-- DROP FUNCTION txid_snapshot_in(cstring);
|
|
||||||
-- DROP FUNCTION txid_snapshot_out(txid_snapshot);
|
|
||||||
|
|
||||||
|
DROP TYPE txid_snapshot CASCADE;
|
||||||
|
-- need cascade to drop the I/O functions
|
||||||
|
Loading…
x
Reference in New Issue
Block a user