home *** CD-ROM | disk | FTP | other *** search
- /*
- * rac.c --
- * POSTGRES rule lock access code.
- */
-
- #include "tmp/c.h"
-
- RcsId("$Header: /private/postgres/src/access/heap/RCS/rac.c,v 1.15 1992/03/05 00:36:28 hong Exp $");
-
- #include "access/htup.h"
-
- #include "rules/rac.h"
- #include "rules/prs2locks.h"
- #include "rules/prs2.h"
-
- #include "storage/block.h"
- #include "storage/buf.h"
- #include "storage/bufmgr.h"
- #include "storage/bufpage.h"
- #include "storage/item.h"
- #include "storage/itemid.h"
- #include "storage/itemptr.h"
- #include "storage/page.h"
-
- #include "utils/inval.h"
- #include "utils/palloc.h"
- #include "utils/rel.h"
- #include "utils/log.h"
-
- /*
- * XXX direct structure accesses should be removed
- */
-
- /*-------------------------------------------------------------------
- * HeapTupleFreeRuleLock
- *
- * Frees a lock, but only if it is a main memory lock.
- *
- */
- void
- HeapTupleFreeRuleLock(tuple)
- HeapTuple tuple;
- {
- if (tuple->t_locktype == MEM_RULE_LOCK) {
- prs2FreeLocks(tuple->t_lock.l_lock);
- }
- }
-
- /*-------------------------------------------------------------------
- *
- * HeapTupleGetRuleLock
- *
- * A rule lock can be either an ItemPointer to the actual data in a
- * disk page or a RuleLock, i.e. a pointer to a main memory structure.
- *
- * This routine always return the main memory representation (if necessary
- * it makes the conversion)
- *
- * NOTE #1: When we save the tuple on disk, if the rule lock is empty
- * (i.e. a "(numOfLocks: 0)"::lock, which must not be confused with
- * an 'InvalidRuleLock') then we store an InvalidItemPointer.
- * So, if the disk representation of the tuple's lock is such an
- * InvalidItemPointer we have to create & return an empty lock.
- *
- * NOTE #2: We ALWAYS return a COPY of the locks. That means we
- * return a freshly palloced new lock, that can and probably MUST
- * be pfreed by the caller (to avoid memory leaks).
- */
- RuleLock
- HeapTupleGetRuleLock(tuple, buffer)
- HeapTuple tuple;
- Buffer buffer;
- {
- register RuleLock l;
-
- BlockNumber blockNumber;
- Page page;
- ItemId itemId;
- Item item;
- Item returnItem;
-
-
- Assert(HeapTupleIsValid(tuple));
-
- /*
- * sanity check
- */
- if (tuple->t_locktype != MEM_RULE_LOCK &&
- tuple->t_locktype != DISK_RULE_LOCK) {
- elog(WARN,"HeapTupleGetRuleLock: locktype = '%c',(%d)\n",
- tuple->t_locktype, tuple->t_locktype);
- }
-
- /*
- * if this is a main memory lock, then return it.
- */
- if (tuple->t_locktype == MEM_RULE_LOCK) {
- l = tuple->t_lock.l_lock;
- if (l==InvalidRuleLock) {
- elog(WARN, "HeapTupleGetRuleLock: Invalid Rule Lock!");
- } else {
- return(prs2CopyLocks(l));
- }
- }
-
- /*
- * no, it is a disk lock. Check if it the item pointer is
- * invalid and if yes, return an empty lock.
- */
- if (!ItemPointerIsValid(&tuple->t_lock.l_ltid)) {
- return (prs2MakeLocks());
- }
-
- /*
- * If this is a disk lock, then we *must* pass a valid
- * buffer...
- * Otherwise ... booooooom!
- */
- if (!BufferIsValid(buffer)) {
- elog(WARN,"HeapTupleGetRuleLock: Invalid buffer");
- }
-
- /* ----------------
- * Yow! raw page access! shouldn't this use the am code?
- * ----------------
- */
- blockNumber = ItemPointerGetBlockNumber(&tuple->t_lock.l_ltid);
-
- buffer = ReadBuffer(BufferGetRelation(buffer), blockNumber);
-
- page = BufferSimpleGetPage(buffer);
- itemId = PageGetItemId(page,
- ItemPointerSimpleGetOffsetIndex(&tuple->t_lock.l_ltid));
- item = PageGetItem(page, itemId);
-
- returnItem = (Item) palloc(itemId->lp_len); /* XXX */
- bcopy(item, returnItem, (int)itemId->lp_len); /* XXX Clib-copy */
-
- ReleaseBuffer(buffer);
-
- /*
- * `l' is a pointer to data in a buffer page.
- * return a copy of it.
- */
- l = LintCast(RuleLock, returnItem);
-
- return(prs2CopyLocks(l));
- }
-
- /*----------------------------------------------------------------------------
- * HeapTupleHasEmptyRuleLock
- *
- * return true if the given tuple has an empty rule lock.
- * We can always use 'HeapTupleGetRuleLock', test the locks, and then
- * pfreed it, but this routine avoids the calls to 'palloc'
- * and 'pfree' thus making postgres 153.34 % faster....
- *----------------------------------------------------------------------------
- */
- bool
- HeapTupleHasEmptyRuleLock(tuple, buffer)
- HeapTuple tuple;
- Buffer buffer;
- {
- register RuleLock l;
-
- Assert(HeapTupleIsValid(tuple));
-
- /*
- * sanity check
- */
- if (tuple->t_locktype != MEM_RULE_LOCK &&
- tuple->t_locktype != DISK_RULE_LOCK) {
- elog(WARN,"HeapTupleHasEmptyRuleLock: locktype = '%c',(%d)\n",
- tuple->t_locktype, tuple->t_locktype);
- }
-
- /*
- * is this is a main memory lock ?
- */
- if (tuple->t_locktype == MEM_RULE_LOCK) {
- l = tuple->t_lock.l_lock;
- if (l==InvalidRuleLock) {
- elog(WARN, "HeapTupleHasEmptyRuleLock: Invalid Rule Lock!");
- } else {
- if (prs2RuleLockIsEmpty(l))
- return(true);
- else
- return(false);
- }
- }
-
- /*
- * no, it is a disk lock. Check if it the item pointer is
- * invalid and if yes, return true (empty lock), otherwise
- * return false.
- */
- if (!ItemPointerIsValid(&tuple->t_lock.l_ltid))
- return (true);
- else
- return(false);
- }
-
- /*------------------------------------------------------------
- *
- * HeapTupleSetRuleLock
- *
- * Set the rule lock of a tuple.
- *
- * NOTE: the old lock of the tuple is pfreed (if it is a main
- * memory pointer of course... If it is an item in a disk page
- * it is left intact)
- *
- * NOTE: No copies of the tuple or the lock are made any more (this
- * routine used to -sometimes- make a copy of the tuple)
- */
- void
- HeapTupleSetRuleLock(tuple, buffer, lock)
- HeapTuple tuple;
- Buffer buffer;
- RuleLock lock;
- {
- RuleLock oldLock;
- Assert(HeapTupleIsValid(tuple));
-
- /*
- * sanity check...
- */
- if (tuple->t_locktype != MEM_RULE_LOCK &&
- tuple->t_locktype != DISK_RULE_LOCK) {
- elog(WARN,"HeapTupleGetRuleLock: locktype = '%c',(%d)\n",
- tuple->t_locktype, tuple->t_locktype);
- }
-
- HeapTupleFreeRuleLock(tuple);
-
- tuple->t_locktype = MEM_RULE_LOCK;
- tuple->t_lock.l_lock = lock;
-
- }
-
- /*------------------------------------------------------------
- *
- * HeapTupleStoreRuleLock
- *
- * Store a rule lock in a page.
- * The 'tuple' has a lock which can be either a "disk" or "main memory"
- * rule lock. In the first case we don't need to do anything because
- * the lock is already there! In the second case, add the lock data
- * somewhere in the disk page & update the tuple->t_lock stuff...
- *
- * NOTE: When we save the tuple on disk, if the rule lock is empty
- * (i.e. a "(numOfLocks: 0)"::lock, which must not be confused with
- * an 'InvalidRuleLock') then we store an InvalidItemPointer.
- */
- void
- HeapTupleStoreRuleLock(tuple, buffer)
- HeapTuple tuple;
- Buffer buffer;
- {
- Relation relation;
- Page page;
- BlockNumber blockNumber;
- OffsetNumber offsetNumber;
- RuleLock lock;
- Size lockSize;
-
- Assert(HeapTupleIsValid(tuple));
- Assert(BufferIsValid(buffer));
-
- /*
- * If it is a disk lock, then there is nothing to do...
- */
- if (tuple->t_locktype == DISK_RULE_LOCK) {
- return;
- }
-
- /*
- * sanity check
- */
- if (tuple->t_locktype != MEM_RULE_LOCK) {
- elog(WARN,"HeapTupleGetRuleLock: locktype = '%c',(%d)\n",
- tuple->t_locktype, tuple->t_locktype);
- }
-
- lock = tuple->t_lock.l_lock;
-
- /*
- * if it is an empty lock, treat the trivial case..
- */
- if (prs2RuleLockIsEmpty(lock)) {
- /*
- * change it to an empty disk lock
- */
- tuple->t_locktype = DISK_RULE_LOCK;
- ItemPointerSetInvalid(&tuple->t_lock.l_ltid);
- return;
- }
-
- relation = BufferGetRelation(buffer);
-
- /* Assert(0); */
- /* XXX START HERE */
- /*
- * need to check if sufficient space. If so, then place it.
- * Otherwise, allocate a new page. Etc. Look at util/access.c
- * for ideas and to have amputtup and amputnew call this funciton.
- *
- * XXX this should be rewritten to use the am code rather than
- * using the buffer and page code directly.
- */
-
- page = BufferSimpleGetPage(buffer);
-
- lockSize = prs2LockSize(prs2GetNumberOfLocks(lock));
-
- if (PageGetFreeSpace(page) >= lockSize) {
-
- blockNumber = BufferGetBlockNumber(buffer);
- offsetNumber = PageAddItem(page, (Item) lock, lockSize,
- InvalidOffsetNumber, LP_USED | LP_LOCK);
- } else {
- Assert(lockSize < BLCKSZ); /* XXX cannot handle this yet */
-
- buffer = ReadBuffer(relation, P_NEW);
-
- #ifndef NO_BUFFERISVALID
- if (!BufferIsValid(buffer)) {
- elog(WARN,
- "HeapTupleStoreRuleLock: cannot get new buffer");
- }
- #endif NO_BUFFERISVALID
-
- BufferSimpleInitPage(buffer);
- blockNumber = BufferGetBlockNumber(buffer);
- offsetNumber = PageAddItem(BufferSimpleGetPage(buffer),
- (Item) lock, lockSize, InvalidOffsetNumber,
- LP_USED | LP_LOCK);
- WriteBuffer(buffer);
- }
- tuple->t_locktype = DISK_RULE_LOCK;
- ItemPointerSimpleSet(&tuple->t_lock.l_ltid, blockNumber, offsetNumber);
-
- /*
- * And now the tricky & funny part... (not submitted to
- * Rec.puzzles yet...)
- *
- * Shall we free the old memory locks or not ????
- * "I say yes! It is safe to pfree them..." (Spyros said, just before
- * the lights went out...)
- *
- * ---
- * The lights went out, so DO NOT FREE the locks! I think the
- * problem is that when 'RelationPutHeapTuple' calls this routine
- * it passes to it an item pointer, i.e. a "disk" tuple, and
- * not the main memory tuple. So finally when the executor does
- * its cleanup, it ends up freeing this lock twice!
- */
- /* prs2FreeLocks(lock); */
-
- /*
- * And our last question for $200!
- * the following call to "RelationInvalidateHeapTuple()"
- * invalidates the cache... Do we really need it ???
- *
- * The correct answer is NO! "HeapTupleStoreRuleLock()"
- * in only called by "RelationPutHeapTuple()"
- * and "RelationPutLongHeapTuple()", which are called
- * by "amreplace()", "aminsert()" and company, which
- * invalidate the cache anyway...
- */
-
- /* RelationInvalidateHeapTuple(relation, tuple); */
-
- }
-