aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/varsup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/varsup.c')
-rw-r--r--src/backend/access/transam/varsup.c505
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 */