mirror of
https://github.com/postgres/postgres.git
synced 2025-08-28 18:48:04 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
606
src/backend/access/transam/varsup.c
Normal file
606
src/backend/access/transam/varsup.c
Normal file
@@ -0,0 +1,606 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* varsup.c--
|
||||
* postgres variable relation support routines
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/varsup.c,v 1.1.1.1 1996/07/09 06:21:13 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <math.h>
|
||||
#include "postgres.h"
|
||||
|
||||
#include "machine.h" /* in port/ directory (needed for BLCKSZ) */
|
||||
#include "storage/buf.h"
|
||||
#include "storage/bufmgr.h"
|
||||
#include "storage/ipc.h" /* for OIDGENLOCKID */
|
||||
|
||||
#include "utils/rel.h"
|
||||
#include "utils/elog.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "access/transam.h" /* where the declarations go */
|
||||
#include "access/xact.h" /* where the declarations go */
|
||||
|
||||
#include "catalog/catname.h"
|
||||
|
||||
/* ----------
|
||||
* note: we reserve the first 16384 object ids for internal use.
|
||||
* oid's less than this appear in the .bki files. the choice of
|
||||
* 16384 is completely arbitrary.
|
||||
* ----------
|
||||
*/
|
||||
#define BootstrapObjectIdData 16384
|
||||
|
||||
/* ---------------------
|
||||
* spin lock for oid generation
|
||||
* ---------------------
|
||||
*/
|
||||
int OidGenLockId;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* variable relation query/update routines
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationGetNextXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationGetNextXid(TransactionId *xidP)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire 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(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(var->nextXidData, xidP);
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationGetLastXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationGetLastXid(TransactionId *xidP)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire 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 lastXid field and
|
||||
* release the buffer
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(var->lastXidData, xidP);
|
||||
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationPutNextXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationPutNextXid(TransactionId xid)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire 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(WARN, "VariableRelationPutNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(xid, &(var->nextXidData));
|
||||
|
||||
WriteBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationPutLastXid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationPutLastXid(TransactionId xid)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* read the variable page, update the lastXid field and
|
||||
* force the page back out to disk.
|
||||
* ----------------
|
||||
*/
|
||||
buf = ReadBuffer(VariableRelation, 0);
|
||||
|
||||
if (! BufferIsValid(buf))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationPutLastXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
TransactionIdStore(xid, &(var->lastXidData));
|
||||
|
||||
WriteBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationGetNextOid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationGetNextOid(Oid *oid_return)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire 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 -- during this time GetNextBootstrapObjectId
|
||||
* should be called instead..
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation)) {
|
||||
if (PointerIsValid(oid_return))
|
||||
(*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(WARN, "VariableRelationGetNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
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;
|
||||
else
|
||||
(*oid_return) = BootstrapObjectIdData;
|
||||
}
|
||||
|
||||
ReleaseBuffer(buf);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* VariableRelationPutNextOid
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
VariableRelationPutNextOid(Oid *oidP)
|
||||
{
|
||||
Buffer buf;
|
||||
VariableRelationContents var;
|
||||
|
||||
/* ----------------
|
||||
* We assume that a spinlock has been acquire to guarantee
|
||||
* exclusive access to the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* do nothing before things are initialized
|
||||
* ----------------
|
||||
*/
|
||||
if (! RelationIsValid(VariableRelation))
|
||||
return;
|
||||
|
||||
/* ----------------
|
||||
* sanity check
|
||||
* ----------------
|
||||
*/
|
||||
if (! PointerIsValid(oidP))
|
||||
{
|
||||
SpinRelease(OidGenLockId);
|
||||
elog(WARN, "VariableRelationPutNextOid: invalid oid pointer");
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* 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(WARN, "VariableRelationPutNextXid: ReadBuffer failed");
|
||||
}
|
||||
|
||||
var = (VariableRelationContents) BufferGetBlock(buf);
|
||||
|
||||
var->nextOid = (*oidP);
|
||||
|
||||
WriteBuffer(buf);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* transaction id generation support
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* GetNewTransactionId
|
||||
*
|
||||
* In the version 2 transaction system, transaction id's are
|
||||
* restricted in several ways.
|
||||
*
|
||||
* First, all transaction id's are even numbers (4, 88, 121342, etc).
|
||||
* This means the binary representation of the number will never
|
||||
* have the least significent bit set. This bit is reserved to
|
||||
* indicate that the transaction id does not in fact hold an XID,
|
||||
* but rather a commit time. This makes it possible for the
|
||||
* vaccuum daemon to disgard information from the log and time
|
||||
* relations for committed tuples. This is important when archiving
|
||||
* tuples to an optical disk because tuples with commit times
|
||||
* stored in their xid fields will not need to consult the log
|
||||
* and time relations.
|
||||
*
|
||||
* Second, since we may someday preform compression of the data
|
||||
* in the log and time relations, we cause the numbering of the
|
||||
* 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.
|
||||
*
|
||||
* Lastly, rather then access the variable relation each time
|
||||
* a backend requests a new transction id, we "prefetch" 32
|
||||
* transaction id's by incrementing the nextXid stored in the
|
||||
* var relation by 64 (remember only even xid's are legal) 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 if when the backend
|
||||
* terminates, we lose the xid's we cached.
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
#define VAR_XID_PREFETCH 32
|
||||
|
||||
static int prefetched_xid_count = 0;
|
||||
static TransactionId next_prefetched_xid;
|
||||
|
||||
void
|
||||
GetNewTransactionId(TransactionId *xid)
|
||||
{
|
||||
TransactionId nextid;
|
||||
|
||||
/* ----------------
|
||||
* during bootstrap initialization, we return the special
|
||||
* bootstrap transaction id.
|
||||
* ----------------
|
||||
*/
|
||||
if (AMI_OVERRIDE) {
|
||||
TransactionIdStore(AmiTransactionId, xid);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* if we run out of prefetched xids, then we get some
|
||||
* more before handing them out to the caller.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (prefetched_xid_count == 0) {
|
||||
/* ----------------
|
||||
* obtain exclusive access to the variable relation page
|
||||
*
|
||||
* get the "next" xid from the variable relation
|
||||
* and save it in the prefetched id.
|
||||
* ----------------
|
||||
*/
|
||||
SpinAcquire(OidGenLockId);
|
||||
VariableRelationGetNextXid(&nextid);
|
||||
TransactionIdStore(nextid, &next_prefetched_xid);
|
||||
|
||||
/* ----------------
|
||||
* now increment the variable relation's next xid
|
||||
* and reset the prefetched_xid_count. We multiply
|
||||
* the id by two because our xid's are always even.
|
||||
* ----------------
|
||||
*/
|
||||
prefetched_xid_count = VAR_XID_PREFETCH;
|
||||
TransactionIdAdd(&nextid, prefetched_xid_count);
|
||||
VariableRelationPutNextXid(nextid);
|
||||
SpinRelease(OidGenLockId);
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* return the next prefetched xid in the pointer passed by
|
||||
* the user and decrement the prefetch count. We add two
|
||||
* to id we return the next time this is called because our
|
||||
* transaction ids are always even.
|
||||
*
|
||||
* XXX Transaction Ids used to be even as the low order bit was
|
||||
* used to determine commit status. This is no long true so
|
||||
* we now use even and odd transaction ids. -mer 5/26/92
|
||||
* ----------------
|
||||
*/
|
||||
TransactionIdStore(next_prefetched_xid, xid);
|
||||
TransactionIdAdd(&next_prefetched_xid, 1);
|
||||
prefetched_xid_count--;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* UpdateLastCommittedXid
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
void
|
||||
UpdateLastCommittedXid(TransactionId xid)
|
||||
{
|
||||
TransactionId lastid;
|
||||
|
||||
|
||||
/* we assume that spinlock OidGenLockId has been acquired
|
||||
* prior to entering this function
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* get the "last committed" transaction id from
|
||||
* the variable relation page.
|
||||
* ----------------
|
||||
*/
|
||||
VariableRelationGetLastXid(&lastid);
|
||||
|
||||
/* ----------------
|
||||
* if the transaction id is greater than the last committed
|
||||
* transaction then we update the last committed transaction
|
||||
* in the variable relation.
|
||||
* ----------------
|
||||
*/
|
||||
if (TransactionIdIsLessThan(lastid, xid))
|
||||
VariableRelationPutLastXid(xid);
|
||||
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* object id generation support
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* ----------------
|
||||
* GetNewObjectIdBlock
|
||||
*
|
||||
* This support function is used to allocate a block of object ids
|
||||
* of the given size. applications wishing to do their own object
|
||||
* id assignments should use this
|
||||
* ----------------
|
||||
*/
|
||||
void
|
||||
GetNewObjectIdBlock(Oid *oid_return, /* place to return the new object id */
|
||||
int oid_block_size) /* number of oids desired */
|
||||
{
|
||||
Oid nextoid;
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY obtain exclusive access to the variable relation page
|
||||
* That someday is today -mer 6 Aug 1992
|
||||
* ----------------
|
||||
*/
|
||||
SpinAcquire(OidGenLockId);
|
||||
|
||||
/* ----------------
|
||||
* get the "next" oid from the variable relation
|
||||
* and give it to the caller.
|
||||
* ----------------
|
||||
*/
|
||||
VariableRelationGetNextOid(&nextoid);
|
||||
if (PointerIsValid(oid_return))
|
||||
(*oid_return) = nextoid;
|
||||
|
||||
/* ----------------
|
||||
* now increment the variable relation's next oid
|
||||
* field by the size of the oid block requested.
|
||||
* ----------------
|
||||
*/
|
||||
nextoid += oid_block_size;
|
||||
VariableRelationPutNextOid(&nextoid);
|
||||
|
||||
/* ----------------
|
||||
* SOMEDAY relinquish our lock on the variable relation page
|
||||
* That someday is today -mer 6 Apr 1992
|
||||
* ----------------
|
||||
*/
|
||||
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 if when the backend
|
||||
* terminates, we lose the oids we cached.
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
#define VAR_OID_PREFETCH 32
|
||||
|
||||
static int prefetched_oid_count = 0;
|
||||
static Oid next_prefetched_oid;
|
||||
|
||||
void
|
||||
GetNewObjectId(Oid *oid_return) /* place to return the new object id */
|
||||
{
|
||||
/* ----------------
|
||||
* if we run out of prefetched oids, then we get some
|
||||
* more before handing them out to the caller.
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
if (prefetched_oid_count == 0) {
|
||||
int oid_block_size = VAR_OID_PREFETCH;
|
||||
|
||||
/* ----------------
|
||||
* during bootstrap time, we want to allocate oids
|
||||
* 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))
|
||||
VariableRelation = heap_openr(VariableRelationName);
|
||||
|
||||
/* ----------------
|
||||
* 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;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* 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;
|
||||
|
||||
next_prefetched_oid++;
|
||||
prefetched_oid_count--;
|
||||
}
|
Reference in New Issue
Block a user