Commit 742cd879 authored by Tom Lane's avatar Tom Lane

Ensure that if the OID counter wraps around, we will not generate 0,

nor any OID in the reserved range (1-16383).
parent 667d5ed2
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.28 2000/04/12 17:14:53 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.29 2000/07/25 20:18:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
static void GetNewObjectIdBlock(Oid *oid_return, int oid_block_size); static void GetNewObjectIdBlock(Oid *oid_return, int oid_block_size);
static void VariableRelationGetNextOid(Oid *oid_return); static void VariableRelationGetNextOid(Oid *oid_return);
static void VariableRelationGetNextXid(TransactionId *xidP); static void VariableRelationGetNextXid(TransactionId *xidP);
static void VariableRelationPutNextOid(Oid *oidP); static void VariableRelationPutNextOid(Oid oid);
/* --------------------- /* ---------------------
* spin lock for oid generation * spin lock for oid generation
...@@ -30,8 +30,13 @@ static void VariableRelationPutNextOid(Oid *oidP); ...@@ -30,8 +30,13 @@ static void VariableRelationPutNextOid(Oid *oidP);
*/ */
int OidGenLockId; int OidGenLockId;
/* ---------------------
* pointer to "variable cache" in shared memory (set up by shmem.c)
* ---------------------
*/
VariableCache ShmemVariableCache = NULL; VariableCache ShmemVariableCache = NULL;
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* variable relation query/update routines * variable relation query/update routines
* ---------------------------------------------------------------- * ----------------------------------------------------------------
...@@ -48,7 +53,7 @@ VariableRelationGetNextXid(TransactionId *xidP) ...@@ -48,7 +53,7 @@ VariableRelationGetNextXid(TransactionId *xidP)
VariableRelationContents var; VariableRelationContents var;
/* ---------------- /* ----------------
* We assume that a spinlock has been acquire to guarantee * We assume that a spinlock has been acquired to guarantee
* exclusive access to the variable relation. * exclusive access to the variable relation.
* ---------------- * ----------------
*/ */
...@@ -76,6 +81,7 @@ VariableRelationGetNextXid(TransactionId *xidP) ...@@ -76,6 +81,7 @@ VariableRelationGetNextXid(TransactionId *xidP)
var = (VariableRelationContents) BufferGetBlock(buf); var = (VariableRelationContents) BufferGetBlock(buf);
TransactionIdStore(var->nextXidData, xidP); TransactionIdStore(var->nextXidData, xidP);
ReleaseBuffer(buf); ReleaseBuffer(buf);
} }
...@@ -90,7 +96,7 @@ VariableRelationPutNextXid(TransactionId xid) ...@@ -90,7 +96,7 @@ VariableRelationPutNextXid(TransactionId xid)
VariableRelationContents var; VariableRelationContents var;
/* ---------------- /* ----------------
* We assume that a spinlock has been acquire to guarantee * We assume that a spinlock has been acquired to guarantee
* exclusive access to the variable relation. * exclusive access to the variable relation.
* ---------------- * ----------------
*/ */
...@@ -133,7 +139,7 @@ VariableRelationGetNextOid(Oid *oid_return) ...@@ -133,7 +139,7 @@ VariableRelationGetNextOid(Oid *oid_return)
VariableRelationContents var; VariableRelationContents var;
/* ---------------- /* ----------------
* We assume that a spinlock has been acquire to guarantee * We assume that a spinlock has been acquired to guarantee
* exclusive access to the variable relation. * exclusive access to the variable relation.
* ---------------- * ----------------
*/ */
...@@ -141,13 +147,11 @@ VariableRelationGetNextOid(Oid *oid_return) ...@@ -141,13 +147,11 @@ VariableRelationGetNextOid(Oid *oid_return)
/* ---------------- /* ----------------
* if the variable relation is not initialized, then we * if the variable relation is not initialized, then we
* assume we are running at bootstrap time and so we return * assume we are running at bootstrap time and so we return
* an invalid object id -- during this time GetNextBootstrapObjectId * an invalid object id (this path should never be taken, probably).
* should be called instead..
* ---------------- * ----------------
*/ */
if (!RelationIsValid(VariableRelation)) if (!RelationIsValid(VariableRelation))
{ {
if (PointerIsValid(oid_return))
(*oid_return) = InvalidOid; (*oid_return) = InvalidOid;
return; return;
} }
...@@ -162,32 +166,12 @@ VariableRelationGetNextOid(Oid *oid_return) ...@@ -162,32 +166,12 @@ VariableRelationGetNextOid(Oid *oid_return)
if (!BufferIsValid(buf)) if (!BufferIsValid(buf))
{ {
SpinRelease(OidGenLockId); SpinRelease(OidGenLockId);
elog(ERROR, "VariableRelationGetNextXid: ReadBuffer failed"); elog(ERROR, "VariableRelationGetNextOid: ReadBuffer failed");
} }
var = (VariableRelationContents) BufferGetBlock(buf); var = (VariableRelationContents) BufferGetBlock(buf);
if (PointerIsValid(oid_return))
{
/* ----------------
* nothing up my sleeve... what's going on here is that this code
* is guaranteed never to be called until all files in data/base/
* are created, and the template database exists. at that point,
* we want to append a pg_database tuple. the first time we do
* this, the oid stored in pg_variable will be bogus, so we use
* a bootstrap value defined at the top of this file.
*
* this comment no longer holds true. This code is called before
* all of the files in data/base are created and you can't rely
* on system oid's to be less than BootstrapObjectIdData. mer 9/18/91
* ----------------
*/
if (OidIsValid(var->nextOid))
(*oid_return) = var->nextOid; (*oid_return) = var->nextOid;
else
(*oid_return) = BootstrapObjectIdData;
}
ReleaseBuffer(buf); ReleaseBuffer(buf);
} }
...@@ -197,13 +181,13 @@ VariableRelationGetNextOid(Oid *oid_return) ...@@ -197,13 +181,13 @@ VariableRelationGetNextOid(Oid *oid_return)
* -------------------------------- * --------------------------------
*/ */
static void static void
VariableRelationPutNextOid(Oid *oidP) VariableRelationPutNextOid(Oid oid)
{ {
Buffer buf; Buffer buf;
VariableRelationContents var; VariableRelationContents var;
/* ---------------- /* ----------------
* We assume that a spinlock has been acquire to guarantee * We assume that a spinlock has been acquired to guarantee
* exclusive access to the variable relation. * exclusive access to the variable relation.
* ---------------- * ----------------
*/ */
...@@ -215,16 +199,6 @@ VariableRelationPutNextOid(Oid *oidP) ...@@ -215,16 +199,6 @@ VariableRelationPutNextOid(Oid *oidP)
if (!RelationIsValid(VariableRelation)) if (!RelationIsValid(VariableRelation))
return; return;
/* ----------------
* sanity check
* ----------------
*/
if (!PointerIsValid(oidP))
{
SpinRelease(OidGenLockId);
elog(ERROR, "VariableRelationPutNextOid: invalid oid pointer");
}
/* ---------------- /* ----------------
* read the variable page, update the nextXid field and * read the variable page, update the nextXid field and
* write the page back out to disk. * write the page back out to disk.
...@@ -240,7 +214,7 @@ VariableRelationPutNextOid(Oid *oidP) ...@@ -240,7 +214,7 @@ VariableRelationPutNextOid(Oid *oidP)
var = (VariableRelationContents) BufferGetBlock(buf); var = (VariableRelationContents) BufferGetBlock(buf);
var->nextOid = (*oidP); var->nextOid = oid;
WriteBuffer(buf); WriteBuffer(buf);
} }
...@@ -253,20 +227,20 @@ VariableRelationPutNextOid(Oid *oidP) ...@@ -253,20 +227,20 @@ VariableRelationPutNextOid(Oid *oidP)
/* ---------------- /* ----------------
* GetNewTransactionId * GetNewTransactionId
* *
* In the version 2 transaction system, transaction id's are * Transaction IDs are allocated via a cache in shared memory.
* restricted in several ways. * 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.
* *
* -- Old comments removed * Since the cache is shared across all backends, cached but unused
* * XIDs are not lost when a backend exits, only when the postmaster
* Second, since we may someday preform compression of the data * quits or forces shared memory reinit. So we can afford to have
* in the log and time relations, we cause the numbering of the * a pretty big value of VAR_XID_PREFETCH.
* transaction ids to begin at 512. This means that some space
* on the page of the log and time relations corresponding to
* transaction id's 0 - 510 will never be used. This space is
* in fact used to store the version number of the postgres
* transaction log and will someday store compression information
* about the log. -- this is also old comments...
* *
* 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.
* ---------------- * ----------------
*/ */
...@@ -352,44 +326,65 @@ ReadNewTransactionId(TransactionId *xid) ...@@ -352,44 +326,65 @@ ReadNewTransactionId(TransactionId *xid)
* GetNewObjectIdBlock * GetNewObjectIdBlock
* *
* This support function is used to allocate a block of object ids * This support function is used to allocate a block of object ids
* of the given size. applications wishing to do their own object * of the given size.
* id assignments should use this
* ---------------- * ----------------
*/ */
static void static void
GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object GetNewObjectIdBlock(Oid *oid_return, /* place to return the first new
* id */ * object id */
int oid_block_size) /* number of oids desired */ int oid_block_size) /* number of oids desired */
{ {
Oid firstfreeoid;
Oid nextoid; Oid nextoid;
/* ---------------- /* ----------------
* SOMEDAY obtain exclusive access to the variable relation page * Obtain exclusive access to the variable relation page
* That someday is today -mer 6 Aug 1992
* ---------------- * ----------------
*/ */
SpinAcquire(OidGenLockId); SpinAcquire(OidGenLockId);
/* ---------------- /* ----------------
* get the "next" oid from the variable relation * get the "next" oid from the variable relation
* and give it to the caller.
* ---------------- * ----------------
*/ */
VariableRelationGetNextOid(&nextoid); VariableRelationGetNextOid(&firstfreeoid);
if (PointerIsValid(oid_return))
(*oid_return) = nextoid;
/* ---------------- /* ----------------
* now increment the variable relation's next oid * Allocate the range of OIDs to be returned to the caller.
* field by the size of the oid block requested. *
* 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.
* ---------------- * ----------------
*/ */
nextoid += oid_block_size; VariableRelationPutNextOid(nextoid);
VariableRelationPutNextOid(&nextoid);
/* ---------------- /* ----------------
* SOMEDAY relinquish our lock on the variable relation page * Relinquish our lock on the variable relation page
* That someday is today -mer 6 Apr 1992
* ---------------- * ----------------
*/ */
SpinRelease(OidGenLockId); SpinRelease(OidGenLockId);
...@@ -406,9 +401,14 @@ GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object ...@@ -406,9 +401,14 @@ GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object
* relation by 32 for each backend. * relation by 32 for each backend.
* *
* Note: 32 has no special significance. We don't want the * Note: 32 has no special significance. We don't want the
* number to be too large because if when the backend * number to be too large because when the backend
* terminates, we lose the oids we cached. * 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.
* ---------------- * ----------------
*/ */
...@@ -431,11 +431,7 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */ ...@@ -431,11 +431,7 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */
int oid_block_size = VAR_OID_PREFETCH; int oid_block_size = VAR_OID_PREFETCH;
/* ---------------- /* ----------------
* during bootstrap time, we want to allocate oids * Make sure pg_variable is open.
* one at a time. Otherwise there might be some
* bootstrap oid's left in the block we prefetch which
* would be passed out after the variable relation was
* initialized. This would be bad.
* ---------------- * ----------------
*/ */
if (!RelationIsValid(VariableRelation)) if (!RelationIsValid(VariableRelation))
...@@ -469,12 +465,11 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */ ...@@ -469,12 +465,11 @@ GetNewObjectId(Oid *oid_return) /* place to return the new object id */
void void
CheckMaxObjectId(Oid assigned_oid) CheckMaxObjectId(Oid assigned_oid)
{ {
Oid pass_oid; Oid temp_oid;
if (prefetched_oid_count == 0) /* make sure next/max is set, or if (prefetched_oid_count == 0) /* make sure next/max is set, or
* reload */ * reload */
GetNewObjectId(&pass_oid); GetNewObjectId(&temp_oid);
/* ---------------- /* ----------------
* If we are below prefetched limits, do nothing * If we are below prefetched limits, do nothing
...@@ -488,7 +483,6 @@ CheckMaxObjectId(Oid assigned_oid) ...@@ -488,7 +483,6 @@ CheckMaxObjectId(Oid assigned_oid)
* If we are here, we are coming from a 'copy from' with oid's * 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 * If we are in the prefetched oid range, just bump it up
*
* ---------------- * ----------------
*/ */
...@@ -506,21 +500,19 @@ CheckMaxObjectId(Oid assigned_oid) ...@@ -506,21 +500,19 @@ CheckMaxObjectId(Oid assigned_oid)
* but we are loading oid's that we can not guarantee are unique * but we are loading oid's that we can not guarantee are unique
* anyway, so we must rely on the user * anyway, so we must rely on the user
* *
*
* We now: * We now:
* set the variable relation with the new max oid * set the variable relation with the new max oid
* force the backend to reload its oid cache * force the backend to reload its oid cache
* *
* We use the oid cache so we don't have to update the variable * By reloading the oid cache, we don't have to update the variable
* relation every time * relation every time when sequential OIDs are being loaded by COPY.
*
* ---------------- * ----------------
*/ */
pass_oid = assigned_oid; SpinAcquire(OidGenLockId);
VariableRelationPutNextOid(&pass_oid); /* not modified */ VariableRelationPutNextOid(assigned_oid);
prefetched_oid_count = 0; /* force reload */ SpinRelease(OidGenLockId);
pass_oid = assigned_oid;
GetNewObjectId(&pass_oid); /* throw away returned oid */
prefetched_oid_count = 0; /* force reload */
GetNewObjectId(&temp_oid); /* cause target OID to be allocated */
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment