diff options
Diffstat (limited to 'src/backend/access/transam/varsup.c')
-rw-r--r-- | src/backend/access/transam/varsup.c | 505 |
1 files changed, 62 insertions, 443 deletions
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c index 75a568f8fde..3c81cb207ab 100644 --- a/src/backend/access/transam/varsup.c +++ b/src/backend/access/transam/varsup.c @@ -1,290 +1,51 @@ /*------------------------------------------------------------------------- * * varsup.c - * postgres variable relation support routines - * - * Portions Copyright (c) 1996-2000, PostgreSQL, Inc - * Portions Copyright (c) 1994, Regents of the University of California + * postgres OID & XID variables support routines * + * Copyright (c) 2000, PostgreSQL, Inc * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.33 2000/11/20 16:47:30 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.34 2000/11/30 08:46:22 vadim Exp $ * *------------------------------------------------------------------------- */ -#include "postgres.h" -#ifdef XLOG -#include "xlog_varsup.c" -#else +#include "postgres.h" -#include "access/heapam.h" -#include "catalog/catname.h" +#include "access/transam.h" #include "storage/proc.h" -static void GetNewObjectIdBlock(Oid *oid_return, int oid_block_size); -static void VariableRelationGetNextOid(Oid *oid_return); -static void VariableRelationGetNextXid(TransactionId *xidP); -static void VariableRelationPutNextOid(Oid oid); +SPINLOCK OidGenLockId; -/* --------------------- - * spin lock for oid generation - * --------------------- - */ -int OidGenLockId; +extern SPINLOCK XidGenLockId; +extern void XLogPutNextOid(Oid nextOid); -/* --------------------- - * pointer to "variable cache" in shared memory (set up by shmem.c) - * --------------------- - */ +/* pointer to "variable cache" in shared memory (set up by shmem.c) */ VariableCache ShmemVariableCache = NULL; - -/* ---------------------------------------------------------------- - * variable relation query/update routines - * ---------------------------------------------------------------- - */ - -/* -------------------------------- - * VariableRelationGetNextXid - * -------------------------------- - */ -static void -VariableRelationGetNextXid(TransactionId *xidP) -{ - Buffer buf; - VariableRelationContents var; - - /* ---------------- - * We assume that a spinlock has been acquired to guarantee - * exclusive access to the variable relation. - * ---------------- - */ - - /* ---------------- - * do nothing before things are initialized - * ---------------- - */ - if (!RelationIsValid(VariableRelation)) - return; - - /* ---------------- - * read the variable page, get the the nextXid field and - * release the buffer - * ---------------- - */ - buf = ReadBuffer(VariableRelation, 0); - - if (!BufferIsValid(buf)) - { - SpinRelease(OidGenLockId); - elog(ERROR, "VariableRelationGetNextXid: ReadBuffer failed"); - } - - var = (VariableRelationContents) BufferGetBlock(buf); - - TransactionIdStore(var->nextXidData, xidP); - - ReleaseBuffer(buf); -} - -/* -------------------------------- - * VariableRelationPutNextXid - * -------------------------------- - */ -void -VariableRelationPutNextXid(TransactionId xid) -{ - Buffer buf; - VariableRelationContents var; - - /* ---------------- - * We assume that a spinlock has been acquired to guarantee - * exclusive access to the variable relation. - * ---------------- - */ - - /* ---------------- - * do nothing before things are initialized - * ---------------- - */ - if (!RelationIsValid(VariableRelation)) - return; - - /* ---------------- - * read the variable page, update the nextXid field and - * write the page back out to disk (with immediate write). - * ---------------- - */ - buf = ReadBuffer(VariableRelation, 0); - - if (!BufferIsValid(buf)) - { - SpinRelease(OidGenLockId); - elog(ERROR, "VariableRelationPutNextXid: ReadBuffer failed"); - } - - var = (VariableRelationContents) BufferGetBlock(buf); - - TransactionIdStore(xid, &(var->nextXidData)); - - FlushBuffer(buf, true, true); -} - -/* -------------------------------- - * VariableRelationGetNextOid - * -------------------------------- - */ -static void -VariableRelationGetNextOid(Oid *oid_return) -{ - Buffer buf; - VariableRelationContents var; - - /* ---------------- - * We assume that a spinlock has been acquired to guarantee - * exclusive access to the variable relation. - * ---------------- - */ - - /* ---------------- - * if the variable relation is not initialized, then we - * assume we are running at bootstrap time and so we return - * an invalid object id (this path should never be taken, probably). - * ---------------- - */ - if (!RelationIsValid(VariableRelation)) - { - (*oid_return) = InvalidOid; - return; - } - - /* ---------------- - * read the variable page, get the the nextOid field and - * release the buffer - * ---------------- - */ - buf = ReadBuffer(VariableRelation, 0); - - if (!BufferIsValid(buf)) - { - SpinRelease(OidGenLockId); - elog(ERROR, "VariableRelationGetNextOid: ReadBuffer failed"); - } - - var = (VariableRelationContents) BufferGetBlock(buf); - - (*oid_return) = var->nextOid; - - ReleaseBuffer(buf); -} - -/* -------------------------------- - * VariableRelationPutNextOid - * -------------------------------- - */ -static void -VariableRelationPutNextOid(Oid oid) -{ - Buffer buf; - VariableRelationContents var; - - /* ---------------- - * We assume that a spinlock has been acquired to guarantee - * exclusive access to the variable relation. - * ---------------- - */ - - /* ---------------- - * do nothing before things are initialized - * ---------------- - */ - if (!RelationIsValid(VariableRelation)) - return; - - /* ---------------- - * read the variable page, update the nextXid field and - * write the page back out to disk. - * ---------------- - */ - buf = ReadBuffer(VariableRelation, 0); - - if (!BufferIsValid(buf)) - { - SpinRelease(OidGenLockId); - elog(ERROR, "VariableRelationPutNextOid: ReadBuffer failed"); - } - - var = (VariableRelationContents) BufferGetBlock(buf); - - var->nextOid = oid; - - WriteBuffer(buf); -} - -/* ---------------------------------------------------------------- - * transaction id generation support - * ---------------------------------------------------------------- - */ - -/* ---------------- - * GetNewTransactionId - * - * Transaction IDs are allocated via a cache in shared memory. - * Each time we need more IDs, we advance the "next XID" value - * in pg_variable by VAR_XID_PREFETCH and set the cache to - * show that many XIDs as available. Then, allocating those XIDs - * requires just a spinlock and not a buffer read/write cycle. - * - * Since the cache is shared across all backends, cached but unused - * XIDs are not lost when a backend exits, only when the postmaster - * quits or forces shared memory reinit. So we can afford to have - * a pretty big value of VAR_XID_PREFETCH. - * - * This code does not worry about initializing the transaction counter - * (see transam.c's InitializeTransactionLog() for that). We also - * ignore the possibility that the counter could someday wrap around. - * ---------------- - */ - -#define VAR_XID_PREFETCH 1024 - void GetNewTransactionId(TransactionId *xid) { - - /* ---------------- - * during bootstrap initialization, we return the special - * bootstrap transaction id. - * ---------------- + /* + * During bootstrap initialization, we return the special + * bootstrap transaction id. */ if (AMI_OVERRIDE) { - TransactionIdStore(AmiTransactionId, xid); + *xid = AmiTransactionId; return; } - SpinAcquire(OidGenLockId); /* not good for concurrency... */ - - if (ShmemVariableCache->xid_count == 0) - { - TransactionId nextid; - - VariableRelationGetNextXid(&nextid); - TransactionIdStore(nextid, &(ShmemVariableCache->nextXid)); - ShmemVariableCache->xid_count = VAR_XID_PREFETCH; - TransactionIdAdd(&nextid, VAR_XID_PREFETCH); - VariableRelationPutNextXid(nextid); - } - - TransactionIdStore(ShmemVariableCache->nextXid, xid); - TransactionIdAdd(&(ShmemVariableCache->nextXid), 1); - (ShmemVariableCache->xid_count)--; + SpinAcquire(XidGenLockId); + *xid = ShmemVariableCache->nextXid; + (ShmemVariableCache->nextXid)++; if (MyProc != (PROC *) NULL) MyProc->xid = *xid; - SpinRelease(OidGenLockId); + SpinRelease(XidGenLockId); + } /* @@ -294,30 +55,20 @@ void ReadNewTransactionId(TransactionId *xid) { - /* ---------------- - * during bootstrap initialization, we return the special - * bootstrap transaction id. - * ---------------- + /* + * During bootstrap initialization, we return the special + * bootstrap transaction id. */ if (AMI_OVERRIDE) { - TransactionIdStore(AmiTransactionId, xid); + *xid = AmiTransactionId; return; } - SpinAcquire(OidGenLockId); /* not good for concurrency... */ + SpinAcquire(XidGenLockId); + *xid = ShmemVariableCache->nextXid; + SpinRelease(XidGenLockId); - /* - * Note that we don't check is ShmemVariableCache->xid_count equal to - * 0 or not. This will work as long as we don't call - * ReadNewTransactionId() before GetNewTransactionId(). - */ - if (ShmemVariableCache->nextXid == 0) - elog(ERROR, "ReadNewTransactionId: ShmemVariableCache->nextXid is not initialized"); - - TransactionIdStore(ShmemVariableCache->nextXid, xid); - - SpinRelease(OidGenLockId); } /* ---------------------------------------------------------------- @@ -325,199 +76,67 @@ ReadNewTransactionId(TransactionId *xid) * ---------------------------------------------------------------- */ -/* ---------------- - * GetNewObjectIdBlock - * - * This support function is used to allocate a block of object ids - * of the given size. - * ---------------- - */ -static void -GetNewObjectIdBlock(Oid *oid_return, /* place to return the first new - * object id */ - int oid_block_size) /* number of oids desired */ -{ - Oid firstfreeoid; - Oid nextoid; - - /* ---------------- - * Obtain exclusive access to the variable relation page - * ---------------- - */ - SpinAcquire(OidGenLockId); - - /* ---------------- - * get the "next" oid from the variable relation - * ---------------- - */ - VariableRelationGetNextOid(&firstfreeoid); - - /* ---------------- - * Allocate the range of OIDs to be returned to the caller. - * - * There are two things going on here. - * - * One: in a virgin database pg_variable will initially contain zeroes, - * so we will read out firstfreeoid = InvalidOid. We want to start - * allocating OIDs at BootstrapObjectIdData instead (OIDs below that - * are reserved for static assignment in the initial catalog data). - * - * Two: if a database is run long enough, the OID counter will wrap - * around. We must not generate an invalid OID when that happens, - * and it seems wise not to generate anything in the reserved range. - * Therefore we advance to BootstrapObjectIdData in this case too. - * - * The comparison here assumes that Oid is an unsigned type. - */ - nextoid = firstfreeoid + oid_block_size; - - if (! OidIsValid(firstfreeoid) || nextoid < firstfreeoid) - { - /* Initialization or wraparound time, force it up to safe range */ - firstfreeoid = BootstrapObjectIdData; - nextoid = firstfreeoid + oid_block_size; - } - - (*oid_return) = firstfreeoid; - - /* ---------------- - * Update the variable relation to show the block range as used. - * ---------------- - */ - VariableRelationPutNextOid(nextoid); - - /* ---------------- - * Relinquish our lock on the variable relation page - * ---------------- - */ - SpinRelease(OidGenLockId); -} - -/* ---------------- - * GetNewObjectId - * - * This function allocates and parses out object ids. Like - * GetNewTransactionId(), it "prefetches" 32 object ids by - * incrementing the nextOid stored in the var relation by 32 and then - * returning these id's one at a time until they are exhausted. - * This means we reduce the number of accesses to the variable - * relation by 32 for each backend. - * - * Note: 32 has no special significance. We don't want the - * number to be too large because when the backend - * terminates, we lose the oids we cached. - * - * Question: couldn't we use a shared-memory cache just like XIDs? - * That would allow a larger interval between pg_variable updates - * without cache losses. Note, however, that we can assign an OID - * without even a spinlock from the backend-local OID cache. - * Maybe two levels of caching would be good. - * ---------------- - */ - -#define VAR_OID_PREFETCH 32 - -static int prefetched_oid_count = 0; -static Oid next_prefetched_oid; +#define VAR_OID_PREFETCH 8192 +static Oid lastSeenOid = InvalidOid; void -GetNewObjectId(Oid *oid_return) /* place to return the new object id */ +GetNewObjectId(Oid *oid_return) { - /* ---------------- - * if we run out of prefetched oids, then we get some - * more before handing them out to the caller. - * ---------------- - */ + SpinAcquire(OidGenLockId); - if (prefetched_oid_count == 0) + /* If we run out of logged for use oids then we log more */ + if (ShmemVariableCache->oidCount == 0) { - int oid_block_size = VAR_OID_PREFETCH; - - /* ---------------- - * Make sure pg_variable is open. - * ---------------- - */ - if (!RelationIsValid(VariableRelation)) - VariableRelation = heap_openr(VariableRelationName, NoLock); - - /* ---------------- - * get a new block of prefetched object ids. - * ---------------- - */ - GetNewObjectIdBlock(&next_prefetched_oid, oid_block_size); - - /* ---------------- - * now reset the prefetched_oid_count. - * ---------------- - */ - prefetched_oid_count = oid_block_size; + XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH); + ShmemVariableCache->oidCount = VAR_OID_PREFETCH; } - /* ---------------- - * return the next prefetched oid in the pointer passed by - * the user and decrement the prefetch count. - * ---------------- - */ if (PointerIsValid(oid_return)) - (*oid_return) = next_prefetched_oid; + lastSeenOid = (*oid_return) = ShmemVariableCache->nextOid; - next_prefetched_oid++; - prefetched_oid_count--; + (ShmemVariableCache->nextOid)++; + (ShmemVariableCache->oidCount)--; + + SpinRelease(OidGenLockId); } void CheckMaxObjectId(Oid assigned_oid) { - Oid temp_oid; - if (prefetched_oid_count == 0) /* make sure next/max is set, or - * reload */ - GetNewObjectId(&temp_oid); - - /* ---------------- - * If we are below prefetched limits, do nothing - * ---------------- - */ - - if (assigned_oid < next_prefetched_oid) + if (lastSeenOid != InvalidOid && assigned_oid < lastSeenOid) return; - /* ---------------- - * If we are here, we are coming from a 'copy from' with oid's - * - * If we are in the prefetched oid range, just bump it up - * ---------------- - */ + SpinAcquire(OidGenLockId); + if (assigned_oid < ShmemVariableCache->nextOid) + { + lastSeenOid = ShmemVariableCache->nextOid - 1; + SpinRelease(OidGenLockId); + return; + } - if (assigned_oid <= next_prefetched_oid + prefetched_oid_count - 1) + /* If we are in the logged oid range, just bump nextOid up */ + if (assigned_oid <= ShmemVariableCache->nextOid + + ShmemVariableCache->oidCount - 1) { - prefetched_oid_count -= assigned_oid - next_prefetched_oid + 1; - next_prefetched_oid = assigned_oid + 1; + ShmemVariableCache->oidCount -= + assigned_oid - ShmemVariableCache->nextOid + 1; + ShmemVariableCache->nextOid = assigned_oid + 1; + SpinRelease(OidGenLockId); return; } - /* ---------------- - * We have exceeded the prefetch oid range - * - * We should lock the database and kill all other backends - * but we are loading oid's that we can not guarantee are unique - * anyway, so we must rely on the user - * - * We now: - * set the variable relation with the new max oid - * force the backend to reload its oid cache - * - * By reloading the oid cache, we don't have to update the variable - * relation every time when sequential OIDs are being loaded by COPY. - * ---------------- + /* + * We have exceeded the logged oid range. + * We should lock the database and kill all other backends + * but we are loading oid's that we can not guarantee are unique + * anyway, so we must rely on the user. */ - SpinAcquire(OidGenLockId); - VariableRelationPutNextOid(assigned_oid); + XLogPutNextOid(assigned_oid + VAR_OID_PREFETCH); + ShmemVariableCache->oidCount = VAR_OID_PREFETCH - 1; + ShmemVariableCache->nextOid = assigned_oid + 1; + SpinRelease(OidGenLockId); - prefetched_oid_count = 0; /* force reload */ - GetNewObjectId(&temp_oid); /* cause target OID to be allocated */ } - -#endif /* !XLOG */ |