On Sat, Jan 16, 2016 at 10:23 AM, Amit Kapila <amit.kapil...@gmail.com> wrote:
> >On Fri, Jan 15, 2016 at 11:23 AM, Mithun Cy <mithun...@enterprisedb.com> > wrote: > >> On Mon, Jan 4, 2016 at 2:28 PM, Andres Freund <and...@anarazel.de> wrote: >> >> >> I think at the very least the cache should be protected by a separate >> >> lock, and that lock should be acquired with TryLock. I.e. the cache is >> >> updated opportunistically. I'd go for an lwlock in the first iteration. >> > > >I also think this observation of yours is right and currently that is > >okay because we always first check TransactionIdIsCurrentTransactionId(). > > >+ const uint32 snapshot_cached= 0; > I have fixed all of the issues reported by regress test. Also now when backend try to cache the snapshot we also try to store the self-xid and sub xid, so other backends can use them. I also did some read-only perf tests. Non-Default Settings. ================ scale_factor=300. ./postgres -c shared_buffers=16GB -N 200 -c min_wal_size=15GB -c max_wal_size=20GB -c checkpoint_timeout=900 -c maintenance_work_mem=1GB -c checkpoint_completion_target=0.9 ./pgbench -c $clients -j $clients -T 300 -M prepared -S postgres Machine Detail: cpu : POWER8 cores: 24 (192 with HT). Clients Base With cached snapshot 1 19653.914409 19926.884664 16 190764.519336 190040.299297 32 339327.881272 354467.445076 48 462632.02493 464767.917813 64 522642.515148 533271.556703 80 515262.813189 513353.962521 But did not see any perf improvement. Will continue testing the same. -- Thanks and Regards Mithun C Y EnterpriseDB: http://www.enterprisedb.com
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 5cb28cf..a441ca0 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1561,6 +1561,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, elog(ERROR, "cache lookup failed for relation %u", OIDOldHeap); relform = (Form_pg_class) GETSTRUCT(reltup); + Assert(TransactionIdIsNormal(frozenXid)); relform->relfrozenxid = frozenXid; relform->relminmxid = cutoffMulti; diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 97e8962..8db028f 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -372,11 +372,19 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid) (arrayP->numProcs - index - 1) * sizeof(int)); arrayP->pgprocnos[arrayP->numProcs - 1] = -1; /* for debugging */ arrayP->numProcs--; + + pg_atomic_write_u32(&ProcGlobal->snapshot_cached, 0); + + ProcGlobal->cached_snapshot_valid = false; LWLockRelease(ProcArrayLock); return; } } + pg_atomic_write_u32(&ProcGlobal->snapshot_cached, 0); + + ProcGlobal->cached_snapshot_valid = false; + /* Ooops */ LWLockRelease(ProcArrayLock); @@ -420,6 +428,8 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid) if (LWLockConditionalAcquire(ProcArrayLock, LW_EXCLUSIVE)) { ProcArrayEndTransactionInternal(proc, pgxact, latestXid); + pg_atomic_write_u32(&ProcGlobal->snapshot_cached, 0); + ProcGlobal->cached_snapshot_valid = false; LWLockRelease(ProcArrayLock); } else @@ -568,6 +578,9 @@ ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid) nextidx = pg_atomic_read_u32(&proc->procArrayGroupNext); } + pg_atomic_write_u32(&ProcGlobal->snapshot_cached, 0); + ProcGlobal->cached_snapshot_valid = false; + /* We're done with the lock now. */ LWLockRelease(ProcArrayLock); @@ -1553,6 +1566,8 @@ GetSnapshotData(Snapshot snapshot) errmsg("out of memory"))); } + snapshot->takenDuringRecovery = RecoveryInProgress(); + /* * It is sufficient to get shared lock on ProcArrayLock, even if we are * going to set MyPgXact->xmin. @@ -1567,12 +1582,39 @@ GetSnapshotData(Snapshot snapshot) /* initialize xmin calculation with xmax */ globalxmin = xmin = xmax; - snapshot->takenDuringRecovery = RecoveryInProgress(); + if (!snapshot->takenDuringRecovery && ProcGlobal->cached_snapshot_valid) + { + Snapshot csnap = &ProcGlobal->cached_snapshot; + TransactionId *saved_xip; + TransactionId *saved_subxip; - if (!snapshot->takenDuringRecovery) + saved_xip = snapshot->xip; + saved_subxip = snapshot->subxip; + + memcpy(snapshot, csnap, sizeof(SnapshotData)); + + snapshot->xip = saved_xip; + snapshot->subxip = saved_subxip; + + memcpy(snapshot->xip, csnap->xip, + sizeof(TransactionId) * csnap->xcnt); + memcpy(snapshot->subxip, csnap->subxip, + sizeof(TransactionId) * csnap->subxcnt); + globalxmin = ProcGlobal->cached_snapshot_globalxmin; + xmin = csnap->xmin; + + count = csnap->xcnt; + subcount = csnap->subxcnt; + suboverflowed = csnap->suboverflowed; + + Assert(TransactionIdIsValid(globalxmin)); + Assert(TransactionIdIsValid(xmin)); + } + else if (!snapshot->takenDuringRecovery) { int *pgprocnos = arrayP->pgprocnos; int numProcs; + uint32 snapshot_cached= 0; /* * Spin over procArray checking xid, xmin, and subxids. The goal is @@ -1587,14 +1629,11 @@ GetSnapshotData(Snapshot snapshot) TransactionId xid; /* - * Backend is doing logical decoding which manages xmin - * separately, check below. + * Ignore procs running LAZY VACUUM (which don't need to retain + * rows) and backends doing logical decoding (which manages xmin + * separately, check below). */ - if (pgxact->vacuumFlags & PROC_IN_LOGICAL_DECODING) - continue; - - /* Ignore procs running LAZY VACUUM */ - if (pgxact->vacuumFlags & PROC_IN_VACUUM) + if (pgxact->vacuumFlags & (PROC_IN_LOGICAL_DECODING | PROC_IN_VACUUM)) continue; /* Update globalxmin to be the smallest valid xmin */ @@ -1663,6 +1702,62 @@ GetSnapshotData(Snapshot snapshot) } } } + + /* + * Let only one of the caller cache the computed snapshot, and others + * can continue as before. + */ + if (pg_atomic_compare_exchange_u32(&ProcGlobal->snapshot_cached, + &snapshot_cached, 1)) + { + Snapshot csnap = &ProcGlobal->cached_snapshot; + TransactionId *saved_xip; + TransactionId *saved_subxip; + int curr_subcount= subcount; + + ProcGlobal->cached_snapshot_globalxmin = globalxmin; + + saved_xip = csnap->xip; + saved_subxip = csnap->subxip; + memcpy(csnap, snapshot, sizeof(SnapshotData)); + csnap->xip = saved_xip; + csnap->subxip = saved_subxip; + + /* not yet stored. Yuck */ + csnap->xmin = xmin; + + memcpy(csnap->xip, snapshot->xip, + sizeof(TransactionId) * count); + memcpy(csnap->subxip, snapshot->subxip, + sizeof(TransactionId) * subcount); + + /* Add my own XID to snapshot. */ + csnap->xip[count] = MyPgXact->xid; + csnap->xcnt = count + 1; + + if (!suboverflowed) + { + if (MyPgXact->overflowed) + suboverflowed = true; + else + { + int nxids = MyPgXact->nxids; + + if (nxids > 0) + { + memcpy(csnap->subxip + subcount, + (void *) MyProc->subxids.xids, + nxids * sizeof(TransactionId)); + curr_subcount += nxids; + } + } + } + + csnap->subxcnt = curr_subcount; + csnap->suboverflowed = suboverflowed; + + ProcGlobal->cached_snapshot_valid = true; + } } else { diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 6453b88..b8d0297 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -51,7 +51,7 @@ #include "storage/spin.h" #include "utils/timeout.h" #include "utils/timestamp.h" - +#include "port/atomics.h" /* GUC variables */ int DeadlockTimeout = 1000; @@ -114,6 +114,13 @@ ProcGlobalShmemSize(void) size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT))); size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT))); + /* for the cached snapshot */ +#define PROCARRAY_MAXPROCS (MaxBackends + max_prepared_xacts) + size = add_size(size, mul_size(sizeof(TransactionId), PROCARRAY_MAXPROCS)); +#define TOTAL_MAX_CACHED_SUBXIDS \ + ((PGPROC_MAX_CACHED_SUBXIDS + 1) * PROCARRAY_MAXPROCS) + size = add_size(size, mul_size(sizeof(TransactionId), TOTAL_MAX_CACHED_SUBXIDS)); + return size; } @@ -278,6 +285,13 @@ InitProcGlobal(void) /* Create ProcStructLock spinlock, too */ ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t)); SpinLockInit(ProcStructLock); + + /* cached snapshot */ + ProcGlobal->cached_snapshot_valid = false; + pg_atomic_write_u32(&ProcGlobal->snapshot_cached, 0); + ProcGlobal->cached_snapshot.xip = ShmemAlloc(PROCARRAY_MAXPROCS * sizeof(TransactionId)); + ProcGlobal->cached_snapshot.subxip = ShmemAlloc(TOTAL_MAX_CACHED_SUBXIDS * sizeof(TransactionId)); + ProcGlobal->cached_snapshot_globalxmin = InvalidTransactionId; } /* diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index dbcdd3f..73a424e 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -16,6 +16,7 @@ #include "access/xlogdefs.h" #include "lib/ilist.h" +#include "utils/snapshot.h" #include "storage/latch.h" #include "storage/lock.h" #include "storage/pg_sema.h" @@ -234,6 +235,12 @@ typedef struct PROC_HDR int startupProcPid; /* Buffer id of the buffer that Startup process waits for pin on, or -1 */ int startupBufferPinWaitBufId; + + /* Cached snapshot */ + volatile bool cached_snapshot_valid; + pg_atomic_uint32 snapshot_cached; + SnapshotData cached_snapshot; + TransactionId cached_snapshot_globalxmin; } PROC_HDR; extern PROC_HDR *ProcGlobal;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers