mirror of
https://github.com/postgres/postgres.git
synced 2025-07-14 08:21:07 +03:00
Ensure that if the OID counter wraps around, we will not generate 0,
nor any OID in the reserved range (1-16383).
This commit is contained in:
@ -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 @@
|
|||||||
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);
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* 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)
|
|||||||
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)
|
|||||||
* --------------------------------
|
* --------------------------------
|
||||||
*/
|
*/
|
||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
/* ----------------
|
/* ----------------
|
||||||
* 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)
|
|||||||
* 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
|
|||||||
* 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 */
|
|||||||
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 */
|
|||||||
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)
|
|||||||
* 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)
|
|||||||
* 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 */
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user