xactlist.mbox
application/octet-stream
Filename: xactlist.mbox
Type: application/octet-stream
Part: 0
From e29927c7966adba2443fdc4f64da9d282f95a05b Mon Sep 17 00:00:00 2001
From: Kevin Grittner <Kevin.Grittner@wicourts.gov>
Date: Sat, 18 Sep 2010 11:08:40 -0500
Subject: [PATCH 1460/1461] Rework techniques for getting to top level transaction when using
an XID from MVCC data, based on concerns form Heikki and Tom. Use
SubTransGetTopmostTransaction, checking both before and after for
a TranactionId before TransactionXmin, which would indicate a
transaction too early to overlap, and therefore not able to
generate a conflict with the current transaction.
---
src/backend/access/transam/varsup.c | 4 +
src/backend/storage/lmgr/predicate.c | 146 ++++++++++++------------------
src/include/storage/predicate.h | 1 +
src/include/storage/predicate_internal.h | 15 ++--
4 files changed, 70 insertions(+), 96 deletions(-)
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index efe11a9..8811e24 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -20,6 +20,7 @@
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
#include "storage/pmsignal.h"
+#include "storage/predicate.h"
#include "storage/proc.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
@@ -156,9 +157,12 @@ GetNewTransactionId(bool isSubXact)
* holds 32K or more transactions, so we don't have to do this very often.
*
* Extend pg_subtrans too.
+ * If it's top level, the predicate locking system also needs to know.
*/
ExtendCLOG(xid);
ExtendSUBTRANS(xid);
+ if (!isSubXact)
+ RegisterPredicateLockingXid(xid);
/*
* Now advance the nextXid counter. This must not happen until after we
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 76e1277..974b95c 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -116,6 +116,7 @@
*
* predicate lock maintenance
* RegisterSerializableTransaction(Snapshot snapshot)
+ * RegisterPredicateLockingXid(void)
* PredicateLockRelation(Relation relation)
* PredicateLockPage(Relation relation, BlockNumber blkno)
* PredicateLockTuple(Relation relation, HeapTuple tuple)
@@ -137,6 +138,7 @@
#include "postgres.h"
+#include "access/subtrans.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
@@ -293,7 +295,6 @@ static bool GetParentPredicateLockTag(const PREDICATELOCKTARGETTAG *tag,
PREDICATELOCKTARGETTAG *parent);
static void DecrementParentLocks(const PREDICATELOCKTARGETTAG *targettag);
static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *tag);
-static void EnsureMySerializableXidExists(void);
static void ClearOldPredicateLocks(void);
static bool XidIsConcurrent(TransactionId xid);
static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
@@ -612,7 +613,6 @@ RegisterSerializableTransaction(const Snapshot snapshot)
sxact->finishedBefore = InvalidTransactionId;
sxact->xmin = snapshot->xmin;
SHMQueueInit(&(sxact->predicateLocks));
- SHMQueueInit(&(sxact->xids));
SHMQueueElemInit(&(sxact->finishedLink));
sxact->rolledBack = false;
LWLockRelease(SerializableXactHashLock);
@@ -632,55 +632,50 @@ RegisterSerializableTransaction(const Snapshot snapshot)
}
/*
- * Make sure we have a SERIALIZABLEXACT reference in MySerializableXact.
- * It should be current for this process and be contained in
- * SerializableXidHash.
+ * Register the top level XID in SerializableXidHash.
+ * Also store it for easy reference in MySerializableXact.
*/
-static void
-EnsureMySerializableXidExists(void)
+void
+RegisterPredicateLockingXid(const TransactionId xid)
{
- TransactionId xid;
-
- Assert(MySerializableXact != InvalidSerializableXact);
-
- MySerializableXact->topXid = GetTopTransactionIdIfAny();
+ SERIALIZABLEXIDTAG sxidtag;
+ SERIALIZABLEXID *sxid;
+ bool found;
/*
- * If this isn't the xid we've most recently seen for this vxid, make sure
- * it's in the hash table.
+ * If we're not tracking predicate lock data for this transaction,
+ * we should ignore the request and return quickly.
*/
- xid = GetCurrentTransactionIdIfAny();
- if (MyXid != xid)
- {
- SERIALIZABLEXIDTAG sxidtag;
- SERIALIZABLEXID *sxid;
- bool found;
+ if (MySerializableXact == InvalidSerializableXact)
+ return;
- Assert(TransactionIdIsValid(xid));
+ /* This should only be done once per transaction. */
+ Assert(MySerializableXact->topXid == InvalidTransactionId);
- sxidtag.xid = xid;
- LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
- sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
- &sxidtag,
- HASH_ENTER, &found);
- if (!sxid)
- ereport(ERROR,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of shared memory"),
- errhint("You might need to increase max_predicate_locks_per_transaction.")));
+ /* We should have a valid XID and be at the top level. */
+ Assert(TransactionIdIsValid(xid));
- /* Initialize the structure. */
- if (!found)
- {
- sxid->myXact = (SERIALIZABLEXACT *) MySerializableXact;
- SHMQueueInsertBefore(&(((SERIALIZABLEXACT *) MySerializableXact)->xids),
- &(sxid->xactLink));
- }
- LWLockRelease(SerializableXactHashLock);
- MyXid = xid;
- }
+ MySerializableXact->topXid = xid;
+
+ sxidtag.xid = xid;
+ LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
+ sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,
+ &sxidtag,
+ HASH_ENTER, &found);
+ if (!sxid)
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of shared memory"),
+ errhint("You might need to increase max_predicate_locks_per_transaction.")));
+
+ Assert(!found);
+
+ /* Initialize the structure. */
+ sxid->myXact = (SERIALIZABLEXACT *) MySerializableXact;
+ LWLockRelease(SerializableXactHashLock);
}
+
/*
* Check whether there are any predicate locks held by any transaction
* for the page at the given block number.
@@ -1053,8 +1048,6 @@ PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
PREDICATELOCK *lock;
LOCALPREDICATELOCK *locallock;
- EnsureMySerializableXidExists();
-
/* Do we have the lock already, or a covering lock? */
if (PredicateLockExists(targettag))
return;
@@ -1201,28 +1194,22 @@ PredicateLockTuple(const Relation relation, const HeapTuple tuple)
return;
/*
- * If it's a heap tuple, return if this xact wrote it. It might be useful
- * to pass in the xmin from the tuple as another parameter.
+ * If it's a heap tuple, return if this xact wrote it.
*/
if (relation->rd_index == NULL)
{
- SERIALIZABLEXIDTAG sxidtag;
- SERIALIZABLEXID *sxid;
-
- sxidtag.xid = HeapTupleHeaderGetXmin(tuple->t_data);
- LWLockAcquire(SerializableXactHashLock, LW_SHARED);
- sxid = (SERIALIZABLEXID *)
- hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
- if (sxid)
+ TransactionId xid;
+
+ xid = HeapTupleHeaderGetXmin(tuple->t_data);
+ if (TransactionIdFollowsOrEquals(xid, TransactionXmin))
{
- if (sxid->myXact == MySerializableXact)
+ xid = SubTransGetTopmostTransaction(xid);
+ if (xid == GetTopTransactionIdIfAny())
{
/* We wrote it; we already have a write lock. */
- LWLockRelease(SerializableXactHashLock);
return;
}
}
- LWLockRelease(SerializableXactHashLock);
}
tid = &(tuple->t_self);
@@ -1731,7 +1718,7 @@ static void
ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact)
{
PREDICATELOCK *predlock;
- SERIALIZABLEXID *sxid;
+ SERIALIZABLEXIDTAG sxidtag;
Assert(sxact != NULL);
Assert(sxact->rolledBack || SxactIsCommitted(sxact));
@@ -1783,31 +1770,13 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact)
}
LWLockRelease(SerializablePredicateLockListLock);
- /* Get rid of the xids and the record of the transaction itself. */
- LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
- sxid = (SERIALIZABLEXID *)
- SHMQueueNext(&(sxact->xids),
- &(sxact->xids),
- offsetof(SERIALIZABLEXID, xactLink));
- while (sxid)
- {
- SERIALIZABLEXID *nextsxid;
- SERIALIZABLEXIDTAG tag;
-
- nextsxid = (SERIALIZABLEXID *)
- SHMQueueNext(&(sxact->xids),
- &(sxid->xactLink),
- offsetof(SERIALIZABLEXID, xactLink));
- tag = sxid->tag;
- hash_search(SerializableXidHash, &tag, HASH_REMOVE, NULL);
-
- /*
- * No need to do retail removal from transaction object; it's going
- * away.
- */
- sxid = nextsxid;
- }
SHMQueueDelete(&(sxact->finishedLink));
+
+ /* Get rid of the xid and the record of the transaction itself. */
+ sxidtag.xid = sxact->topXid;
+ LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
+ if (sxidtag.xid != InvalidTransactionId)
+ hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
hash_search(SerializableXactHash, &(sxact->tag), HASH_REMOVE, NULL);
LWLockRelease(SerializableXactHashLock);
}
@@ -1903,6 +1872,13 @@ CheckForSerializableConflictOut(const bool valid, const Relation relation,
xid = HeapTupleHeaderGetXmin(tuple->t_data);
}
+ /* Bail out if xid is too early to be a conflict. */
+ if (TransactionIdPrecedes(xid, TransactionXmin))
+ return;
+ xid = SubTransGetTopmostTransaction(xid);
+ if (TransactionIdPrecedes(xid, TransactionXmin))
+ return;
+
/*
* It's OK to look for conflicts with a share lock, and record them with
* an exclusive lock when found; we just have to release the shared lock
@@ -1949,12 +1925,6 @@ CheckForSerializableConflictOut(const bool valid, const Relation relation,
sxacttag = sxact->tag;
LWLockRelease(SerializableXactHashLock);
- /*
- * Make sure we have somewhere to record a conflict against this
- * transaction.
- */
- EnsureMySerializableXidExists();
-
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
sxact = (SERIALIZABLEXACT *)
hash_search(SerializableXactHash, &sxacttag, HASH_FIND, NULL);
@@ -2184,8 +2154,6 @@ CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple,
if (SkipSerialization(relation))
return;
- EnsureMySerializableXidExists();
-
/*
* It is important that we check for locks from the finest granularity to
* the coarsest granularity, so that granularity promotion doesn't cause
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 7dcc2af..2cc20ab 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -37,6 +37,7 @@ extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blk
/* predicate lock maintenance */
extern void RegisterSerializableTransaction(const Snapshot snapshot);
+extern void RegisterPredicateLockingXid(const TransactionId xid);
extern void PredicateLockRelation(const Relation relation);
extern void PredicateLockPage(const Relation relation, const BlockNumber blkno);
extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple);
diff --git a/src/include/storage/predicate_internal.h b/src/include/storage/predicate_internal.h
index 7cdb5af..d6a2b8c 100644
--- a/src/include/storage/predicate_internal.h
+++ b/src/include/storage/predicate_internal.h
@@ -74,7 +74,6 @@ typedef struct SERIALIZABLEXACT
* serializable xids are before this. */
TransactionId xmin; /* the transaction's snapshot xmin */
SHM_QUEUE predicateLocks; /* list of associated PREDICATELOCK objects */
- SHM_QUEUE xids; /* list of associated SERIALIZABLEXID objects */
SHM_QUEUE finishedLink; /* list link in
* FinishedSerializableTransactions */
bool rolledBack; /* ignore conflicts when true; allows deferred
@@ -93,8 +92,8 @@ typedef struct SERIALIZABLEXIDTAG
/*
* The SERIALIZABLEXID struct provides a link from a TransactionId for a
- * serializable transaction or subtransaction to the related SERIALIZABLEXACT
- * record.
+ * serializable transaction to the related SERIALIZABLEXACT record, even if
+ * the transaction has completed and its connection has been closed.
*
* A hash table of these objects is maintained in shared memory to provide a
* quick way to find the top level transaction information for a serializable
@@ -104,8 +103,12 @@ typedef struct SERIALIZABLEXIDTAG
* allows a fast link from MVCC transaction IDs to the related serializable
* transaction hash table entry.
*
- * These are created as the transaction and its subtransactions write data,
- * and are kept until the cleanup of the top level transaction.
+ * These are created as new top level transaction IDs are first assigned to
+ * transactions which are participating in predicate locking. They are
+ * removed with their related serializable transaction objects.
+ *
+ * The SubTransGetTopmostTransaction method is used where necessary to get
+ * from an XID which might be from a subtransaction to the top level XID.
*/
typedef struct SERIALIZABLEXID
{
@@ -114,8 +117,6 @@ typedef struct SERIALIZABLEXID
/* data */
SERIALIZABLEXACT *myXact; /* pointer to the top level transaction data */
- SHM_QUEUE xactLink; /* list link in SERIALIZABLEXACT's list of
- * xids */
} SERIALIZABLEXID;
--
1.6.3.3
From b8eca245ab63725d0fbfc3b5969f4a17fc765f2c Mon Sep 17 00:00:00 2001
From: Kevin Grittner <Kevin.Grittner@wicourts.gov>
Date: Tue, 21 Sep 2010 10:11:26 -0500
Subject: [PATCH 1461/1461] Replace the hash table for SERIALIZABLEXACT objects with a list.
The hash table was really only being used for memory allocation
purposes; it was the SHM_QUEUE objects forming lists which really
mattered. That seemed inefficient and overly hacky, so a simple
shared memory list implementation using SHM_QUEUE was created.
The use of SHM_QUEUE is hidden, and all access is through four
small functions, but no effort was made to really turn the list
into a proper "black box" or generalize it.
---
src/backend/storage/lmgr/predicate.c | 186 +++++++++++++++++++++++-------
src/include/storage/predicate_internal.h | 32 +++++
2 files changed, 177 insertions(+), 41 deletions(-)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 974b95c..44c86e0 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -257,10 +257,21 @@ TransactionId SerializableGlobalXmin = InvalidTransactionId;
int SerializableGlobalXminCount = 0;
/*
+ * This provides a list of objects in order to track transactions
+ * participating in predicate locking. Entries in the list are fixed size,
+ * and reside in shared memory. The memory address of an entry must remain
+ * fixed during its lifetime. The list will be protected from concurrent
+ * update externally; no provision is made in this code to manage that. The
+ * number of entries in the list, and the size allowed for each entry is
+ * fixed upon creation.
+ */
+static PredTranList PredLockTranList;
+
+
+/*
* The predicate locking hash tables are in shared memory.
* Each backend keeps pointers to them.
*/
-static HTAB *SerializableXactHash;
static HTAB *SerializableXidHash;
static HTAB *PredicateLockTargetHash;
static HTAB *PredicateLockHash;
@@ -275,16 +286,19 @@ static HTAB *LocalPredicateLockHash = NULL;
/*
* Keep a pointer to the currently-running serializable transaction (if any)
* for quick reference.
+ * TODO SSI: Remove volatile qualifier and the then-unnecessary casts?
*/
static volatile SERIALIZABLEXACT *MySerializableXact = InvalidSerializableXact;
-/* TODO SSI: Remove volatile qualifier and the then-unnecessary casts? */
-
-/* The most recently used xid within this transaction, for optimizations. */
-static TransactionId MyXid = InvalidTransactionId;
/* local functions */
+
+static SERIALIZABLEXACT *CreatePredTran(void);
+static void ReleasePredTran(SERIALIZABLEXACT *sxact);
+static SERIALIZABLEXACT *FirstPredTran(void);
+static SERIALIZABLEXACT *NextPredTran(SERIALIZABLEXACT *sxact);
+
static uint32 predicatelock_hash(const void *key, Size keysize);
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact);
static bool PredicateLockExists(const PREDICATELOCKTARGETTAG *newtargettag);
@@ -302,6 +316,78 @@ static void CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag);
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
const SERIALIZABLEXACT *writer);
+
+/*
+ * These functions are a simple implementation of a list for this specific
+ * type of struct. If there is ever a generalized shared memory list, we
+ * should probably switch to that.
+ */
+static SERIALIZABLEXACT *
+CreatePredTran(void)
+{
+ PredTranListElement ptle;
+
+ ptle = (PredTranListElement)
+ SHMQueueNext(&PredLockTranList->availableList,
+ &PredLockTranList->availableList,
+ offsetof(PredTranListElementData, link));
+ SHMQueueDelete(&ptle->link);
+ SHMQueueInsertBefore(&PredLockTranList->activeList, &ptle->link);
+ return &ptle->sxact;
+}
+
+static void
+ReleasePredTran(SERIALIZABLEXACT *sxact)
+{
+ PredTranListElement ptle;
+
+ Assert(ShmemAddrIsValid(sxact));
+
+ ptle = (PredTranListElement)
+ (((char *) sxact)
+ - offsetof(PredTranListElementData, sxact)
+ + offsetof(PredTranListElementData, link));
+ SHMQueueDelete(&ptle->link);
+ SHMQueueInsertBefore(&PredLockTranList->availableList, &ptle->link);
+}
+
+static SERIALIZABLEXACT *
+FirstPredTran(void)
+{
+ PredTranListElement ptle;
+
+ ptle = (PredTranListElement)
+ SHMQueueNext(&PredLockTranList->activeList,
+ &PredLockTranList->activeList,
+ offsetof(PredTranListElementData, link));
+ if (!ptle)
+ return NULL;
+
+ return &ptle->sxact;
+}
+
+static SERIALIZABLEXACT *
+NextPredTran(SERIALIZABLEXACT *sxact)
+{
+ PredTranListElement ptle;
+
+ Assert(ShmemAddrIsValid(sxact));
+
+ ptle = (PredTranListElement)
+ (((char *) sxact)
+ - offsetof(PredTranListElementData, sxact)
+ + offsetof(PredTranListElementData, link));
+ ptle = (PredTranListElement)
+ SHMQueueNext(&PredLockTranList->activeList,
+ &ptle->link,
+ offsetof(PredTranListElementData, link));
+ if (!ptle)
+ return NULL;
+
+ return &ptle->sxact;
+}
+
+
/*
* InitPredicateLocks -- Initialize the predicate locking data structures.
*
@@ -319,6 +405,7 @@ InitPredicateLocks(void)
int hash_flags;
long init_table_size,
max_table_size;
+ Size requestSize;
bool found;
/*
@@ -375,25 +462,46 @@ InitPredicateLocks(void)
init_table_size = max_table_size / 2;
/*
- * Allocate hash table for SERIALIZABLEXACT structs. This stores per-vxid
- * information for serializable transactions which have accessed data.
+ * Allocate a list to hold information on transaction participating in
+ * predicate locking.
+ *
+ * Assume an average of 10 predicate locking transactions per backend.
+ * That may seem high, but each transaction must be kept until every
+ * overlapping predicate locking transaction has completed, so we have
+ * to tolerate the occassional long-running transaction.
*/
- MemSet(&info, 0, sizeof(info));
- info.keysize = sizeof(SERIALIZABLEXACTTAG);
- info.entrysize = sizeof(SERIALIZABLEXACT);
- info.hash = tag_hash;
- hash_flags = (HASH_ELEM | HASH_FUNCTION);
-
- SerializableXactHash = ShmemInitHash("SERIALIZABLEXACT hash",
- init_table_size,
- max_table_size,
- &info,
- hash_flags);
-
- /* Assume an average of 10 serializable xids per backend. */
max_table_size *= 10;
init_table_size *= 10;
+ PredLockTranList = ShmemInitStruct("PredTranList",
+ PredTranListDataSize,
+ &found);
+ if (!found)
+ {
+ int i;
+
+ SHMQueueInit(&PredLockTranList->availableList); // available elements
+ SHMQueueInit(&PredLockTranList->activeList); // active elements
+ requestSize = mul_size((Size) max_table_size,
+ PredTranListElementDataSize);
+ PredLockTranList->element = ShmemAlloc(requestSize);
+ if (PredLockTranList->element == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("not enough shared memory for elements of data structure"
+ " \"%s\" (%lu bytes requested)",
+ "PredTranList", (unsigned long) requestSize)));
+ PredLockTranList->entryLimit = max_table_size; // get from GUC?
+ PredLockTranList->entryCount = 0; // starts empty
+ /* Add all elements to available list, clean. */
+ memset(PredLockTranList->element, 0, requestSize);
+ for (i = 0; i < max_table_size; i++)
+ {
+ SHMQueueInsertBefore(&(PredLockTranList->availableList),
+ &(PredLockTranList->element[i].link));
+ }
+ }
+
/*
* Allocate hash table for SERIALIZABLEXID structs. This stores per-xid
* information for serializable transactions which have accessed data.
@@ -447,13 +555,14 @@ PredicateLockShmemSize(void)
*/
size = add_size(size, size / 10);
- /* serializable transaction table */
+ /* transaction list */
max_table_size = MaxBackends;
- size = add_size(size, hash_estimate_size(max_table_size,
- sizeof(SERIALIZABLEXACT)));
-
- /* serializable subtransaction table */
max_table_size *= 10;
+ size = add_size(size, PredTranListDataSize);
+ size = add_size(size, mul_size((Size) max_table_size,
+ PredTranListElementDataSize));
+
+ /* transaction xid table */
size = add_size(size, hash_estimate_size(max_table_size,
sizeof(SERIALIZABLEXID)));
@@ -561,7 +670,7 @@ GetPredicateLockStatusData(void)
/*
* Make sure we have a SERIALIZABLEXACT reference in MySerializableXact.
* It should be current for this process and be contained in
- * SerializableXactHash.
+ * PredLockTranList.
*/
void
RegisterSerializableTransaction(const Snapshot snapshot)
@@ -569,7 +678,6 @@ RegisterSerializableTransaction(const Snapshot snapshot)
PGPROC *proc;
SERIALIZABLEXACTTAG sxacttag;
SERIALIZABLEXACT *sxact;
- bool found;
HASHCTL hash_ctl;
/* We only do this for serializable transactions. Once. */
@@ -596,10 +704,8 @@ RegisterSerializableTransaction(const Snapshot snapshot)
{
Assert(TransactionIdFollows(snapshot->xmin, SerializableGlobalXmin));
}
- sxact = (SERIALIZABLEXACT *) hash_search(SerializableXactHash,
- &sxacttag,
- HASH_ENTER, &found);
- Assert(!found);
+ sxact = CreatePredTran();
+ /* TODO SSI: If null, cancel oldest tran and try again? */
if (!sxact)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
@@ -607,6 +713,7 @@ RegisterSerializableTransaction(const Snapshot snapshot)
errhint("You might need to increase max_predicate_locks_per_transaction.")));
/* Initialize the structure. */
+ sxact->tag = sxacttag;
sxact->outConflict = InvalidSerializableXact;
sxact->inConflict = InvalidSerializableXact;
sxact->topXid = GetTopTransactionIdIfAny();
@@ -1542,13 +1649,12 @@ PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno,
static void
SetNewSerializableGlobalXmin(void)
{
- HASH_SEQ_STATUS seqstat;
SERIALIZABLEXACT *sxact;
SerializableGlobalXmin = InvalidTransactionId;
SerializableGlobalXminCount = 0;
- hash_seq_init(&seqstat, SerializableXactHash);
- while ((sxact = (SERIALIZABLEXACT *) hash_seq_search(&seqstat)))
+
+ for (sxact = FirstPredTran(); sxact != NULL; sxact = NextPredTran(sxact))
{
if (!SxactIsOnFinishedList(sxact))
{
@@ -1662,7 +1768,6 @@ ReleasePredicateLocks(const bool isCommit)
ClearOldPredicateLocks();
MySerializableXact = InvalidSerializableXact;
- MyXid = InvalidTransactionId;
/* Delete per-transaction lock table */
hash_destroy(LocalPredicateLockHash);
@@ -1777,7 +1882,7 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact)
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
if (sxidtag.xid != InvalidTransactionId)
hash_search(SerializableXidHash, &sxidtag, HASH_REMOVE, NULL);
- hash_search(SerializableXactHash, &(sxact->tag), HASH_REMOVE, NULL);
+ ReleasePredTran(sxact);
LWLockRelease(SerializableXactHashLock);
}
@@ -1838,7 +1943,6 @@ CheckForSerializableConflictOut(const bool valid, const Relation relation,
TransactionId xid;
SERIALIZABLEXIDTAG sxidtag;
SERIALIZABLEXID *sxid;
- SERIALIZABLEXACTTAG sxacttag;
SERIALIZABLEXACT *sxact;
if (SkipSerialization(relation))
@@ -1922,18 +2026,18 @@ CheckForSerializableConflictOut(const bool valid, const Relation relation,
return;
}
- sxacttag = sxact->tag;
LWLockRelease(SerializableXactHashLock);
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
- sxact = (SERIALIZABLEXACT *)
- hash_search(SerializableXactHash, &sxacttag, HASH_FIND, NULL);
- if (!sxact)
+ sxid = (SERIALIZABLEXID *)
+ hash_search(SerializableXidHash, &sxidtag, HASH_FIND, NULL);
+ if (!sxid)
{
/* It must have been cleaned up, which means it wasn't useful. */
LWLockRelease(SerializableXactHashLock);
return;
}
+ Assert(sxid->myXact == sxact);
xid = sxact->topXid;
if (!XidIsConcurrent(xid))
{
diff --git a/src/include/storage/predicate_internal.h b/src/include/storage/predicate_internal.h
index d6a2b8c..222fc74 100644
--- a/src/include/storage/predicate_internal.h
+++ b/src/include/storage/predicate_internal.h
@@ -80,6 +80,38 @@ typedef struct SERIALIZABLEXACT
* cleanup */
} SERIALIZABLEXACT;
+/*
+ * The following types are used to provide an ad hoc list for holding
+ * SERIALIZABLEXACT objects. An HTAB is overkill, since there is no need to
+ * access these by key -- there are direct pointers to these objects where
+ * needed. If a shared memory list is created, these types can probably be
+ * eliminated in favor of using the general solution.
+ */
+typedef struct PredTranListElementData
+{
+ SHM_QUEUE link;
+ SERIALIZABLEXACT sxact;
+} PredTranListElementData;
+
+typedef struct PredTranListElementData * PredTranListElement;
+
+#define PredTranListElementDataSize \
+ ((Size)MAXALIGN(sizeof(PredTranListElementData)))
+
+typedef struct PredTranListData
+{
+ SHM_QUEUE availableList;
+ SHM_QUEUE activeList;
+ PredTranListElement element;
+ int entryLimit;
+ int entryCount;
+} PredTranListData;
+
+typedef struct PredTranListData *PredTranList;
+
+#define PredTranListDataSize \
+ ((Size)MAXALIGN(sizeof(PredTranListData)))
+
/*
* The SERIALIZABLEXIDTAG struct identifies an xid assigned to a serializable
--
1.6.3.3