aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/varsup.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/access/transam/varsup.c
downloadpostgresql-PG95-1_01.tar.gz
postgresql-PG95-1_01.zip
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/access/transam/varsup.c')
-rw-r--r--src/backend/access/transam/varsup.c606
1 files changed, 606 insertions, 0 deletions
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
new file mode 100644
index 00000000000..a53cc7d35b1
--- /dev/null
+++ b/src/backend/access/transam/varsup.c
@@ -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--;
+}