From e29927c7966adba2443fdc4f64da9d282f95a05b Mon Sep 17 00:00:00 2001 From: Kevin Grittner 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 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