diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 1951103b26..b85c046b41 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7300,6 +7300,19 @@ StartupXLOG(void) TransactionIdIsValid(record->xl_xid)) RecordKnownAssignedTransactionIds(record->xl_xid); + /* + * Assign subtransaction xids to the top level xid if the + * record has that information. This is required at most + * once per subtransactions. + */ + if (TransactionIdIsValid(xlogreader->toplevel_xid) && + standbyState >= STANDBY_INITIALIZED) + { + Assert(XLogStandbyInfoActive()); + ProcArrayCacheXidAssignment(xlogreader->toplevel_xid, + record->xl_xid); + } + /* Now apply the WAL record itself */ RmgrTable[record->xl_rmid].rm_redo(xlogreader); diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index cfb88db4a4..efddd0e1e6 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -958,6 +958,53 @@ ProcArrayApplyXidAssignment(TransactionId topxid, LWLockRelease(ProcArrayLock); } +static HTAB *xidAssignmentsHash = NULL; + +typedef struct XidAssignmentEntry +{ + /* the hash lookup key MUST BE FIRST */ + TransactionId topXid; + + int nsubxids; + TransactionId subxids[PGPROC_MAX_CACHED_SUBXIDS]; +} XidAssignmentEntry; + +void +ProcArrayCacheXidAssignment(TransactionId topXid, TransactionId subXid) +{ + XidAssignmentEntry *entry; + bool found; + + if (xidAssignmentsHash == NULL) + { + /* First time through: initialize the hash table */ + HASHCTL ctl; + + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(TransactionId); + ctl.entrysize = sizeof(XidAssignmentEntry); + xidAssignmentsHash = hash_create("XID assignment cache", 256, + &ctl, HASH_ELEM | HASH_BLOBS); + } + + /* Look for an existing entry */ + entry = (XidAssignmentEntry *) hash_search(xidAssignmentsHash, + (void *) &topXid, + HASH_ENTER, &found); + + if (!found) + entry->nsubxids = 0; + + entry->subxids[entry->nsubxids++] = subXid; + + /* after reaching the limit, apply the assignments for this top XID */ + if (entry->nsubxids == PGPROC_MAX_CACHED_SUBXIDS) + { + ProcArrayApplyXidAssignment(topXid, entry->nsubxids, entry->subxids); + entry->nsubxids = 0; + } +} + /* * TransactionIdIsInProgress -- is given transaction running in some backend * diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index a5c7d0c064..17d89bdd7e 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -67,6 +67,7 @@ extern void ProcArrayInitRecovery(TransactionId initializedUptoXID); extern void ProcArrayApplyRecoveryInfo(RunningTransactions running); extern void ProcArrayApplyXidAssignment(TransactionId topxid, int nsubxids, TransactionId *subxids); +extern void ProcArrayCacheXidAssignment(TransactionId topxid, TransactionId subxid); extern void RecordKnownAssignedTransactionIds(TransactionId xid); extern void ExpireTreeKnownAssignedTransactionIds(TransactionId xid,