]> granicus.if.org Git - postgresql/blobdiff - src/backend/utils/adt/txid.c
Add support for EUI-64 MAC addresses as macaddr8
[postgresql] / src / backend / utils / adt / txid.c
index 31c78182017824973ab54d23514338083e9f12c9..772d7c72031a1c47e840835add6befb7475e48a0 100644 (file)
  * via functions such as SubTransGetTopmostTransaction().
  *
  *
- *     Copyright (c) 2003-2010, PostgreSQL Global Development Group
+ *     Copyright (c) 2003-2017, PostgreSQL Global Development Group
  *     Author: Jan Wieck, Afilias USA INC.
  *     64-bit txids: Marko Kreen, Skype Technologies
  *
- *     $PostgreSQL: pgsql/src/backend/utils/adt/txid.c,v 1.12 2010/02/20 21:24:02 tgl Exp $
+ *     src/backend/utils/adt/txid.c
  *
  *-------------------------------------------------------------------------
  */
 
 #include "access/transam.h"
 #include "access/xact.h"
+#include "access/xlog.h"
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "libpq/pqformat.h"
+#include "postmaster/postmaster.h"
 #include "utils/builtins.h"
+#include "utils/memutils.h"
 #include "utils/snapmgr.h"
 
 
 /* txid will be signed int8 in database, so must limit to 63 bits */
-#define MAX_TXID   UINT64CONST(0x7FFFFFFFFFFFFFFF)
+#define MAX_TXID   ((uint64) PG_INT64_MAX)
 
 /* Use unsigned variant internally */
 typedef uint64 txid;
@@ -61,11 +64,14 @@ typedef struct
        uint32          nxip;                   /* number of txids in xip array */
        txid            xmin;
        txid            xmax;
-       txid            xip[1];                 /* in-progress txids, xmin <= xip[i] < xmax */
+       /* in-progress txids, xmin <= xip[i] < xmax: */
+       txid            xip[FLEXIBLE_ARRAY_MEMBER];
 } TxidSnapshot;
 
 #define TXID_SNAPSHOT_SIZE(nxip) \
        (offsetof(TxidSnapshot, xip) + sizeof(txid) * (nxip))
+#define TXID_SNAPSHOT_MAX_NXIP \
+       ((MaxAllocSize - offsetof(TxidSnapshot, xip)) / sizeof(txid))
 
 /*
  * Epoch values from xact.c
@@ -127,7 +133,8 @@ cmp_txid(const void *aa, const void *bb)
 }
 
 /*
- * sort a snapshot's txids, so we can use bsearch() later.
+ * Sort a snapshot's txids, so we can use bsearch() later.  Also remove
+ * any duplicates.
  *
  * For consistency of on-disk representation, we always sort even if bsearch
  * will not be used.
@@ -135,8 +142,27 @@ cmp_txid(const void *aa, const void *bb)
 static void
 sort_snapshot(TxidSnapshot *snap)
 {
+       txid            last = 0;
+       int                     nxip,
+                               idx1,
+                               idx2;
+
        if (snap->nxip > 1)
+       {
                qsort(snap->xip, snap->nxip, sizeof(txid), cmp_txid);
+
+               /* remove duplicates */
+               nxip = snap->nxip;
+               idx1 = idx2 = 0;
+               while (idx1 < nxip)
+               {
+                       if (snap->xip[idx1] != last)
+                               last = snap->xip[idx2++] = snap->xip[idx1];
+                       else
+                               snap->nxip--;
+                       idx1++;
+               }
+       }
 }
 
 /*
@@ -291,10 +317,12 @@ parse_snapshot(const char *str)
                str = endp;
 
                /* require the input to be in order */
-               if (val < xmin || val >= xmax || val <= last_val)
+               if (val < xmin || val >= xmax || val < last_val)
                        goto bad_format;
 
-               buf_add_txid(buf, val);
+               /* skip duplicates */
+               if (val != last_val)
+                       buf_add_txid(buf, val);
                last_val = val;
 
                if (*str == ',')
@@ -306,8 +334,11 @@ parse_snapshot(const char *str)
        return buf_finalize(buf);
 
 bad_format:
-       elog(ERROR, "invalid input for txid_snapshot: \"%s\"", str_start);
-       return NULL;
+       ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
+                        errmsg("invalid input syntax for type %s: \"%s\"",
+                                       "txid_snapshot", str_start)));
+       return NULL;                            /* keep compiler quiet */
 }
 
 /*
@@ -321,7 +352,8 @@ bad_format:
 /*
  * txid_current() returns int8
  *
- *             Return the current toplevel transaction ID as TXID
+ *     Return the current toplevel transaction ID as TXID
+ *     If the current transaction does not have one, one is assigned.
  */
 Datum
 txid_current(PG_FUNCTION_ARGS)
@@ -330,11 +362,10 @@ txid_current(PG_FUNCTION_ARGS)
        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.
+        * 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()");
 
@@ -345,6 +376,27 @@ txid_current(PG_FUNCTION_ARGS)
        PG_RETURN_INT64(val);
 }
 
+/*
+ * Same as txid_current() but doesn't assign a new xid if there isn't one
+ * yet.
+ */
+Datum
+txid_current_if_assigned(PG_FUNCTION_ARGS)
+{
+       txid            val;
+       TxidEpoch       state;
+       TransactionId   topxid = GetTopTransactionIdIfAny();
+
+       if (topxid == InvalidTransactionId)
+               PG_RETURN_NULL();
+
+       load_xid_epoch(&state);
+
+       val = convert_xid(topxid, &state);
+
+       PG_RETURN_INT64(val);
+}
+
 /*
  * txid_current_snapshot() returns txid_snapshot
  *
@@ -357,8 +409,7 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
 {
        TxidSnapshot *snap;
        uint32          nxip,
-                               i,
-                               size;
+                               i;
        TxidEpoch       state;
        Snapshot        cur;
 
@@ -368,11 +419,16 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
 
        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;
-       size = TXID_SNAPSHOT_SIZE(nxip);
-       snap = palloc(size);
-       SET_VARSIZE(snap, size);
+       snap = palloc(TXID_SNAPSHOT_SIZE(nxip));
 
        /* fill */
        snap->xmin = convert_xid(cur->xmin, &state);
@@ -381,9 +437,18 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
        for (i = 0; i < nxip; i++)
                snap->xip[i] = convert_xid(cur->xip[i], &state);
 
-       /* we want them guaranteed to be in ascending order */
+       /*
+        * 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);
 }
 
@@ -445,20 +510,12 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
        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'.
-        */
+       /* load and validate nxip */
        nxip = pq_getmsgint(buf, 4);
-       avail = buf->len - buf->cursor;
-       expect = 8 + 8 + nxip * 8;
-       if (nxip < 0 || nxip > avail || expect > avail)
+       if (nxip < 0 || nxip > TXID_SNAPSHOT_MAX_NXIP)
                goto bad_format;
 
        xmin = pq_getmsgint64(buf);
@@ -469,23 +526,34 @@ txid_snapshot_recv(PG_FUNCTION_ARGS)
        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)
+               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;
+       ereport(ERROR,
+                       (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                        errmsg("invalid external txid_snapshot data")));
+       PG_RETURN_POINTER(NULL);        /* keep compiler quiet */
 }
 
 /*