From 3f7fbf85dc5b42dfd33c803efe6c90533773576a Mon Sep 17 00:00:00 2001 From: "Vadim B. Mikheev" <vadim4o@yahoo.com> Date: Tue, 15 Dec 1998 12:47:01 +0000 Subject: [PATCH] Initial MVCC code. New code for locking buffer' context. --- src/backend/access/gist/gist.c | 17 +- src/backend/access/gist/gistscan.c | 5 + src/backend/access/hash/hashpage.c | 20 +- src/backend/access/heap/heapam.c | 496 +++++++++--------- src/backend/access/heap/hio.c | 71 +-- src/backend/access/heap/stats.c | 8 +- src/backend/access/index/indexam.c | 6 +- src/backend/access/nbtree/nbtinsert.c | 27 +- src/backend/access/nbtree/nbtpage.c | 20 +- src/backend/access/rtree/rtree.c | 19 +- src/backend/access/rtree/rtscan.c | 7 +- src/backend/access/transam/transam.c | 21 +- src/backend/access/transam/transsup.c | 33 +- src/backend/access/transam/xact.c | 7 +- src/backend/catalog/aclchk.c | 4 +- src/backend/catalog/heap.c | 32 +- src/backend/catalog/index.c | 22 +- src/backend/catalog/pg_operator.c | 10 +- src/backend/catalog/pg_type.c | 10 +- src/backend/commands/async.c | 30 +- src/backend/commands/command.c | 4 +- src/backend/commands/copy.c | 23 +- src/backend/commands/dbcommands.c | 4 +- src/backend/commands/defind.c | 4 +- src/backend/commands/proclang.c | 2 +- src/backend/commands/remove.c | 14 +- src/backend/commands/rename.c | 6 +- src/backend/commands/sequence.c | 42 +- src/backend/commands/trigger.c | 155 +++--- src/backend/commands/user.c | 20 +- src/backend/commands/vacuum.c | 12 +- src/backend/executor/execMain.c | 97 ++-- src/backend/executor/execUtils.c | 31 +- src/backend/executor/nodeHash.c | 10 +- src/backend/parser/gram.c | 2 +- src/backend/parser/parse_func.c | 4 +- src/backend/rewrite/rewriteRemove.c | 6 +- src/backend/rewrite/rewriteSupport.c | 4 +- src/backend/storage/buffer/buf_init.c | 25 +- src/backend/storage/buffer/bufmgr.c | 149 +++++- src/backend/storage/buffer/s_lock.c | 21 +- src/backend/storage/ipc/ipci.c | 7 +- src/backend/storage/ipc/shmem.c | 23 +- src/backend/storage/large_object/inv_api.c | 18 +- src/backend/storage/lmgr/Makefile | 4 +- src/backend/storage/lmgr/lmgr.c | 580 ++++++--------------- src/backend/storage/lmgr/lock.c | 49 +- src/backend/utils/adt/sets.c | 8 +- src/backend/utils/cache/relcache.c | 12 +- src/backend/utils/time/tqual.c | 207 +++++++- src/include/access/heapam.h | 16 +- src/include/access/hio.h | 6 +- src/include/access/htup.h | 3 +- src/include/access/xact.h | 4 +- src/include/catalog/pg_am.h | 3 +- src/include/catalog/pg_class.h | 7 +- src/include/commands/trigger.h | 9 +- src/include/storage/buf_internals.h | 63 +-- src/include/storage/bufmgr.h | 13 +- src/include/storage/ipc.h | 4 +- src/include/storage/lmgr.h | 64 +-- src/include/storage/lock.h | 12 +- src/include/storage/proc.h | 4 +- src/include/storage/s_lock.h | 4 +- src/include/utils/tqual.h | 35 +- 65 files changed, 1382 insertions(+), 1273 deletions(-) diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index a7617842042..ce9ef24c88e 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -104,8 +104,7 @@ gistbuild(Relation heap, Buffer buffer = InvalidBuffer; bool *compvec; - /* GiSTs only know how to do stupid locking now */ - RelationSetLockForWrite(index); + /* no locking is needed */ setheapoverride(true); /* so we can see the new pg_index tuple */ initGISTstate(&giststate, index); @@ -269,7 +268,6 @@ gistbuild(Relation heap, /* okay, all heap tuples are indexed */ heap_endscan(scan); - RelationUnsetLockForWrite(index); if (pred != NULL || oldPred != NULL) { @@ -343,7 +341,12 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation itup = index_formtuple(RelationGetDescr(r), datum, nulls); itup->t_tid = *ht_ctid; + /* + * Notes in ExecUtils:ExecOpenIndices() + * RelationSetLockForWrite(r); + */ + res = gistdoinsert(r, itup, &giststate); for (i = 0; i < r->rd_att->natts; i++) if (compvec[i] == TRUE) @@ -351,7 +354,6 @@ gistinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation pfree(itup); pfree(compvec); - /* XXX two-phase locking -- don't unlock the relation until EOT */ return res; } @@ -1103,8 +1105,12 @@ gistdelete(Relation r, ItemPointer tid) Buffer buf; Page page; - /* must write-lock on delete */ + /* + * Notes in ExecUtils:ExecOpenIndices() + * Also note that only vacuum deletes index tuples now... + * RelationSetLockForWrite(r); + */ blkno = ItemPointerGetBlockNumber(tid); offnum = ItemPointerGetOffsetNumber(tid); @@ -1120,7 +1126,6 @@ gistdelete(Relation r, ItemPointer tid) WriteBuffer(buf); - /* XXX -- two-phase locking, don't release the write lock */ } void diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index f74316cb331..3528fd30ce2 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -65,7 +65,12 @@ gistbeginscan(Relation r, { IndexScanDesc s; + /* + * Let index_beginscan does its work... + * RelationSetLockForRead(r); + */ + s = RelationGetIndexScan(r, fromEnd, nkeys, key); gistregscan(s); diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c index dc3ad3727aa..208cda1bf7e 100644 --- a/src/backend/access/hash/hashpage.c +++ b/src/backend/access/hash/hashpage.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.17 1998/09/01 03:20:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/hash/hashpage.c,v 1.18 1998/12/15 12:45:10 vadim Exp $ * * NOTES * Postgres hash pages look like ordinary relation pages. The opaque @@ -81,7 +81,7 @@ _hash_metapinit(Relation rel) /* can't be sharing this with anyone, now... */ if (USELOCKING) - RelationSetLockForWrite(rel); + LockRelation(rel, AccessExclusiveLock); if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0) { @@ -169,7 +169,7 @@ _hash_metapinit(Relation rel) _hash_relbuf(rel, metabuf, HASH_WRITE); if (USELOCKING) - RelationUnsetLockForWrite(rel); + UnlockRelation(rel, AccessExclusiveLock); } /* @@ -316,19 +316,16 @@ _hash_setpagelock(Relation rel, BlockNumber blkno, int access) { - ItemPointerData iptr; if (USELOCKING) { - ItemPointerSet(&iptr, blkno, 1); - switch (access) { case HASH_WRITE: - RelationSetSingleWLockPage(rel, &iptr); + LockPage(rel, blkno, ExclusiveLock); break; case HASH_READ: - RelationSetSingleRLockPage(rel, &iptr); + LockPage(rel, blkno, ShareLock); break; default: elog(ERROR, "_hash_setpagelock: invalid access (%d) on blk %x: %s", @@ -343,19 +340,16 @@ _hash_unsetpagelock(Relation rel, BlockNumber blkno, int access) { - ItemPointerData iptr; if (USELOCKING) { - ItemPointerSet(&iptr, blkno, 1); - switch (access) { case HASH_WRITE: - RelationUnsetSingleWLockPage(rel, &iptr); + UnlockPage(rel, blkno, ExclusiveLock); break; case HASH_READ: - RelationUnsetSingleRLockPage(rel, &iptr); + UnlockPage(rel, blkno, ShareLock); break; default: elog(ERROR, "_hash_unsetpagelock: invalid access (%d) on blk %x: %s", diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 76fcfaf2c82..8ffd9d41922 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.38 1998/11/27 19:51:36 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.39 1998/12/15 12:45:13 vadim Exp $ * * * INTERFACE ROUTINES @@ -89,15 +89,12 @@ #include <utils/inval.h> #include <utils/memutils.h> - #ifndef HAVE_MEMMOVE #include <regex/utils.h> #else #include <string.h> #endif -static void doinsert(Relation relation, HeapTuple tup); - /* ---------------------------------------------------------------- * heap support routines * ---------------------------------------------------------------- @@ -214,7 +211,7 @@ static void heapgettup(Relation relation, HeapTuple tuple, int dir, - Buffer *buf, + Buffer *buffer, Snapshot snapshot, int nkeys, ScanKey key) @@ -255,7 +252,7 @@ heapgettup(Relation relation, elog(DEBUG, "heapgettup(%s, tid=0x%x, dir=%d, ...)", RelationGetRelationName(relation), tid, dir); } - elog(DEBUG, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buf, nkeys, key); + elog(DEBUG, "heapgettup(..., b=0x%x, nkeys=%d, key=0x%x", buffer, nkeys, key); elog(DEBUG, "heapgettup: relation(%c)=`%s', %p", relation->rd_rel->relkind, &relation->rd_rel->relname, @@ -288,25 +285,26 @@ heapgettup(Relation relation, /* assume it is a valid TID XXX */ if (ItemPointerIsValid(tid) == false) { - *buf = InvalidBuffer; + *buffer = InvalidBuffer; tuple->t_data = NULL; return; } - *buf = RelationGetBufferWithBuffer(relation, + *buffer = RelationGetBufferWithBuffer(relation, ItemPointerGetBlockNumber(tid), - *buf); + *buffer); -#ifndef NO_BUFFERISVALID - if (!BufferIsValid(*buf)) + if (!BufferIsValid(*buffer)) elog(ERROR, "heapgettup: failed ReadBuffer"); -#endif - dp = (Page) BufferGetPage(*buf); + LockBuffer(*buffer, BUFFER_LOCK_SHARE); + + dp = (Page) BufferGetPage(*buffer); lineoff = ItemPointerGetOffsetNumber(tid); lpp = PageGetItemId(dp, lineoff); tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp); tuple->t_len = ItemIdGetLength(lpp); + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); return; } @@ -328,18 +326,18 @@ heapgettup(Relation relation, } if (page < 0) { - *buf = InvalidBuffer; + *buffer = InvalidBuffer; tuple->t_data = NULL; return; } - *buf = RelationGetBufferWithBuffer(relation, page, *buf); -#ifndef NO_BUFFERISVALID - if (!BufferIsValid(*buf)) + *buffer = RelationGetBufferWithBuffer(relation, page, *buffer); + if (!BufferIsValid(*buffer)) elog(ERROR, "heapgettup: failed ReadBuffer"); -#endif - dp = (Page) BufferGetPage(*buf); + LockBuffer(*buffer, BUFFER_LOCK_SHARE); + + dp = (Page) BufferGetPage(*buffer); lines = PageGetMaxOffsetNumber(dp); if (tid == NULL) { @@ -373,19 +371,19 @@ heapgettup(Relation relation, if (page >= pages) { - *buf = InvalidBuffer; + *buffer = InvalidBuffer; tuple->t_data = NULL; return; } /* page and lineoff now reference the physically next tid */ - *buf = RelationGetBufferWithBuffer(relation, page, *buf); -#ifndef NO_BUFFERISVALID - if (!BufferIsValid(*buf)) + *buffer = RelationGetBufferWithBuffer(relation, page, *buffer); + if (!BufferIsValid(*buffer)) elog(ERROR, "heapgettup: failed ReadBuffer"); -#endif - dp = (Page) BufferGetPage(*buf); + LockBuffer(*buffer, BUFFER_LOCK_SHARE); + + dp = (Page) BufferGetPage(*buffer); lines = PageGetMaxOffsetNumber(dp); } @@ -420,10 +418,13 @@ heapgettup(Relation relation, * if current tuple qualifies, return it. * ---------------- */ - HeapTupleSatisfies(tuple, relation, *buf, (PageHeader) dp, + HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp, snapshot, nkeys, key); if (tuple->t_data != NULL) + { + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); return; + } } /* ---------------- @@ -448,6 +449,7 @@ heapgettup(Relation relation, * this page and it's time to move to the next.. * ---------------- */ + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); page = nextpage(page, dir); /* ---------------- @@ -456,20 +458,19 @@ heapgettup(Relation relation, */ if (page < 0 || page >= pages) { - if (BufferIsValid(*buf)) - ReleaseBuffer(*buf); - *buf = InvalidBuffer; + if (BufferIsValid(*buffer)) + ReleaseBuffer(*buffer); + *buffer = InvalidBuffer; tuple->t_data = NULL; return; } - *buf = ReleaseAndReadBuffer(*buf, relation, page); + *buffer = ReleaseAndReadBuffer(*buffer, relation, page); -#ifndef NO_BUFFERISVALID - if (!BufferIsValid(*buf)) + if (!BufferIsValid(*buffer)) elog(ERROR, "heapgettup: failed ReadBuffer"); -#endif - dp = (Page) BufferGetPage(*buf); + LockBuffer(*buffer, BUFFER_LOCK_SHARE); + dp = (Page) BufferGetPage(*buffer); lines = PageGetMaxOffsetNumber((Page) dp); linesleft = lines - 1; if (dir < 0) @@ -485,13 +486,6 @@ heapgettup(Relation relation, } } -static void -doinsert(Relation relation, HeapTuple tup) -{ - RelationPutHeapTupleAtEnd(relation, tup); - return; -} - /* ---------------------------------------------------------------- * heap access method interface @@ -599,11 +593,7 @@ heap_beginscan(Relation relation, if (RelationIsValid(relation) == false) elog(ERROR, "heap_beginscan: !RelationIsValid(relation)"); - /* ---------------- - * set relation level read lock - * ---------------- - */ - RelationSetLockForRead(relation); + LockRelation(relation, AccessShareLock); /* XXX someday assert SelfTimeQual if relkind == RELKIND_UNCATALOGED */ if (relation->rd_rel->relkind == RELKIND_UNCATALOGED) @@ -707,13 +697,7 @@ heap_endscan(HeapScanDesc scan) */ RelationDecrementReferenceCount(scan->rs_rd); - /* ---------------- - * Non 2-phase read locks on catalog relations - * ---------------- - */ - if (IsSystemRelationName(RelationGetRelationName(scan->rs_rd)->data)) - - RelationUnsetLockForRead(scan->rs_rd); + UnlockRelation(scan->rs_rd, AccessShareLock); pfree(scan); /* XXX */ } @@ -997,14 +981,6 @@ heap_fetch(Relation relation, IncrHeapAccessStat(local_fetch); IncrHeapAccessStat(global_fetch); - /* - * Note: This is collosally expensive - does two system calls per - * indexscan tuple fetch. Not good, and since we should be doing page - * level locking by the scanner anyway, it is commented out. - */ - - /* RelationSetLockForTupleRead(relation, tid); */ - /* ---------------- * get the buffer from the relation descriptor * Note that this does a buffer pin. @@ -1013,13 +989,11 @@ heap_fetch(Relation relation, buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); -#ifndef NO_BUFFERISVALID if (!BufferIsValid(buffer)) - { elog(ERROR, "heap_fetch: %s relation: ReadBuffer(%lx) failed", &relation->rd_rel->relname, (long) tid); - } -#endif + + LockBuffer(buffer, BUFFER_LOCK_SHARE); /* ---------------- * get the item line pointer corresponding to the requested tid @@ -1047,6 +1021,8 @@ heap_fetch(Relation relation, HeapTupleSatisfies(tuple, relation, buffer, dp, snapshot, 0, (ScanKey) NULL); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + if (tuple->t_data == NULL) { ReleaseBuffer(buffer); @@ -1090,14 +1066,6 @@ heap_insert(Relation relation, HeapTuple tup) IncrHeapAccessStat(local_insert); IncrHeapAccessStat(global_insert); - /* ---------------- - * set relation level write lock. If this is a "local" relation (not - * visible to others), we don't need to set a write lock. - * ---------------- - */ - if (!relation->rd_islocal) - RelationSetLockForWrite(relation); - /* ---------------- * If the object id of this tuple has already been assigned, trust * the caller. There are a couple of ways this can happen. At initial @@ -1122,228 +1090,178 @@ heap_insert(Relation relation, HeapTuple tup) tup->t_data->t_infomask &= ~(HEAP_XACT_MASK); tup->t_data->t_infomask |= HEAP_XMAX_INVALID; - doinsert(relation, tup); + RelationPutHeapTupleAtEnd(relation, tup); if (IsSystemRelationName(RelationGetRelationName(relation)->data)) { - RelationUnsetLockForWrite(relation); - - /* ---------------- - * invalidate caches (only works for system relations) - * ---------------- - */ RelationInvalidateHeapTuple(relation, tup); } return tup->t_data->t_oid; } -/* ---------------- - * heap_delete - delete a tuple - * - * Must decide how to handle errors. - * ---------------- +/* + * heap_delete - delete a tuple */ int -heap_delete(Relation relation, ItemPointer tid) +heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid) { ItemId lp; HeapTupleData tp; PageHeader dp; - Buffer buf; + Buffer buffer; + int result; - /* ---------------- - * increment access statistics - * ---------------- - */ + /* increment access statistics */ IncrHeapAccessStat(local_delete); IncrHeapAccessStat(global_delete); - /* ---------------- - * sanity check - * ---------------- - */ Assert(ItemPointerIsValid(tid)); - /* ---------------- - * set relation level write lock - * ---------------- - */ - RelationSetLockForWrite(relation); - - buf = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); + buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); -#ifndef NO_BUFFERISVALID - if (!BufferIsValid(buf)) - { /* XXX L_SH better ??? */ + if (!BufferIsValid(buffer)) elog(ERROR, "heap_delete: failed ReadBuffer"); - } -#endif /* NO_BUFFERISVALID */ - dp = (PageHeader) BufferGetPage(buf); - lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - /* - * Just like test against non-functional updates we try to catch - * non-functional delete attempts. - vadim 05/05/97 - */ + dp = (PageHeader) BufferGetPage(buffer); + lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); tp.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); tp.t_len = ItemIdGetLength(lp); tp.t_self = *tid; - if (TupleUpdatedByCurXactAndCmd(&tp)) +l1: + result = HeapTupleSatisfiesUpdate(&tp); + + if (result == HeapTupleInvisible) { - - /* - * Vadim says this is no longer needed 1998/6/15 elog(NOTICE, - * "Non-functional delete, tuple already deleted"); - */ - if (IsSystemRelationName(RelationGetRelationName(relation)->data)) - RelationUnsetLockForWrite(relation); - ReleaseBuffer(buf); - return 1; + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + ReleaseBuffer(buffer); + elog(ERROR, "heap_delete: (am)invalid tid"); } - /* ---------------- - * check that we're deleteing a valid item - * ---------------- - */ - HeapTupleSatisfies((&tp), relation, buf, dp, - false, 0, (ScanKey) NULL); - if (!(tp.t_data)) + else if (result == HeapTupleBeingUpdated) { - - /* XXX call something else */ - ReleaseBuffer(buf); - - elog(ERROR, "heap_delete: (am)invalid tid"); + TransactionId xwait = tp.t_data->t_xmax; + + /* sleep untill concurrent transaction ends */ + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + XactLockTableWait(xwait); + + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + if (TransactionIdDidAbort(xwait)) + goto l1; + /* concurrent xact committed */ + Assert(tp.t_data->t_xmax == xwait); + if (!(tp.t_data->t_infomask & HEAP_XMAX_COMMITTED)) + { + tp.t_data->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } + /* if tuple was marked for update but not updated... */ + if (tp.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE) + result = HeapTupleMayBeUpdated; + else + result = HeapTupleUpdated; + } + if (result != HeapTupleMayBeUpdated) + { + Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated); + if (ctid != NULL) + *ctid = tp.t_data->t_ctid; + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + ReleaseBuffer(buffer); + return result; } - /* ---------------- - * get the tuple and lock tell the buffer manager we want - * exclusive access to the page - * ---------------- - */ - - /* ---------------- - * store transaction information of xact deleting the tuple - * ---------------- - */ + /* store transaction information of xact deleting the tuple */ TransactionIdStore(GetCurrentTransactionId(), &(tp.t_data->t_xmax)); tp.t_data->t_cmax = GetCurrentCommandId(); - tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID); + tp.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | + HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE); - /* ---------------- - * invalidate caches - * ---------------- - */ + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + + /* invalidate caches */ RelationInvalidateHeapTuple(relation, &tp); - WriteBuffer(buf); - if (IsSystemRelationName(RelationGetRelationName(relation)->data)) - RelationUnsetLockForWrite(relation); + WriteBuffer(buffer); - return 0; + return HeapTupleMayBeUpdated; } -/* ---------------- - * heap_replace - replace a tuple - * - * Must decide how to handle errors. - * - * Fix arguments, work with indexes. - * - * 12/30/93 - modified the return value to be 1 when - * a non-functional update is detected. This - * prevents the calling routine from updating - * indices unnecessarily. -kw - * - * ---------------- +/* + * heap_replace - replace a tuple */ int -heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup) +heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup, + ItemPointer ctid) { ItemId lp; HeapTupleData oldtup; - Page dp; + PageHeader dp; Buffer buffer; + int result; - /* ---------------- - * increment access statistics - * ---------------- - */ + /* increment access statistics */ IncrHeapAccessStat(local_replace); IncrHeapAccessStat(global_replace); - /* ---------------- - * sanity checks - * ---------------- - */ Assert(ItemPointerIsValid(otid)); - /* ---------------- - * set relation level write lock - * ---------------- - */ - if (!relation->rd_islocal) - RelationSetLockForWrite(relation); - buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(otid)); if (!BufferIsValid(buffer)) elog(ERROR, "amreplace: failed ReadBuffer"); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); - dp = (Page) BufferGetPage(buffer); + dp = (PageHeader) BufferGetPage(buffer); lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(otid)); - /* ---------------- - * logically delete old item - * ---------------- - */ - oldtup.t_data = (HeapTupleHeader) PageGetItem(dp, lp); oldtup.t_len = ItemIdGetLength(lp); oldtup.t_self = *otid; - /* ----------------- - * the following test should be able to catch all non-functional - * update attempts and shut out all ghost tuples. - * XXX In the future, Spyros may need to update the rule lock on a tuple - * more than once within the same command and same transaction. - * He will have to introduce a new flag to override the following check. - * -- Wei - * - * ----------------- - */ - - if (TupleUpdatedByCurXactAndCmd(&oldtup)) +l2: + result = HeapTupleSatisfiesUpdate(&oldtup); + + if (result == HeapTupleInvisible) { - elog(NOTICE, "Non-functional update, only first update is performed"); - if (IsSystemRelationName(RelationGetRelationName(relation)->data)) - RelationUnsetLockForWrite(relation); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); - return 1; + elog(ERROR, "heap_replace: (am)invalid tid"); } - - /* ---------------- - * check that we're replacing a valid item - - * - * NOTE that this check must follow the non-functional update test - * above as it can happen that we try to 'replace' the same tuple - * twice in a single transaction. The second time around the - * tuple will fail the NowTimeQual. We don't want to abort the - * xact, we only want to flag the 'non-functional' NOTICE. -mer - * ---------------- - */ - HeapTupleSatisfies((&oldtup), - relation, - buffer, - (PageHeader) dp, - false, - 0, - (ScanKey) NULL); - if (!(oldtup.t_data)) + else if (result == HeapTupleBeingUpdated) { + TransactionId xwait = oldtup.t_data->t_xmax; + + /* sleep untill concurrent transaction ends */ + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + XactLockTableWait(xwait); + + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); + if (TransactionIdDidAbort(xwait)) + goto l2; + /* concurrent xact committed */ + Assert(oldtup.t_data->t_xmax == xwait); + if (!(oldtup.t_data->t_infomask & HEAP_XMAX_COMMITTED)) + { + oldtup.t_data->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(buffer); + } + /* if tuple was marked for update but not updated... */ + if (oldtup.t_data->t_infomask & HEAP_MARKED_FOR_UPDATE) + result = HeapTupleMayBeUpdated; + else + result = HeapTupleUpdated; + } + if (result != HeapTupleMayBeUpdated) + { + Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated); + if (ctid != NULL) + *ctid = oldtup.t_data->t_ctid; + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); - elog(ERROR, "heap_replace: (am)invalid otid"); + return result; } /* XXX order problems if not atomic assignment ??? */ @@ -1354,42 +1272,122 @@ heap_replace(Relation relation, ItemPointer otid, HeapTuple newtup) newtup->t_data->t_infomask &= ~(HEAP_XACT_MASK); newtup->t_data->t_infomask |= HEAP_XMAX_INVALID; - /* ---------------- - * insert new item - * ---------------- - */ + /* logically delete old item */ + TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax)); + oldtup.t_data->t_cmax = GetCurrentCommandId(); + oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | + HEAP_XMAX_INVALID | HEAP_MARKED_FOR_UPDATE); + + /* insert new item */ if ((unsigned) DOUBLEALIGN(newtup->t_len) <= PageGetFreeSpace((Page) dp)) - RelationPutHeapTuple(relation, BufferGetBlockNumber(buffer), newtup); + RelationPutHeapTuple(relation, buffer, newtup); else { - /* ---------------- - * new item won't fit on same page as old item, have to look - * for a new place to put it. - * ---------------- + /* + * New item won't fit on same page as old item, have to look + * for a new place to put it. Note that we have to unlock + * current buffer context - not good but RelationPutHeapTupleAtEnd + * uses extend lock. */ - doinsert(relation, newtup); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + RelationPutHeapTupleAtEnd(relation, newtup); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); } - /* ---------------- - * new item in place, now record transaction information - * ---------------- + /* + * New item in place, now record address of new tuple in + * t_ctid of old one. */ - TransactionIdStore(GetCurrentTransactionId(), &(oldtup.t_data->t_xmax)); - oldtup.t_data->t_cmax = GetCurrentCommandId(); - oldtup.t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID); + oldtup.t_data->t_ctid = newtup->t_self; - /* ---------------- - * invalidate caches - * ---------------- - */ + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + + /* invalidate caches */ RelationInvalidateHeapTuple(relation, &oldtup); WriteBuffer(buffer); - if (IsSystemRelationName(RelationGetRelationName(relation)->data)) - RelationUnsetLockForWrite(relation); + return HeapTupleMayBeUpdated; +} + +/* + * heap_mark4update - mark a tuple for update + */ +int +heap_mark4update(Relation relation, HeapTuple tuple, Buffer *buffer) +{ + ItemPointer tid = &(tuple->t_self); + ItemId lp; + PageHeader dp; + int result; + + /* increment access statistics */ + IncrHeapAccessStat(local_mark4update); + IncrHeapAccessStat(global_mark4update); + + *buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); + + if (!BufferIsValid(*buffer)) + elog(ERROR, "heap_mark4update: failed ReadBuffer"); + + LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); + + dp = (PageHeader) BufferGetPage(*buffer); + lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); + tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); + tuple->t_len = ItemIdGetLength(lp); + +l3: + result = HeapTupleSatisfiesUpdate(tuple); + + if (result == HeapTupleInvisible) + { + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); + ReleaseBuffer(*buffer); + elog(ERROR, "heap_mark4update: (am)invalid tid"); + } + else if (result == HeapTupleBeingUpdated) + { + TransactionId xwait = tuple->t_data->t_xmax; + + /* sleep untill concurrent transaction ends */ + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); + XactLockTableWait(xwait); + + LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE); + if (TransactionIdDidAbort(xwait)) + goto l3; + /* concurrent xact committed */ + Assert(tuple->t_data->t_xmax == xwait); + if (!(tuple->t_data->t_infomask & HEAP_XMAX_COMMITTED)) + { + tuple->t_data->t_infomask |= HEAP_XMAX_COMMITTED; + SetBufferCommitInfoNeedsSave(*buffer); + } + /* if tuple was marked for update but not updated... */ + if (tuple->t_data->t_infomask & HEAP_MARKED_FOR_UPDATE) + result = HeapTupleMayBeUpdated; + else + result = HeapTupleUpdated; + } + if (result != HeapTupleMayBeUpdated) + { + Assert(result == HeapTupleSelfUpdated || result == HeapTupleUpdated); + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); + return result; + } + + /* store transaction information of xact marking the tuple */ + TransactionIdStore(GetCurrentTransactionId(), &(tuple->t_data->t_xmax)); + tuple->t_data->t_cmax = GetCurrentCommandId(); + tuple->t_data->t_infomask &= ~(HEAP_XMAX_COMMITTED | HEAP_XMAX_INVALID); + tuple->t_data->t_infomask |= HEAP_MARKED_FOR_UPDATE; + + LockBuffer(*buffer, BUFFER_LOCK_UNLOCK); + + WriteNoReleaseBuffer(*buffer); - return 0; + return HeapTupleMayBeUpdated; } /* ---------------- diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c index 5c727145f6f..462de54ccfd 100644 --- a/src/backend/access/heap/hio.c +++ b/src/backend/access/heap/hio.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Id: hio.c,v 1.14 1998/11/27 19:51:36 vadim Exp $ + * $Id: hio.c,v 1.15 1998/12/15 12:45:14 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -15,6 +15,7 @@ #include <postgres.h> #include <storage/bufpage.h> +#include <access/hio.h> #include <access/heapam.h> #include <storage/bufmgr.h> #include <utils/memutils.h> @@ -29,19 +30,20 @@ * Probably needs to have an amdelunique to allow for * internal index records to be deleted and reordered as needed. * For the heap AM, this should never be needed. + * + * Note - we assume that caller hold BUFFER_LOCK_EXCLUSIVE on the buffer. + * */ void RelationPutHeapTuple(Relation relation, - BlockNumber blockIndex, + Buffer buffer, HeapTuple tuple) { - Buffer buffer; - Page pageHeader; - BlockNumber numberOfBlocks; - OffsetNumber offnum; - unsigned int len; - ItemId itemId; - Item item; + Page pageHeader; + OffsetNumber offnum; + unsigned int len; + ItemId itemId; + Item item; /* ---------------- * increment access statistics @@ -50,21 +52,6 @@ RelationPutHeapTuple(Relation relation, IncrHeapAccessStat(local_RelationPutHeapTuple); IncrHeapAccessStat(global_RelationPutHeapTuple); - Assert(RelationIsValid(relation)); - Assert(HeapTupleIsValid(tuple)); - - numberOfBlocks = RelationGetNumberOfBlocks(relation); - Assert(blockIndex < numberOfBlocks); - - buffer = ReadBuffer(relation, blockIndex); -#ifndef NO_BUFFERISVALID - if (!BufferIsValid(buffer)) - { - elog(ERROR, "RelationPutHeapTuple: no buffer for %ld in %s", - blockIndex, &relation->rd_rel->relname); - } -#endif - pageHeader = (Page) BufferGetPage(buffer); len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */ Assert((int) len <= PageGetFreeSpace(pageHeader)); @@ -75,11 +62,17 @@ RelationPutHeapTuple(Relation relation, itemId = PageGetItemId((Page) pageHeader, offnum); item = PageGetItem((Page) pageHeader, itemId); - ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, blockIndex, offnum); + ItemPointerSet(&((HeapTupleHeader) item)->t_ctid, + BufferGetBlockNumber(buffer), offnum); + /* + * Let the caller do this! + * WriteBuffer(buffer); + */ + /* return an accurate tuple */ - ItemPointerSet(&tuple->t_self, blockIndex, offnum); + ItemPointerSet(&tuple->t_self, BufferGetBlockNumber(buffer), offnum); } /* @@ -99,6 +92,7 @@ RelationPutHeapTuple(Relation relation, * RelationGetNumberOfBlocks to be useful. * * NOTE: This code presumes that we have a write lock on the relation. + * Not now - we use extend locking... * * Also note that this routine probably shouldn't have to exist, and does * screw up the call graph rather badly, but we are wasting so much time and @@ -116,8 +110,8 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple) ItemId itemId; Item item; - Assert(RelationIsValid(relation)); - Assert(HeapTupleIsValid(tuple)); + if (!relation->rd_islocal) + LockRelation(relation, ExtendLock); /* * XXX This does an lseek - VERY expensive - but at the moment it is @@ -132,16 +126,18 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple) { buffer = ReadBuffer(relation, lastblock); pageHeader = (Page) BufferGetPage(buffer); - if (PageIsNew((PageHeader) pageHeader)) - { - buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW); - pageHeader = (Page) BufferGetPage(buffer); - PageInit(pageHeader, BufferGetPageSize(buffer), 0); - } + /* + * There was IF instead of ASSERT here ?! + */ + Assert(PageIsNew((PageHeader) pageHeader)); + buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW); + pageHeader = (Page) BufferGetPage(buffer); + PageInit(pageHeader, BufferGetPageSize(buffer), 0); } else buffer = ReadBuffer(relation, lastblock - 1); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); pageHeader = (Page) BufferGetPage(buffer); len = (unsigned) DOUBLEALIGN(tuple->t_len); /* be conservative */ @@ -152,7 +148,9 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple) if (len > PageGetFreeSpace(pageHeader)) { + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); buffer = ReleaseAndReadBuffer(buffer, relation, P_NEW); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); pageHeader = (Page) BufferGetPage(buffer); PageInit(pageHeader, BufferGetPageSize(buffer), 0); @@ -160,6 +158,9 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple) elog(ERROR, "Tuple is too big: size %d", len); } + if (!relation->rd_islocal) + UnlockRelation(relation, ExtendLock); + offnum = PageAddItem((Page) pageHeader, (Item) tuple->t_data, tuple->t_len, InvalidOffsetNumber, LP_USED); @@ -173,5 +174,7 @@ RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple) /* return an accurate tuple */ ItemPointerSet(&tuple->t_self, lastblock, offnum); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); WriteBuffer(buffer); + } diff --git a/src/backend/access/heap/stats.c b/src/backend/access/heap/stats.c index 2bebfd9b0be..d630dedf815 100644 --- a/src/backend/access/heap/stats.c +++ b/src/backend/access/heap/stats.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.13 1997/09/08 02:20:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/heap/Attic/stats.c,v 1.14 1998/12/15 12:45:15 vadim Exp $ * * NOTES * initam should be moved someplace else. @@ -73,6 +73,7 @@ InitHeapAccessStatistics() stats->global_insert = 0; stats->global_delete = 0; stats->global_replace = 0; + stats->global_mark4update = 0; stats->global_markpos = 0; stats->global_restrpos = 0; stats->global_BufferGetRelation = 0; @@ -94,6 +95,7 @@ InitHeapAccessStatistics() stats->local_insert = 0; stats->local_delete = 0; stats->local_replace = 0; + stats->local_mark4update = 0; stats->local_markpos = 0; stats->local_restrpos = 0; stats->local_BufferGetRelation = 0; @@ -157,6 +159,7 @@ ResetHeapAccessStatistics() stats->local_insert = 0; stats->local_delete = 0; stats->local_replace = 0; + stats->local_mark4update = 0; stats->local_markpos = 0; stats->local_restrpos = 0; stats->local_BufferGetRelation = 0; @@ -274,6 +277,9 @@ PrintHeapAccessStatistics(HeapAccessStatistics stats) printf("local/global_replace: %6d/%6d\n", stats->local_replace, stats->global_replace); + printf("local/global_mark4update: %6d/%6d\n", + stats->local_mark4update, stats->global_mark4update); + printf("local/global_markpos: %6d/%6d\n", stats->local_markpos, stats->global_markpos); diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index aa2d9446504..f1516c669b3 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.28 1998/10/02 16:27:43 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.29 1998/12/15 12:45:15 vadim Exp $ * * INTERFACE ROUTINES * index_open - open an index relation by relationId @@ -225,7 +225,7 @@ index_beginscan(Relation relation, RELATION_CHECKS; GET_REL_PROCEDURE(beginscan, ambeginscan); - RelationSetRIntentLock(relation); + LockRelation(relation, AccessShareLock); scandesc = (IndexScanDesc) fmgr(procedure, relation, scanFromEnd, numberOfKeys, key); @@ -262,7 +262,7 @@ index_endscan(IndexScanDesc scan) fmgr(procedure, scan); - RelationUnsetRIntentLock(scan->relation); + UnlockRelation(scan->relation, AccessShareLock); } /* ---------------- diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 44349cfe3c7..54ea9ed8abd 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.31 1998/11/27 19:51:40 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.32 1998/12/15 12:45:20 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -18,6 +18,7 @@ #include <storage/bufpage.h> #include <access/nbtree.h> #include <access/heapam.h> +#include <access/xact.h> #include <storage/bufmgr.h> #include <fmgr.h> @@ -67,6 +68,8 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel /* trade in our read lock for a write lock */ _bt_relbuf(rel, buf, BT_READ); + +l1: buf = _bt_getbuf(rel, blkno, BT_WRITE); /* @@ -120,9 +123,25 @@ _bt_doinsert(Relation rel, BTItem btitem, bool index_is_unique, Relation heapRel { /* they're equal */ btitem = (BTItem) PageGetItem(page, PageGetItemId(page, offset)); htup.t_self = btitem->bti_itup.t_tid; - heap_fetch(heapRel, SnapshotSelf, &htup, &buffer); - if (htup.t_data != NULL) - { /* it is a duplicate */ + heap_fetch(heapRel, SnapshotDirty, &htup, &buffer); + if (htup.t_data != NULL) /* it is a duplicate */ + { + TransactionId xwait = + (TransactionIdIsValid(SnapshotDirty->xmin)) ? + SnapshotDirty->xmin : SnapshotDirty->xmax; + + /* + * If this tuple is being updated by other transaction + * then we have to wait for its commit/abort. + */ + if (TransactionIdIsValid(xwait)) + { + if (nbuf != InvalidBuffer) + _bt_relbuf(rel, nbuf, BT_READ); + _bt_relbuf(rel, buf, BT_WRITE); + XactLockTableWait(xwait); + goto l1; /* continue from the begin */ + } elog(ERROR, "Cannot insert a duplicate key into a unique index"); } /* htup null so no buffer to release */ diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 223efc5c91e..306f4fa0e93 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.16 1998/09/01 03:21:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.17 1998/12/15 12:45:23 vadim Exp $ * * NOTES * Postgres btree pages look like ordinary relation pages. The opaque @@ -93,7 +93,7 @@ _bt_metapinit(Relation rel) /* can't be sharing this with anyone, now... */ if (USELOCKING) - RelationSetLockForWrite(rel); + LockRelation(rel, AccessExclusiveLock); if ((nblocks = RelationGetNumberOfBlocks(rel)) != 0) { @@ -120,7 +120,7 @@ _bt_metapinit(Relation rel) /* all done */ if (USELOCKING) - RelationUnsetLockForWrite(rel); + UnlockRelation(rel, AccessExclusiveLock); } #ifdef NOT_USED @@ -571,32 +571,26 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access) static void _bt_setpagelock(Relation rel, BlockNumber blkno, int access) { - ItemPointerData iptr; if (USELOCKING) { - ItemPointerSet(&iptr, blkno, P_HIKEY); - if (access == BT_WRITE) - RelationSetSingleWLockPage(rel, &iptr); + LockPage(rel, blkno, ExclusiveLock); else - RelationSetSingleRLockPage(rel, &iptr); + LockPage(rel, blkno, ShareLock); } } static void _bt_unsetpagelock(Relation rel, BlockNumber blkno, int access) { - ItemPointerData iptr; if (USELOCKING) { - ItemPointerSet(&iptr, blkno, P_HIKEY); - if (access == BT_WRITE) - RelationUnsetSingleWLockPage(rel, &iptr); + UnlockPage(rel, blkno, ExclusiveLock); else - RelationUnsetSingleRLockPage(rel, &iptr); + UnlockPage(rel, blkno, ShareLock); } } diff --git a/src/backend/access/rtree/rtree.c b/src/backend/access/rtree/rtree.c index 3a8feda536d..9bf6d90dae1 100644 --- a/src/backend/access/rtree/rtree.c +++ b/src/backend/access/rtree/rtree.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.29 1998/11/27 19:51:41 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtree.c,v 1.30 1998/12/15 12:45:25 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -107,9 +107,6 @@ rtbuild(Relation heap, initRtstate(&rtState, index); - /* rtrees only know how to do stupid locking now */ - RelationSetLockForWrite(index); - pred = predInfo->pred; oldPred = predInfo->oldPred; @@ -250,7 +247,6 @@ rtbuild(Relation heap, /* okay, all heap tuples are indexed */ heap_endscan(scan); - RelationUnsetLockForWrite(index); if (pred != NULL || oldPred != NULL) { @@ -308,10 +304,14 @@ rtinsert(Relation r, Datum *datum, char *nulls, ItemPointer ht_ctid, Relation he itup->t_tid = *ht_ctid; initRtstate(&rtState, r); + /* + * Notes in ExecUtils:ExecOpenIndices() + * RelationSetLockForWrite(r); + */ + res = rtdoinsert(r, itup, &rtState); - /* XXX two-phase locking -- don't unlock the relation until EOT */ return res; } @@ -946,8 +946,12 @@ rtdelete(Relation r, ItemPointer tid) Buffer buf; Page page; - /* must write-lock on delete */ + /* + * Notes in ExecUtils:ExecOpenIndices() + * Also note that only vacuum deletes index tuples now... + * RelationSetLockForWrite(r); + */ blkno = ItemPointerGetBlockNumber(tid); offnum = ItemPointerGetOffsetNumber(tid); @@ -963,7 +967,6 @@ rtdelete(Relation r, ItemPointer tid) WriteBuffer(buf); - /* XXX -- two-phase locking, don't release the write lock */ return (char *) NULL; } diff --git a/src/backend/access/rtree/rtscan.c b/src/backend/access/rtree/rtscan.c index 6d0bb632e7f..f2c7927d273 100644 --- a/src/backend/access/rtree/rtscan.c +++ b/src/backend/access/rtree/rtscan.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.19 1998/09/01 04:27:12 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.20 1998/12/15 12:45:29 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -66,7 +66,12 @@ rtbeginscan(Relation r, { IndexScanDesc s; + /* + * Let index_beginscan does its work... + * RelationSetLockForRead(r); + */ + s = RelationGetIndexScan(r, fromEnd, nkeys, key); rtregscan(s); diff --git a/src/backend/access/transam/transam.c b/src/backend/access/transam/transam.c index 5bcce3c2d70..b68b6ab6691 100644 --- a/src/backend/access/transam/transam.c +++ b/src/backend/access/transam/transam.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.19 1998/09/01 04:27:15 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/transam.c,v 1.20 1998/12/15 12:45:30 vadim Exp $ * * NOTES * This file contains the high level access-method interface to the @@ -172,8 +172,12 @@ TransactionLogTest(TransactionId transactionId, /* transaction id to test */ if (!fail) { - TransactionIdStore(transactionId, &cachedTestXid); - cachedTestXidStatus = xidstatus; + /* must not cache status of running xaction !!! */ + if (xidstatus != XID_INPROGRESS) + { + TransactionIdStore(transactionId, &cachedTestXid); + cachedTestXidStatus = xidstatus; + } return (bool) (status == xidstatus); } @@ -219,11 +223,14 @@ TransactionLogUpdate(TransactionId transactionId, /* trans id to update */ status, &fail); - /* ---------------- - * update (invalidate) our single item TransactionLogTest cache. - * ---------------- - */ + /* + * update (invalidate) our single item TransactionLogTest cache. + * if (status != XID_COMMIT) + * + * What's the hell ?! Why != XID_COMMIT ?! + */ + if (status != XID_INPROGRESS) { TransactionIdStore(transactionId, &cachedTestXid); cachedTestXidStatus = status; diff --git a/src/backend/access/transam/transsup.c b/src/backend/access/transam/transsup.c index 6f1b09b5774..edf953384f9 100644 --- a/src/backend/access/transam/transsup.c +++ b/src/backend/access/transam/transsup.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.17 1998/09/01 04:27:16 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/Attic/transsup.c,v 1.18 1998/12/15 12:45:33 vadim Exp $ * * NOTES * This file contains support functions for the high @@ -289,18 +289,12 @@ TransBlockNumberGetXidStatus(Relation relation, XidStatus xstatus; /* recorded status of xid */ bool localfail; /* bool used if failP = NULL */ - /* ---------------- - * SOMEDAY place a read lock on the log relation - * That someday is today 5 Aug 1991 -mer - * ---------------- - */ - RelationSetLockForRead(relation); - /* ---------------- * get the page containing the transaction information * ---------------- */ buffer = ReadBuffer(relation, blockNumber); + LockBuffer(buffer, BUFFER_LOCK_SHARE); block = BufferGetBlock(buffer); /* ---------------- @@ -318,14 +312,9 @@ TransBlockNumberGetXidStatus(Relation relation, * release the buffer and return the status * ---------------- */ + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); ReleaseBuffer(buffer); - /* ---------------- - * SOMEDAY release our lock on the log relation - * ---------------- - */ - RelationUnsetLockForRead(relation); - return xstatus; } @@ -345,19 +334,12 @@ TransBlockNumberSetXidStatus(Relation relation, Block block; /* block containing xstatus */ bool localfail; /* bool used if failP = NULL */ - /* ---------------- - * SOMEDAY gain exclusive access to the log relation - * - * That someday is today 5 Aug 1991 -mer - * ---------------- - */ - RelationSetLockForWrite(relation); - /* ---------------- * get the block containing the transaction status * ---------------- */ buffer = ReadBuffer(relation, blockNumber); + LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE); block = BufferGetBlock(buffer); /* ---------------- @@ -372,16 +354,11 @@ TransBlockNumberSetXidStatus(Relation relation, TransBlockSetXidStatus(block, xid, xstatus); + LockBuffer(buffer, BUFFER_LOCK_UNLOCK); if ((*failP) == false) WriteBuffer(buffer); else ReleaseBuffer(buffer); - - /* ---------------- - * SOMEDAY release our lock on the log relation - * ---------------- - */ - RelationUnsetLockForWrite(relation); } /* -------------------------------- diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 35bcbfed6a4..002b43cd040 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.25 1998/10/08 18:29:15 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.26 1998/12/15 12:45:35 vadim Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -194,6 +194,8 @@ TransactionStateData CurrentTransactionStateData = { TransactionState CurrentTransactionState = &CurrentTransactionStateData; +int XactIsoLevel = XACT_SERIALIZED; + /* ---------------- * info returned when the system is disabled * @@ -816,6 +818,8 @@ StartTransaction() */ GetNewTransactionId(&(s->transactionIdData)); + XactLockTableInsert(s->transactionIdData); + /* ---------------- * initialize current transaction state fields * ---------------- @@ -966,6 +970,7 @@ AbortTransaction() * do abort processing * ---------------- */ + UnlockBuffers(); AtAbort_Notify(); CloseSequences(); AtEOXact_portals(); diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 6c4fb244571..b9057176307 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.17 1998/11/27 19:51:46 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.18 1998/12/15 12:45:39 vadim Exp $ * * NOTES * See acl.h. @@ -162,7 +162,7 @@ ChangeAcl(char *relname, tuple = heap_modifytuple(tuple, relation, values, nulls, replaces); /* XXX handle index on pg_class? */ setheapoverride(true); - heap_replace(relation, &tuple->t_self, tuple); + heap_replace(relation, &tuple->t_self, tuple, NULL); setheapoverride(false); /* keep the catalog indices up to date */ diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 3fbdcec4e32..bc897c5965c 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.69 1998/12/14 05:18:37 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.70 1998/12/15 12:45:40 vadim Exp $ * * INTERFACE ROUTINES * heap_create() - Create an uncataloged heap relation @@ -929,7 +929,7 @@ RelationRemoveInheritance(Relation relation) while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) { - heap_delete(catalogRelation, &tuple->t_self); + heap_delete(catalogRelation, &tuple->t_self, NULL); found = true; } @@ -951,7 +951,7 @@ RelationRemoveInheritance(Relation relation) &entry); while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) - heap_delete(catalogRelation, &tuple->t_self); + heap_delete(catalogRelation, &tuple->t_self, NULL); heap_endscan(scan); heap_close(catalogRelation); @@ -1020,7 +1020,7 @@ DeletePgRelationTuple(Relation rel) * delete the relation tuple from pg_class, and finish up. * ---------------- */ - heap_delete(pg_class_desc, &tup->t_self); + heap_delete(pg_class_desc, &tup->t_self, NULL); pfree(tup); heap_close(pg_class_desc); @@ -1048,7 +1048,7 @@ DeletePgAttributeTuples(Relation rel) * Get a write lock _before_ getting the read lock in the scan * ---------------- */ - RelationSetLockForWrite(pg_attribute_desc); + LockRelation(pg_attribute_desc, AccessExclusiveLock); for (attnum = FirstLowInvalidHeapAttributeNumber + 1; attnum <= rel->rd_att->natts; @@ -1059,7 +1059,7 @@ DeletePgAttributeTuples(Relation rel) Int16GetDatum(attnum), 0, 0))) { - heap_delete(pg_attribute_desc, &tup->t_self); + heap_delete(pg_attribute_desc, &tup->t_self, NULL); pfree(tup); } } @@ -1068,7 +1068,7 @@ DeletePgAttributeTuples(Relation rel) * Release the write lock * ---------------- */ - RelationUnsetLockForWrite(pg_attribute_desc); + UnlockRelation(pg_attribute_desc, AccessExclusiveLock); heap_close(pg_attribute_desc); } @@ -1183,7 +1183,7 @@ DeletePgTypeTuple(Relation rel) * we release the read lock on pg_type. -mer 13 Aug 1991 * ---------------- */ - heap_delete(pg_type_desc, &tup->t_self); + heap_delete(pg_type_desc, &tup->t_self, NULL); heap_endscan(pg_type_scan); heap_close(pg_type_desc); @@ -1209,7 +1209,7 @@ heap_destroy_with_catalog(char *relname) if (rel == NULL) elog(ERROR, "Relation %s Does Not Exist!", relname); - RelationSetLockForWrite(rel); + LockRelation(rel, AccessExclusiveLock); rid = rel->rd_id; /* ---------------- @@ -1288,7 +1288,7 @@ heap_destroy_with_catalog(char *relname) rel->rd_tmpunlinked = TRUE; - RelationUnsetLockForWrite(rel); + UnlockRelation(rel, AccessExclusiveLock); heap_close(rel); @@ -1608,16 +1608,16 @@ RemoveAttrDefault(Relation rel) ScanKeyEntryInitialize(&key, 0, Anum_pg_attrdef_adrelid, F_OIDEQ, rel->rd_id); - RelationSetLockForWrite(adrel); + LockRelation(adrel, AccessExclusiveLock); adscan = heap_beginscan(adrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tup = heap_getnext(adscan, 0))) - heap_delete(adrel, &tup->t_self); + heap_delete(adrel, &tup->t_self, NULL); heap_endscan(adscan); - RelationUnsetLockForWrite(adrel); + UnlockRelation(adrel, AccessExclusiveLock); heap_close(adrel); } @@ -1635,16 +1635,16 @@ RemoveRelCheck(Relation rel) ScanKeyEntryInitialize(&key, 0, Anum_pg_relcheck_rcrelid, F_OIDEQ, rel->rd_id); - RelationSetLockForWrite(rcrel); + LockRelation(rcrel, AccessExclusiveLock); rcscan = heap_beginscan(rcrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tup = heap_getnext(rcscan, 0))) - heap_delete(rcrel, &tup->t_self); + heap_delete(rcrel, &tup->t_self, NULL); heap_endscan(rcscan); - RelationUnsetLockForWrite(rcrel); + UnlockRelation(rcrel, AccessExclusiveLock); heap_close(rcrel); } diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 0c487bc2496..29565ba285e 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.65 1998/12/13 04:37:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.66 1998/12/15 12:45:43 vadim Exp $ * * * INTERFACE ROUTINES @@ -913,7 +913,7 @@ UpdateIndexPredicate(Oid indexoid, Node *oldPred, Node *predicate) newtup = heap_modifytuple(tuple, pg_index, values, nulls, replace); - heap_replace(pg_index, &newtup->t_self, newtup); + heap_replace(pg_index, &newtup->t_self, newtup, NULL); pfree(newtup); heap_close(pg_index); @@ -1039,15 +1039,11 @@ index_create(char *heapRelationName, heapRelation = heap_open(heapoid); - /* ---------------- - * write lock heap to guarantee exclusive access - * ---------------- - RelationSetLockForWrite(heapRelation); - * ^^^^^ - * Does it have any sense ? - vadim 10/27/97 + /* + * Only SELECT ... FOR UPDATE are allowed */ - RelationSetLockForRead(heapRelation); + LockRelation(heapRelation, ShareLock); /* ---------------- * construct new tuple descriptor @@ -1195,7 +1191,7 @@ index_destroy(Oid indexId) AssertState(HeapTupleIsValid(tuple)); - heap_delete(relationRelation, &tuple->t_self); + heap_delete(relationRelation, &tuple->t_self, NULL); pfree(tuple); heap_close(relationRelation); @@ -1212,7 +1208,7 @@ index_destroy(Oid indexId) Int16GetDatum(attnum), 0, 0))) { - heap_delete(attributeRelation, &tuple->t_self); + heap_delete(attributeRelation, &tuple->t_self, NULL); pfree(tuple); attnum++; } @@ -1232,7 +1228,7 @@ index_destroy(Oid indexId) indexRelation = heap_openr(IndexRelationName); - heap_delete(indexRelation, &tuple->t_self); + heap_delete(indexRelation, &tuple->t_self, NULL); pfree(tuple); heap_close(indexRelation); @@ -1424,7 +1420,7 @@ UpdateStats(Oid relid, long reltuples, bool hasindex) values[Anum_pg_class_relhasindex - 1] = CharGetDatum(hasindex); newtup = heap_modifytuple(tuple, pg_class, values, nulls, replace); - heap_replace(pg_class, &tuple->t_self, newtup); + heap_replace(pg_class, &tuple->t_self, newtup, NULL); CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); CatalogIndexInsert(idescs, Num_pg_class_indices, pg_class, newtup); CatalogCloseIndices(Num_pg_class_indices, idescs); diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c index 96fb9ae35f6..40a33fd5b55 100644 --- a/src/backend/catalog/pg_operator.c +++ b/src/backend/catalog/pg_operator.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.30 1998/11/27 19:51:50 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.31 1998/12/15 12:45:45 vadim Exp $ * * NOTES * these routines moved here from commands/define.c and somewhat cleaned up. @@ -711,7 +711,7 @@ OperatorDef(char *operatorName, replaces); setheapoverride(true); - heap_replace(pg_operator_desc, &tup->t_self, tup); + heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); } else @@ -830,7 +830,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) replaces); setheapoverride(true); - heap_replace(pg_operator_desc, &tup->t_self, tup); + heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); } @@ -855,7 +855,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) replaces); setheapoverride(true); - heap_replace(pg_operator_desc, &tup->t_self, tup); + heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); values[Anum_pg_operator_oprcom - 1] = (Datum) NULL; @@ -884,7 +884,7 @@ OperatorUpd(Oid baseId, Oid commId, Oid negId) replaces); setheapoverride(true); - heap_replace(pg_operator_desc, &tup->t_self, tup); + heap_replace(pg_operator_desc, &tup->t_self, tup, NULL); setheapoverride(false); } diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index f46bb8f3a2a..f67317defe0 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.31 1998/11/27 19:51:51 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.32 1998/12/15 12:45:47 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -459,7 +459,7 @@ TypeCreate(char *typeName, * when the heap_insert() or heap_replace() is called. * ----------------- */ - RelationSetLockForWrite(pg_type_desc); + LockRelation(pg_type_desc, AccessExclusiveLock); typeKey[0].sk_argument = PointerGetDatum(typeName); pg_type_scan = heap_beginscan(pg_type_desc, @@ -484,7 +484,7 @@ TypeCreate(char *typeName, replaces); setheapoverride(true); - heap_replace(pg_type_desc, &tup->t_self, tup); + heap_replace(pg_type_desc, &tup->t_self, tup, NULL); setheapoverride(false); typeObjectId = tup->t_data->t_oid; @@ -516,7 +516,7 @@ TypeCreate(char *typeName, CatalogIndexInsert(idescs, Num_pg_type_indices, pg_type_desc, tup); CatalogCloseIndices(Num_pg_type_indices, idescs); } - RelationUnsetLockForWrite(pg_type_desc); + UnlockRelation(pg_type_desc, AccessExclusiveLock); heap_close(pg_type_desc); return typeObjectId; @@ -561,7 +561,7 @@ TypeRename(char *oldTypeName, char *newTypeName) namestrcpy(&(((Form_pg_type) GETSTRUCT(oldtup))->typname), newTypeName); setheapoverride(true); - heap_replace(pg_type_desc, &oldtup->t_self, oldtup); + heap_replace(pg_type_desc, &oldtup->t_self, oldtup, NULL); setheapoverride(false); /* update the system catalog indices */ diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c index 50d4f13cc09..b18941781d4 100644 --- a/src/backend/commands/async.c +++ b/src/backend/commands/async.c @@ -6,7 +6,7 @@ * Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.42 1998/11/27 19:51:53 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.43 1998/12/15 12:45:50 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -218,7 +218,7 @@ Async_Listen(char *relname, int pid) TPRINTF(TRACE_NOTIFY, "Async_Listen: %s", relname); lRel = heap_openr(ListenerRelationName); - RelationSetLockForWrite(lRel); + LockRelation(lRel, AccessExclusiveLock); tdesc = RelationGetDescr(lRel); /* Detect whether we are already listening on this relname */ @@ -242,7 +242,7 @@ Async_Listen(char *relname, int pid) if (alreadyListener) { elog(NOTICE, "Async_Listen: We are already listening on %s", relname); - RelationUnsetLockForWrite(lRel); + UnlockRelation(lRel, AccessExclusiveLock); heap_close(lRel); return; } @@ -267,7 +267,7 @@ Async_Listen(char *relname, int pid) heap_insert(lRel, newtup); pfree(newtup); - RelationUnsetLockForWrite(lRel); + UnlockRelation(lRel, AccessExclusiveLock); heap_close(lRel); /* @@ -320,9 +320,9 @@ Async_Unlisten(char *relname, int pid) if (lTuple != NULL) { lRel = heap_openr(ListenerRelationName); - RelationSetLockForWrite(lRel); - heap_delete(lRel, &lTuple->t_self); - RelationUnsetLockForWrite(lRel); + LockRelation(lRel, AccessExclusiveLock); + heap_delete(lRel, &lTuple->t_self, NULL); + UnlockRelation(lRel, AccessExclusiveLock); heap_close(lRel); } /* We do not complain about unlistening something not being listened; @@ -358,7 +358,7 @@ Async_UnlistenAll() TPRINTF(TRACE_NOTIFY, "Async_UnlistenAll"); lRel = heap_openr(ListenerRelationName); - RelationSetLockForWrite(lRel); + LockRelation(lRel, AccessExclusiveLock); tdesc = RelationGetDescr(lRel); /* Find and delete all entries with my listenerPID */ @@ -369,10 +369,10 @@ Async_UnlistenAll() sRel = heap_beginscan(lRel, 0, SnapshotNow, 1, key); while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0))) - heap_delete(lRel, &lTuple->t_self); + heap_delete(lRel, &lTuple->t_self, NULL); heap_endscan(sRel); - RelationUnsetLockForWrite(lRel); + UnlockRelation(lRel, AccessExclusiveLock); heap_close(lRel); } @@ -463,7 +463,7 @@ AtCommit_Notify() TPRINTF(TRACE_NOTIFY, "AtCommit_Notify"); lRel = heap_openr(ListenerRelationName); - RelationSetLockForWrite(lRel); + LockRelation(lRel, AccessExclusiveLock); tdesc = RelationGetDescr(lRel); sRel = heap_beginscan(lRel, 0, SnapshotNow, 0, (ScanKey) NULL); @@ -516,7 +516,7 @@ AtCommit_Notify() * but as far as I can see we should just do it for any * failure (certainly at least for EPERM too...) */ - heap_delete(lRel, &lTuple->t_self); + heap_delete(lRel, &lTuple->t_self, NULL); } else #endif @@ -527,7 +527,7 @@ AtCommit_Notify() { rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl); - heap_replace(lRel, &lTuple->t_self, rTuple); + heap_replace(lRel, &lTuple->t_self, rTuple, NULL); } } } @@ -741,7 +741,7 @@ ProcessIncomingNotify(void) StartTransactionCommand(); lRel = heap_openr(ListenerRelationName); - RelationSetLockForWrite(lRel); + LockRelation(lRel, AccessExclusiveLock); tdesc = RelationGetDescr(lRel); /* Scan only entries with my listenerPID */ @@ -772,7 +772,7 @@ ProcessIncomingNotify(void) NotifyMyFrontEnd(relname, sourcePID); /* Rewrite the tuple with 0 in notification column */ rTuple = heap_modifytuple(lTuple, lRel, value, nulls, repl); - heap_replace(lRel, &lTuple->t_self, rTuple); + heap_replace(lRel, &lTuple->t_self, rTuple, NULL); } } heap_endscan(sRel); diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 6cbf8b980cb..f1fc29f6f6e 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.33 1998/11/27 19:51:54 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.34 1998/12/15 12:45:52 vadim Exp $ * * NOTES * The PortalExecutorHeapMemory crap needs to be eliminated @@ -482,7 +482,7 @@ PerformAddAttribute(char *relationName, heap_close(attrdesc); ((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts; - heap_replace(rel, &reltup->t_self, reltup); + heap_replace(rel, &reltup->t_self, reltup, NULL); /* keep catalog indices current */ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs); diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 419874e5d49..61151ef6aad 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.64 1998/11/27 19:51:54 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.65 1998/12/15 12:45:53 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -777,6 +777,20 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim) pfree(typmod); } pfree(byval); + + /* comments in execUtils.c */ + if (has_index) + { + for (i = 0; i < n_indices; i++) + { + if (index_rels[i] == NULL) + continue; + if ((index_rels[i])->rd_rel->relam != BTREE_AM_OID && + (index_rels[i])->rd_rel->relam != HASH_AM_OID) + UnlockRelation(index_rels[i], AccessExclusiveLock); + index_close(index_rels[i]); + } + } heap_close(rel); } @@ -914,7 +928,14 @@ GetIndexRelations(Oid main_relation_oid, *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation)); for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next) + { (*index_rels)[i] = index_open(scan->index_rel_oid); + /* comments in execUtils.c */ + if ((*index_rels)[i] != NULL && + ((*index_rels)[i])->rd_rel->relam != BTREE_AM_OID && + ((*index_rels)[i])->rd_rel->relam != HASH_AM_OID) + LockRelation((*index_rels)[i], AccessExclusiveLock); + } for (i = 0, scan = head; i < *n_indices + 1; i++) { diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index d25d430c39c..a774ca1deb1 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.27 1998/12/14 05:18:43 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.28 1998/12/15 12:45:55 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -235,7 +235,7 @@ check_permissions(char *command, * delays when multiple 'createdb's or 'destroydb's are run simult. * -mer 7/3/91 */ - RelationSetLockForWrite(dbrel); + LockRelation(dbrel, AccessExclusiveLock); dbtup = get_pg_dbtup(command, dbname, dbrel); dbfound = HeapTupleIsValid(dbtup); diff --git a/src/backend/commands/defind.c b/src/backend/commands/defind.c index c071c2d9fe8..33d069e6517 100644 --- a/src/backend/commands/defind.c +++ b/src/backend/commands/defind.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.28 1998/11/27 19:51:56 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.29 1998/12/15 12:45:56 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -342,7 +342,7 @@ ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable) heapRelation = heap_open(relationId); indexRelation = index_open(indexId); - RelationSetLockForWrite(heapRelation); + LockRelation(heapRelation, ShareLock); InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId); diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c index c8b4e836f02..d95c4efdff7 100644 --- a/src/backend/commands/proclang.c +++ b/src/backend/commands/proclang.c @@ -174,7 +174,7 @@ DropProceduralLanguage(DropPLangStmt *stmt) } rel = heap_openr(LanguageRelationName); - heap_delete(rel, &langTup->t_self); + heap_delete(rel, &langTup->t_self, NULL); pfree(langTup); heap_close(rel); diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c index e662e90ec56..e11983ea8e9 100644 --- a/src/backend/commands/remove.c +++ b/src/backend/commands/remove.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.30 1998/11/27 19:51:57 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.31 1998/12/15 12:45:57 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -102,7 +102,7 @@ RemoveOperator(char *operatorName, /* operator name */ elog(ERROR, "RemoveOperator: operator '%s': permission denied", operatorName); #endif - heap_delete(relation, &tup->t_self); + heap_delete(relation, &tup->t_self, NULL); } else { @@ -157,7 +157,7 @@ SingleOpOperatorRemove(Oid typeOid) key[0].sk_attno = attnums[i]; scan = heap_beginscan(rel, 0, SnapshotNow, 1, key); while (HeapTupleIsValid(tup = heap_getnext(scan, 0))) - heap_delete(rel, &tup->t_self); + heap_delete(rel, &tup->t_self, NULL); heap_endscan(scan); } heap_close(rel); @@ -268,7 +268,7 @@ RemoveType(char *typeName) /* type name to be removed */ relation = heap_openr(TypeRelationName); typeOid = tup->t_data->t_oid; - heap_delete(relation, &tup->t_self); + heap_delete(relation, &tup->t_self, NULL); /* Now, Delete the "array of" that type */ shadow_type = makeArrayTypeName(typeName); @@ -282,7 +282,7 @@ RemoveType(char *typeName) /* type name to be removed */ } typeOid = tup->t_data->t_oid; - heap_delete(relation, &tup->t_self); + heap_delete(relation, &tup->t_self, NULL); heap_close(relation); } @@ -357,7 +357,7 @@ RemoveFunction(char *functionName, /* function name to be removed */ elog(ERROR, "RemoveFunction: function \"%s\" is built-in", functionName); } - heap_delete(relation, &tup->t_self); + heap_delete(relation, &tup->t_self, NULL); heap_close(relation); } @@ -428,7 +428,7 @@ RemoveAggregate(char *aggName, char *aggType) aggName); } } - heap_delete(relation, &tup->t_self); + heap_delete(relation, &tup->t_self, NULL); heap_close(relation); } diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c index c423da11963..2977d9e79d0 100644 --- a/src/backend/commands/rename.c +++ b/src/backend/commands/rename.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.18 1998/11/27 19:51:57 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.19 1998/12/15 12:45:58 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -180,7 +180,7 @@ renameatt(char *relname, newattname, NAMEDATALEN); attrelation = heap_openr(AttributeRelationName); - heap_replace(attrelation, &oldatttup->t_self, oldatttup); + heap_replace(attrelation, &oldatttup->t_self, oldatttup, NULL); /* keep system catalog indices current */ CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations); @@ -248,7 +248,7 @@ renamerel(char *oldrelname, char *newrelname) /* insert fixed rel tuple */ relrelation = heap_openr(RelationRelationName); - heap_replace(relrelation, &oldreltup->t_self, oldreltup); + heap_replace(relrelation, &oldreltup->t_self, oldreltup, NULL); /* keep the system catalog indices current */ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, irelations); diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 9edec5a9dc6..e391936cbf8 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -162,7 +162,7 @@ DefineSequence(CreateSeqStmt *seq) rel = heap_openr(seq->seqname); Assert(RelationIsValid(rel)); - RelationSetLockForWrite(rel); + LockRelation(rel, AccessExclusiveLock); tupDesc = RelationGetDescr(rel); @@ -185,7 +185,7 @@ DefineSequence(CreateSeqStmt *seq) if (WriteBuffer(buf) == STATUS_ERROR) elog(ERROR, "DefineSequence: WriteBuffer failed"); - RelationUnsetLockForWrite(rel); + UnlockRelation(rel, AccessExclusiveLock); heap_close(rel); return; @@ -200,7 +200,6 @@ nextval(struct varlena * seqin) SeqTable elm; Buffer buf; Form_pg_sequence seq; - ItemPointerData iptr; int4 incby, maxv, minv, @@ -209,7 +208,7 @@ nextval(struct varlena * seqin) next, rescnt = 0; - /* open and WIntentLock sequence */ + /* open and AccessShareLock sequence */ elm = init_sequence("nextval", seqname); pfree(seqname); @@ -219,7 +218,7 @@ nextval(struct varlena * seqin) return elm->last; } - seq = read_info("nextval", elm, &buf); /* lock page and read + seq = read_info("nextval", elm, &buf); /* lock page' buffer and read * tuple */ next = result = seq->last_value; @@ -282,12 +281,11 @@ nextval(struct varlena * seqin) seq->last_value = next; /* last fetched number */ seq->is_called = 't'; + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + if (WriteBuffer(buf) == STATUS_ERROR) elog(ERROR, "%s.nextval: WriteBuffer failed", elm->name); - ItemPointerSet(&iptr, 0, FirstOffsetNumber); - RelationUnsetSingleWLockPage(elm->rel, &iptr); - return result; } @@ -300,7 +298,7 @@ currval(struct varlena * seqin) SeqTable elm; int4 result; - /* open and WIntentLock sequence */ + /* open and AccessShareLock sequence */ elm = init_sequence("currval", seqname); pfree(seqname); @@ -320,7 +318,6 @@ setval(struct varlena * seqin, int4 next) SeqTable elm; Buffer buf; Form_pg_sequence seq; - ItemPointerData iptr; #ifndef NO_SECURITY if (pg_aclcheck(seqname, getpgusername(), ACL_WR) != ACLCHECK_OK) @@ -328,9 +325,9 @@ setval(struct varlena * seqin, int4 next) seqname, seqname); #endif - /* open and WIntentLock sequence */ + /* open and AccessShareLock sequence */ elm = init_sequence("setval", seqname); - seq = read_info("setval", elm, &buf); /* lock page and read + seq = read_info("setval", elm, &buf); /* lock page' buffer and read * tuple */ if (seq->cache_value != 1) @@ -353,27 +350,22 @@ setval(struct varlena * seqin, int4 next) seq->last_value = next; /* last fetched number */ seq->is_called = 't'; + LockBuffer(buf, BUFFER_LOCK_UNLOCK); + if (WriteBuffer(buf) == STATUS_ERROR) elog(ERROR, "%s.settval: WriteBuffer failed", seqname); - ItemPointerSet(&iptr, 0, FirstOffsetNumber); - RelationUnsetSingleWLockPage(elm->rel, &iptr); - return next; } static Form_pg_sequence read_info(char *caller, SeqTable elm, Buffer *buf) { - ItemPointerData iptr; - PageHeader page; - ItemId lp; + PageHeader page; + ItemId lp; HeapTupleData tuple; sequence_magic *sm; - Form_pg_sequence seq; - - ItemPointerSet(&iptr, 0, FirstOffsetNumber); - RelationSetSingleWLockPage(elm->rel, &iptr); + Form_pg_sequence seq; if (RelationGetNumberOfBlocks(elm->rel) != 1) elog(ERROR, "%s.%s: invalid number of blocks in sequence", @@ -383,6 +375,8 @@ read_info(char *caller, SeqTable elm, Buffer *buf) if (!BufferIsValid(*buf)) elog(ERROR, "%s.%s: ReadBuffer failed", elm->name, caller); + LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE); + page = (PageHeader) BufferGetPage(*buf); sm = (sequence_magic *) PageGetSpecialPointer(page); @@ -439,7 +433,7 @@ init_sequence(char *caller, char *name) if (!RelationIsValid(temp->rel)) elog(ERROR, "%s.%s: sequence does not exist", name, caller); - RelationSetWIntentLock(temp->rel); + LockRelation(temp->rel, AccessShareLock); if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE) elog(ERROR, "%s.%s: %s is not sequence !", name, caller, name); @@ -485,7 +479,7 @@ CloseSequences(void) { rel = elm->rel; elm->rel = (Relation) NULL; - RelationUnsetWIntentLock(rel); + UnlockRelation(rel, AccessShareLock); heap_close(rel); } elm = elm->next; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 431a70a6ff9..60d0056930b 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -40,7 +40,7 @@ void RelationBuildTriggers(Relation relation); void FreeTriggerDesc(Relation relation); static void DescribeTrigger(TriggerDesc *trigdesc, Trigger *trigger); -static HeapTuple GetTupleForTrigger(Relation relation, ItemPointer tid, +static HeapTuple GetTupleForTrigger(EState *estate, ItemPointer tid, bool before); extern GlobalMemory CacheCxt; @@ -77,7 +77,7 @@ CreateTrigger(CreateTrigStmt *stmt) if (!RelationIsValid(rel)) elog(ERROR, "CreateTrigger: there is no relation %s", stmt->relname); - RelationSetLockForWrite(rel); + LockRelation(rel, AccessExclusiveLock); TRIGGER_CLEAR_TYPE(tgtype); if (stmt->before) @@ -114,7 +114,7 @@ CreateTrigger(CreateTrigStmt *stmt) /* Scan pg_trigger */ tgrel = heap_openr(TriggerRelationName); - RelationSetLockForWrite(tgrel); + LockRelation(tgrel, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, F_OIDEQ, RelationGetRelid(rel)); tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); @@ -211,7 +211,7 @@ CreateTrigger(CreateTrigStmt *stmt) CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple); CatalogCloseIndices(Num_pg_trigger_indices, idescs); pfree(tuple); - RelationUnsetLockForWrite(tgrel); + UnlockRelation(tgrel, AccessExclusiveLock); heap_close(tgrel); pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1])); @@ -227,7 +227,7 @@ CreateTrigger(CreateTrigStmt *stmt) pgrel = heap_openr(RelationRelationName); ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1; RelationInvalidateHeapTuple(pgrel, tuple); - heap_replace(pgrel, &tuple->t_self, tuple); + heap_replace(pgrel, &tuple->t_self, tuple, NULL); CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs); CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple); CatalogCloseIndices(Num_pg_class_indices, ridescs); @@ -267,10 +267,10 @@ DropTrigger(DropTrigStmt *stmt) if (!RelationIsValid(rel)) elog(ERROR, "DropTrigger: there is no relation %s", stmt->relname); - RelationSetLockForWrite(rel); + LockRelation(rel, AccessExclusiveLock); tgrel = heap_openr(TriggerRelationName); - RelationSetLockForWrite(tgrel); + LockRelation(tgrel, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, F_OIDEQ, RelationGetRelid(rel)); tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); @@ -280,7 +280,7 @@ DropTrigger(DropTrigStmt *stmt) if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0) { - heap_delete(tgrel, &tuple->t_self); + heap_delete(tgrel, &tuple->t_self, NULL); tgfound++; } else @@ -293,7 +293,7 @@ DropTrigger(DropTrigStmt *stmt) elog(NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s", tgfound, stmt->trigname, stmt->relname); heap_endscan(tgscan); - RelationUnsetLockForWrite(tgrel); + UnlockRelation(tgrel, AccessExclusiveLock); heap_close(tgrel); tuple = SearchSysCacheTupleCopy(RELNAME, @@ -306,7 +306,7 @@ DropTrigger(DropTrigStmt *stmt) pgrel = heap_openr(RelationRelationName); ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found; RelationInvalidateHeapTuple(pgrel, tuple); - heap_replace(pgrel, &tuple->t_self, tuple); + heap_replace(pgrel, &tuple->t_self, tuple, NULL); CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs); CatalogIndexInsert(ridescs, Num_pg_class_indices, pgrel, tuple); CatalogCloseIndices(Num_pg_class_indices, ridescs); @@ -333,17 +333,17 @@ RelationRemoveTriggers(Relation rel) HeapTuple tup; tgrel = heap_openr(TriggerRelationName); - RelationSetLockForWrite(tgrel); + LockRelation(tgrel, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid, F_OIDEQ, RelationGetRelid(rel)); tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &key); while (HeapTupleIsValid(tup = heap_getnext(tgscan, 0))) - heap_delete(tgrel, &tup->t_self); + heap_delete(tgrel, &tup->t_self, NULL); heap_endscan(tgscan); - RelationUnsetLockForWrite(tgrel); + UnlockRelation(tgrel, AccessExclusiveLock); heap_close(tgrel); } @@ -376,7 +376,6 @@ RelationBuildTriggers(Relation relation) ObjectIdGetDatum(RelationGetRelid(relation))); tgrel = heap_openr(TriggerRelationName); - RelationSetLockForRead(tgrel); irel = index_openr(TriggerRelidIndex); sd = index_beginscan(irel, false, 1, &skey); @@ -450,7 +449,6 @@ RelationBuildTriggers(Relation relation) index_endscan(sd); pfree(sd); index_close(irel); - RelationUnsetLockForRead(tgrel); heap_close(tgrel); /* Build trigdesc */ @@ -657,16 +655,17 @@ ExecARInsertTriggers(Relation rel, HeapTuple trigtuple) } bool -ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid) +ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid) { - TriggerData *SaveTriggerData; - int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE]; - Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; - HeapTuple trigtuple; - HeapTuple newtuple = NULL; - int i; - - trigtuple = GetTupleForTrigger(rel, tupleid, true); + Relation rel = estate->es_result_relation_info->ri_RelationDesc; + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_DELETE]; + Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_DELETE]; + HeapTuple trigtuple; + HeapTuple newtuple = NULL; + int i; + + trigtuple = GetTupleForTrigger(estate, tupleid, true); if (trigtuple == NULL) return false; @@ -692,15 +691,16 @@ ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid) } void -ExecARDeleteTriggers(Relation rel, ItemPointer tupleid) +ExecARDeleteTriggers(EState *estate, ItemPointer tupleid) { + Relation rel = estate->es_result_relation_info->ri_RelationDesc; TriggerData *SaveTriggerData; int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_DELETE]; Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_DELETE]; HeapTuple trigtuple; int i; - trigtuple = GetTupleForTrigger(rel, tupleid, false); + trigtuple = GetTupleForTrigger(estate, tupleid, false); Assert(trigtuple != NULL); SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); @@ -722,17 +722,18 @@ ExecARDeleteTriggers(Relation rel, ItemPointer tupleid) } HeapTuple -ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple) +ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) { - TriggerData *SaveTriggerData; - int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE]; - Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE]; - HeapTuple trigtuple; - HeapTuple oldtuple; - HeapTuple intuple = newtuple; - int i; - - trigtuple = GetTupleForTrigger(rel, tupleid, true); + Relation rel = estate->es_result_relation_info->ri_RelationDesc; + TriggerData *SaveTriggerData; + int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_UPDATE]; + Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_UPDATE]; + HeapTuple trigtuple; + HeapTuple oldtuple; + HeapTuple intuple = newtuple; + int i; + + trigtuple = GetTupleForTrigger(estate, tupleid, true); if (trigtuple == NULL) return NULL; @@ -759,15 +760,16 @@ ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple) } void -ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple) +ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple newtuple) { + Relation rel = estate->es_result_relation_info->ri_RelationDesc; TriggerData *SaveTriggerData; int ntrigs = rel->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE]; Trigger **trigger = rel->trigdesc->tg_after_row[TRIGGER_EVENT_UPDATE]; HeapTuple trigtuple; int i; - trigtuple = GetTupleForTrigger(rel, tupleid, false); + trigtuple = GetTupleForTrigger(estate, tupleid, false); Assert(trigtuple != NULL); SaveTriggerData = (TriggerData *) palloc(sizeof(TriggerData)); @@ -789,48 +791,67 @@ ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple newtuple) } static HeapTuple -GetTupleForTrigger(Relation relation, ItemPointer tid, bool before) +GetTupleForTrigger(EState *estate, ItemPointer tid, bool before) { - ItemId lp; + Relation relation = estate->es_result_relation_info->ri_RelationDesc; HeapTupleData tuple; HeapTuple result; - PageHeader dp; - Buffer b; + Buffer buffer; - b = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); + if (before) + { + int test; + + /* + * mark tuple for update + */ + tuple.t_self = *tid; + test = heap_mark4update(relation, &tuple, &buffer); + switch (test) + { + case HeapTupleSelfUpdated: + ReleaseBuffer(buffer); + return(NULL); - if (!BufferIsValid(b)) - elog(ERROR, "GetTupleForTrigger: failed ReadBuffer"); + case HeapTupleMayBeUpdated: + break; - dp = (PageHeader) BufferGetPage(b); - lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); + case HeapTupleUpdated: + ReleaseBuffer(buffer); + if (XactIsoLevel == XACT_SERIALIZED) + elog(ERROR, "Serialize access failed due to concurrent update"); + else + elog(ERROR, "Isolation level %u is not supported", XactIsoLevel); + return(NULL); - Assert(ItemIdIsUsed(lp)); + default: + ReleaseBuffer(buffer); + elog(ERROR, "Unknown status %u from heap_mark4update", test); + return(NULL); + } + } + else + { + PageHeader dp; + ItemId lp; - tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); - tuple.t_len = ItemIdGetLength(lp); - tuple.t_self = *tid; + buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid)); - if (before) - { - if (TupleUpdatedByCurXactAndCmd(&tuple)) - { - elog(NOTICE, "GetTupleForTrigger: Non-functional delete/update"); - ReleaseBuffer(b); - return NULL; - } + if (!BufferIsValid(buffer)) + elog(ERROR, "GetTupleForTrigger: failed ReadBuffer"); - HeapTupleSatisfies(&tuple, relation, b, dp, - false, 0, (ScanKey) NULL); - if (!tuple.t_data) - { - ReleaseBuffer(b); - elog(ERROR, "GetTupleForTrigger: (am)invalid tid"); - } + dp = (PageHeader) BufferGetPage(buffer); + lp = PageGetItemId(dp, ItemPointerGetOffsetNumber(tid)); + + Assert(ItemIdIsUsed(lp)); + + tuple.t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp); + tuple.t_len = ItemIdGetLength(lp); + tuple.t_self = *tid; } result = heap_copytuple(&tuple); - ReleaseBuffer(b); + ReleaseBuffer(buffer); return result; } diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index e0c0e51ea13..7c4203528fa 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: user.c,v 1.22 1998/12/14 08:11:00 scrappy Exp $ + * $Id: user.c,v 1.23 1998/12/15 12:46:00 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -136,7 +136,7 @@ DefineUser(CreateUserStmt *stmt) * Secure a write lock on pg_shadow so we can be sure of what the next * usesysid should be. */ - RelationSetLockForWrite(pg_shadow_rel); + LockRelation(pg_shadow_rel, AccessExclusiveLock); scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, NULL); while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) @@ -154,7 +154,7 @@ DefineUser(CreateUserStmt *stmt) if (exists) { - RelationUnsetLockForWrite(pg_shadow_rel); + UnlockRelation(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel); UserAbortTransactionBlock(); elog(ERROR, @@ -187,7 +187,7 @@ DefineUser(CreateUserStmt *stmt) * This goes after the UpdatePgPwdFile to be certain that two backends * to not attempt to write to the pg_pwd file at the same time. */ - RelationUnsetLockForWrite(pg_shadow_rel); + UnlockRelation(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel); if (IsTransactionBlock() && !inblock) @@ -235,14 +235,14 @@ AlterUser(AlterUserStmt *stmt) * dump of the pg_pwd file is done, there is not another backend doing * the same. */ - RelationSetLockForWrite(pg_shadow_rel); + LockRelation(pg_shadow_rel, AccessExclusiveLock); tuple = SearchSysCacheTuple(USENAME, PointerGetDatum(stmt->user), 0, 0, 0); if (!HeapTupleIsValid(tuple)) { - RelationUnsetLockForWrite(pg_shadow_rel); + UnlockRelation(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel); UserAbortTransactionBlock(); /* needed? */ elog(ERROR, "alterUser: user \"%s\" does not exist", stmt->user); @@ -288,7 +288,7 @@ AlterUser(AlterUserStmt *stmt) UpdatePgPwdFile(sql); - RelationUnsetLockForWrite(pg_shadow_rel); + UnlockRelation(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel); if (IsTransactionBlock() && !inblock) @@ -342,14 +342,14 @@ RemoveUser(char *user) * dump of the pg_pwd file is done, there is not another backend doing * the same. */ - RelationSetLockForWrite(pg_shadow_rel); + LockRelation(pg_shadow_rel, AccessExclusiveLock); tuple = SearchSysCacheTuple(USENAME, PointerGetDatum(user), 0, 0, 0); if (!HeapTupleIsValid(tuple)) { - RelationUnsetLockForWrite(pg_shadow_rel); + UnlockRelation(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel); UserAbortTransactionBlock(); elog(ERROR, "removeUser: user \"%s\" does not exist", user); @@ -422,7 +422,7 @@ RemoveUser(char *user) UpdatePgPwdFile(sql); - RelationUnsetLockForWrite(pg_shadow_rel); + UnlockRelation(pg_shadow_rel, AccessExclusiveLock); heap_close(pg_shadow_rel); if (IsTransactionBlock() && !inblock) diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index f7bed005add..608dd729ffa 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.91 1998/11/27 19:51:58 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.92 1998/12/15 12:46:01 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -497,7 +497,7 @@ vc_vacone(Oid relid, bool analyze, List *va_cols) } /* we require the relation to be locked until the indices are cleaned */ - RelationSetLockForWrite(onerel); + LockRelation(onerel, AccessExclusiveLock); /* scan it */ vacuum_pages.vpl_num_pages = fraged_pages.vpl_num_pages = 0; @@ -1918,7 +1918,7 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums) if (i >= attcnt) continue; /* don't delete it */ } - heap_delete(pgstatistic, &tuple->t_self); + heap_delete(pgstatistic, &tuple->t_self, NULL); } heap_endscan(scan); @@ -1928,11 +1928,7 @@ vc_delhilowstats(Oid relid, int attcnt, int *attnums) static void vc_setpagelock(Relation rel, BlockNumber blkno) { - ItemPointerData itm; - - ItemPointerSet(&itm, blkno, 1); - - RelationSetLockForWritePage(rel, &itm); + LockPage(rel, blkno, ExclusiveLock); } /* diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 45be159ae17..712f2285342 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.59 1998/11/27 19:51:59 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.60 1998/12/15 12:46:04 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -51,6 +51,7 @@ /* #include "access/localam.h" */ #include "optimizer/var.h" #include "access/heapam.h" +#include "access/xact.h" #include "catalog/heap.h" #include "commands/trigger.h" @@ -421,7 +422,6 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) { /****************** * if we have a result relation, open it and - * initialize the result relation info stuff. ****************** */ @@ -440,14 +440,7 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) elog(ERROR, "You can't change sequence relation %s", resultRelationDesc->rd_rel->relname.data); - /* - * Write-lock the result relation right away: if the relation is - * used in a subsequent scan, we won't have to elevate the - * read-lock set by heap_beginscan to a write-lock (needed by - * heap_insert, heap_delete and heap_replace). This will hopefully - * prevent some deadlocks. - 01/24/94 - */ - RelationSetLockForWrite(resultRelationDesc); + LockRelation(resultRelationDesc, RowExclusiveLock); resultRelationInfo = makeNode(RelationInfo); resultRelationInfo->ri_RangeTableIndex = resultRelationIndex; @@ -461,7 +454,8 @@ InitPlan(CmdType operation, Query *parseTree, Plan *plan, EState *estate) * in the result relation information.. ****************** */ - ExecOpenIndices(resultRelationOid, resultRelationInfo); + if (operation != CMD_DELETE) + ExecOpenIndices(resultRelationOid, resultRelationInfo); estate->es_result_relation_info = resultRelationInfo; } @@ -1006,8 +1000,10 @@ ExecDelete(TupleTableSlot *slot, ItemPointer tupleid, EState *estate) { - RelationInfo *resultRelationInfo; - Relation resultRelationDesc; + RelationInfo *resultRelationInfo; + Relation resultRelationDesc; + ItemPointerData ctid; + int result; /****************** * get the result relation information @@ -1022,19 +1018,35 @@ ExecDelete(TupleTableSlot *slot, { bool dodelete; - dodelete = ExecBRDeleteTriggers(resultRelationDesc, tupleid); + dodelete = ExecBRDeleteTriggers(estate, tupleid); if (!dodelete) /* "do nothing" */ return; } - /****************** + /* * delete the tuple - ****************** */ - if (heap_delete(resultRelationDesc, /* relation desc */ - tupleid)) /* item pointer to tuple */ - return; + result = heap_delete(resultRelationDesc, tupleid, &ctid); + switch (result) + { + case HeapTupleSelfUpdated: + return; + + case HeapTupleMayBeUpdated: + break; + + case HeapTupleUpdated: + if (XactIsoLevel == XACT_SERIALIZED) + elog(ERROR, "Serialize access failed due to concurrent update"); + else + elog(ERROR, "Isolation level %u is not supported", XactIsoLevel); + return; + + default: + elog(ERROR, "Unknown status %u from heap_delete", result); + return; + } IncrDeleted(); (estate->es_processed)++; @@ -1054,7 +1066,7 @@ ExecDelete(TupleTableSlot *slot, /* AFTER ROW DELETE Triggers */ if (resultRelationDesc->trigdesc && resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_DELETE] > 0) - ExecARDeleteTriggers(resultRelationDesc, tupleid); + ExecARDeleteTriggers(estate, tupleid); } @@ -1075,10 +1087,12 @@ ExecReplace(TupleTableSlot *slot, EState *estate, Query *parseTree) { - HeapTuple tuple; - RelationInfo *resultRelationInfo; - Relation resultRelationDesc; - int numIndices; + HeapTuple tuple; + RelationInfo *resultRelationInfo; + Relation resultRelationDesc; + ItemPointerData ctid; + int result; + int numIndices; /****************** * abort the operation if not running transactions @@ -1117,7 +1131,7 @@ ExecReplace(TupleTableSlot *slot, { HeapTuple newtuple; - newtuple = ExecBRUpdateTriggers(resultRelationDesc, tupleid, tuple); + newtuple = ExecBRUpdateTriggers(estate, tupleid, tuple); if (newtuple == NULL) /* "do nothing" */ return; @@ -1140,19 +1154,28 @@ ExecReplace(TupleTableSlot *slot, ExecConstraints("ExecReplace", resultRelationDesc, tuple); } - /****************** + /* * replace the heap tuple - * - * Don't want to continue if our heap_replace didn't actually - * do a replace. This would be the case if heap_replace - * detected a non-functional update. -kw 12/30/93 - ****************** */ - if (heap_replace(resultRelationDesc, /* relation desc */ - tupleid, /* item ptr of tuple to replace */ - tuple)) - { /* replacement heap tuple */ - return; + result = heap_replace(resultRelationDesc, tupleid, tuple, &ctid); + switch (result) + { + case HeapTupleSelfUpdated: + return; + + case HeapTupleMayBeUpdated: + break; + + case HeapTupleUpdated: + if (XactIsoLevel == XACT_SERIALIZED) + elog(ERROR, "Serialize access failed due to concurrent update"); + else + elog(ERROR, "Isolation level %u is not supported", XactIsoLevel); + return; + + default: + elog(ERROR, "Unknown status %u from heap_replace", result); + return; } IncrReplaced(); @@ -1187,7 +1210,7 @@ ExecReplace(TupleTableSlot *slot, /* AFTER ROW UPDATE Triggers */ if (resultRelationDesc->trigdesc && resultRelationDesc->trigdesc->n_after_row[TRIGGER_EVENT_UPDATE] > 0) - ExecARUpdateTriggers(resultRelationDesc, tupleid, tuple); + ExecARUpdateTriggers(estate, tupleid, tuple); } #if 0 diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 1af4fcbc88a..58dbcd19efc 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.40 1998/11/27 19:52:01 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execUtils.c,v 1.41 1998/12/15 12:46:05 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -868,7 +868,23 @@ ExecOpenIndices(Oid resultRelationOid, indexOid = lfirsti(indexoid); indexDesc = index_open(indexOid); if (indexDesc != NULL) + { relationDescs[i++] = indexDesc; + /* + * Hack for not btree and hash indices: they use relation level + * exclusive locking on updation (i.e. - they are not ready + * for MVCC) and so we have to exclusively lock indices here + * to prevent deadlocks if we will scan them - index_beginscan + * places AccessShareLock, indices update methods don't use + * locks at all. We release this lock in ExecCloseIndices. + * Note, that hashes use page level locking - i.e. are not + * deadlock-free, - let's them be on their way -:)) + * vadim 03-12-1998 + */ + if (indexDesc->rd_rel->relam != BTREE_AM_OID && + indexDesc->rd_rel->relam != HASH_AM_OID) + LockRelation(indexDesc, AccessExclusiveLock); + } } /* ---------------- @@ -948,9 +964,18 @@ ExecCloseIndices(RelationInfo *resultRelationInfo) relationDescs = resultRelationInfo->ri_IndexRelationDescs; for (i = 0; i < numIndices; i++) - if (relationDescs[i] != NULL) - index_close(relationDescs[i]); + { + if (relationDescs[i] == NULL) + continue; + /* + * Notes in ExecOpenIndices. + */ + if (relationDescs[i]->rd_rel->relam != BTREE_AM_OID && + relationDescs[i]->rd_rel->relam != HASH_AM_OID) + UnlockRelation(relationDescs[i], AccessExclusiveLock); + index_close(relationDescs[i]); + } /* * XXX should free indexInfo array here too. */ diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 5f528850ffa..5ec45c7c795 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -6,7 +6,7 @@ * Copyright (c) 1994, Regents of the University of California * * - * $Id: nodeHash.c,v 1.27 1998/12/14 08:11:02 scrappy Exp $ + * $Id: nodeHash.c,v 1.28 1998/12/15 12:46:06 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -693,13 +693,13 @@ ExecScanHashBucket(HashJoinState *hjstate, else heapTuple = (HeapTuple) LONGALIGN(((char *) curtuple + curtuple->t_len + HEAPTUPLESIZE)); - - heapTuple->t_data = (HeapTupleHeader) - ((char *) heapTuple + HEAPTUPLESIZE); while (heapTuple < (HeapTuple) ABSADDR(bucket->bottom)) { + heapTuple->t_data = (HeapTupleHeader) + ((char *) heapTuple + HEAPTUPLESIZE); + inntuple = ExecStoreTuple(heapTuple, /* tuple to store */ hjstate->hj_HashTupleSlot, /* slot */ InvalidBuffer, /* tuple has no buffer */ @@ -713,8 +713,6 @@ ExecScanHashBucket(HashJoinState *hjstate, heapTuple = (HeapTuple) LONGALIGN(((char *) heapTuple + heapTuple->t_len + HEAPTUPLESIZE)); - heapTuple->t_data = (HeapTupleHeader) - ((char *) heapTuple + HEAPTUPLESIZE); } if (firstotuple == NULL) diff --git a/src/backend/parser/gram.c b/src/backend/parser/gram.c index 6c484aecf18..0eb9d3eb137 100644 --- a/src/backend/parser/gram.c +++ b/src/backend/parser/gram.c @@ -235,7 +235,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.51 1998/12/14 05:18:57 scrappy Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/Attic/gram.c,v 2.52 1998/12/15 12:46:08 vadim Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index c2066a43b12..bc9c9a738a4 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.34 1998/12/13 23:54:40 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.35 1998/12/15 12:46:14 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -1115,7 +1115,6 @@ find_inheritors(Oid relid, Oid **supervec) inhrel = heap_openr(InheritsRelationName); - RelationSetLockForRead(inhrel); inhtupdesc = RelationGetDescr(inhrel); /* @@ -1182,7 +1181,6 @@ find_inheritors(Oid relid, Oid **supervec) } } while (qentry != (SuperQE *) NULL); - RelationUnsetLockForRead(inhrel); heap_close(inhrel); if (nvisited > 0) diff --git a/src/backend/rewrite/rewriteRemove.c b/src/backend/rewrite/rewriteRemove.c index fd1472a93cf..8be2f413cfc 100644 --- a/src/backend/rewrite/rewriteRemove.c +++ b/src/backend/rewrite/rewriteRemove.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.20 1998/12/14 00:02:17 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteRemove.c,v 1.21 1998/12/15 12:46:16 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -127,7 +127,7 @@ RemoveRewriteRule(char *ruleName) /* * Now delete the tuple... */ - heap_delete(RewriteRelation, &tuple->t_self); + heap_delete(RewriteRelation, &tuple->t_self, NULL); pfree(tuple); heap_close(RewriteRelation); @@ -164,7 +164,7 @@ RelationRemoveRules(Oid relid) 0, SnapshotNow, 1, &scanKeyData); while (HeapTupleIsValid(tuple = heap_getnext(scanDesc, 0))) - heap_delete(RewriteRelation, &tuple->t_self); + heap_delete(RewriteRelation, &tuple->t_self, NULL); heap_endscan(scanDesc); heap_close(RewriteRelation); diff --git a/src/backend/rewrite/rewriteSupport.c b/src/backend/rewrite/rewriteSupport.c index 2b57e277116..15a9b18b906 100644 --- a/src/backend/rewrite/rewriteSupport.c +++ b/src/backend/rewrite/rewriteSupport.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.29 1998/11/27 19:52:18 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteSupport.c,v 1.30 1998/12/15 12:46:18 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -128,7 +128,7 @@ setRelhasrulesInRelation(Oid relationId, bool relhasrules) relationRelation = heap_openr(RelationRelationName); ((Form_pg_class) GETSTRUCT(tuple))->relhasrules = relhasrules; - heap_replace(relationRelation, &tuple->t_self, tuple); + heap_replace(relationRelation, &tuple->t_self, tuple, NULL); /* keep the catalog indices up to date */ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs); diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 975e999ec2b..620708aaae3 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.19 1998/09/01 04:31:39 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.20 1998/12/15 12:46:18 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -62,13 +62,13 @@ BufferBlock BufferBlocks; #ifndef HAS_TEST_AND_SET long *NWaitIOBackendP; - #endif extern IpcSemaphoreId WaitIOSemId; long *PrivateRefCount; /* also used in freelist.c */ long *LastRefCount; /* refcounts of last ExecMain level */ +bits8 *BufferLocks; /* */ long *CommitInfoNeedsSave;/* to write buffers where we have filled * in t_infomask */ @@ -146,21 +146,6 @@ InitBufferPool(IPCKey key) foundDescs; int i; - /* check padding of BufferDesc and BufferHdr */ - - /* - * we need both checks because a sbufdesc_padded > - * PADDED_SBUFDESC_SIZE will shrink sbufdesc to the required size, - * which is bad - */ - if (sizeof(struct sbufdesc) != PADDED_SBUFDESC_SIZE || - sizeof(struct sbufdesc_unpadded) > PADDED_SBUFDESC_SIZE) - elog(ERROR, "Internal error: sbufdesc does not have the proper size, " - "contact the Postgres developers"); - if (sizeof(struct sbufdesc_unpadded) <= PADDED_SBUFDESC_SIZE / 2) - elog(ERROR, "Internal error: sbufdesc is greatly over-sized, " - "contact the Postgres developers"); - Data_Descriptors = NBuffers; Free_List_Descriptor = Data_Descriptors; Lookup_List_Descriptor = Data_Descriptors + 1; @@ -232,6 +217,7 @@ InitBufferPool(IPCKey key) buf->buf_id = i; #ifdef HAS_TEST_AND_SET S_INIT_LOCK(&(buf->io_in_progress_lock)); + S_INIT_LOCK(&(buf->cntx_lock)); #endif } @@ -252,10 +238,15 @@ InitBufferPool(IPCKey key) WaitIOSemId = IpcSemaphoreCreate(IPCKeyGetWaitIOSemaphoreKey(key), 1, IPCProtection, 0, 1, &status); + WaitCLSemId = IpcSemaphoreCreate(IPCKeyGetWaitCLSemaphoreKey(key), + 1, IPCProtection, + IpcSemaphoreDefaultStartValue, + 1, &status); } #endif PrivateRefCount = (long *) calloc(NBuffers, sizeof(long)); LastRefCount = (long *) calloc(NBuffers, sizeof(long)); + BufferLocks = (bits8*) calloc (NBuffers, sizeof(bits8)); CommitInfoNeedsSave = (long *) calloc(NBuffers, sizeof(long)); } diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index cab1e8084e0..d5fa26b6035 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.44 1998/10/08 18:29:54 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.45 1998/12/15 12:46:19 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -86,7 +86,6 @@ static void WaitIO(BufferDesc *buf, SPINLOCK spinlock); #ifndef HAS_TEST_AND_SET static void SignalIO(BufferDesc *buf); extern long *NWaitIOBackendP; /* defined in buf_init.c */ - #endif /* HAS_TEST_AND_SET */ static Buffer ReadBufferWithBufferLock(Relation relation, BlockNumber blockNum, @@ -583,7 +582,6 @@ BufferAlloc(Relation reln, if (buf->refcount > 1) SignalIO(buf); #endif /* !HAS_TEST_AND_SET */ - /* give up the buffer since we don't need it any more */ buf->refcount--; PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0; @@ -1096,6 +1094,7 @@ WaitIO(BufferDesc *buf, SPINLOCK spinlock) #else /* HAS_TEST_AND_SET */ IpcSemaphoreId WaitIOSemId; +IpcSemaphoreId WaitCLSemId; static void WaitIO(BufferDesc *buf, SPINLOCK spinlock) @@ -1933,3 +1932,147 @@ SetBufferCommitInfoNeedsSave(Buffer buffer) if (!BufferIsLocal(buffer)) CommitInfoNeedsSave[buffer - 1]++; } + +void +UnlockBuffers() +{ + BufferDesc *buf; + int i; + + for (i = 0; i < NBuffers; i++) + { + if (BufferLocks[i] == 0) + continue; + + Assert(BufferIsValid(i+1)); + buf = &(BufferDescriptors[i]); + +#ifdef HAS_TEST_AND_SET + S_LOCK(&(buf->cntx_lock)); +#else + IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock); +#endif + + if (BufferLocks[i] & BL_R_LOCK) + { + Assert(buf->r_locks > 0); + (buf->r_locks)--; + } + if (BufferLocks[i] & BL_RI_LOCK) + { + Assert(buf->ri_lock); + buf->ri_lock = false; + } + if (BufferLocks[i] & BL_W_LOCK) + { + Assert(buf->w_lock); + buf->w_lock = false; + } +#ifdef HAS_TEST_AND_SET + S_UNLOCK(&(buf->cntx_lock)); +#else + IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock); +#endif + BufferLocks[i] = 0; + } +} + +void +LockBuffer (Buffer buffer, int mode) +{ + BufferDesc *buf; + + Assert(BufferIsValid(buffer)); + if (BufferIsLocal(buffer)) + return; + + buf = &(BufferDescriptors[buffer-1]); + +#ifdef HAS_TEST_AND_SET + S_LOCK(&(buf->cntx_lock)); +#else + IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock); +#endif + + if (mode == BUFFER_LOCK_UNLOCK) + { + if (BufferLocks[buffer-1] & BL_R_LOCK) + { + Assert(buf->r_locks > 0); + Assert(!(buf->w_lock)); + Assert(!(BufferLocks[buffer-1] & (BL_W_LOCK | BL_RI_LOCK))) + (buf->r_locks)--; + BufferLocks[buffer-1] &= ~BL_R_LOCK; + } + else if (BufferLocks[buffer-1] & BL_W_LOCK) + { + Assert(buf->w_lock); + Assert(buf->r_locks == 0 && !buf->ri_lock); + Assert(!(BufferLocks[buffer-1] & (BL_R_LOCK | BL_RI_LOCK))) + buf->w_lock = false; + BufferLocks[buffer-1] &= ~BL_W_LOCK; + } + else + elog(ERROR, "UNLockBuffer: buffer %u is not locked", buffer); + } + else if (mode == BUFFER_LOCK_SHARE) + { + unsigned i = 0; + + Assert(!(BufferLocks[buffer-1] & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK))); + while (buf->ri_lock || buf->w_lock) + { +#ifdef HAS_TEST_AND_SET + S_UNLOCK(&(buf->cntx_lock)); + s_lock_sleep(i++); + S_LOCK(&(buf->cntx_lock)); +#else + IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock); + s_lock_sleep(i++) + IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock); +#endif + } + (buf->r_locks)++; + BufferLocks[buffer-1] |= BL_R_LOCK; + } + else if (mode == BUFFER_LOCK_EXCLUSIVE) + { + unsigned i = 0; + + Assert(!(BufferLocks[buffer-1] & (BL_R_LOCK | BL_W_LOCK | BL_RI_LOCK))); + while (buf->r_locks > 0 || buf->w_lock) + { + if (buf->r_locks > 3) + { + if (!(BufferLocks[buffer-1] & BL_RI_LOCK)) + BufferLocks[buffer-1] |= BL_RI_LOCK; + buf->ri_lock = true; + } +#ifdef HAS_TEST_AND_SET + S_UNLOCK(&(buf->cntx_lock)); + s_lock_sleep(i++); + S_LOCK(&(buf->cntx_lock)); +#else + IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock); + s_lock_sleep(i++) + IpcSemaphoreLock(WaitCLSemId, 0, IpcExclusiveLock); +#endif + } + buf->w_lock = true; + BufferLocks[buffer-1] |= BL_W_LOCK; + if (BufferLocks[buffer-1] & BL_RI_LOCK) + { + buf->ri_lock = false; + BufferLocks[buffer-1] &= ~BL_RI_LOCK; + } + } + else + elog(ERROR, "LockBuffer: unknown lock mode %d", mode); + +#ifdef HAS_TEST_AND_SET + S_UNLOCK(&(buf->cntx_lock)); +#else + IpcSemaphoreUnlock(WaitCLSemId, 0, IpcExclusiveLock); +#endif + +} diff --git a/src/backend/storage/buffer/s_lock.c b/src/backend/storage/buffer/s_lock.c index a7b42bc4793..439240a386f 100644 --- a/src/backend/storage/buffer/s_lock.c +++ b/src/backend/storage/buffer/s_lock.c @@ -7,13 +7,14 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.12 1998/09/18 17:18:39 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/Attic/s_lock.c,v 1.13 1998/12/15 12:46:21 vadim Exp $ * *------------------------------------------------------------------------- */ #include <stdio.h> #include <sys/time.h> +#include <unistd.h> #include "config.h" #include "c.h" @@ -52,6 +53,16 @@ s_lock_stuck(volatile slock_t *lock, const char *file, const int line) } +void +s_lock_sleep(unsigned spin) +{ + struct timeval delay; + + delay.tv_sec = 0; + delay.tv_usec = s_spincycle[spin % S_NSPINCYCLE]; + (void) select(0, NULL, NULL, NULL, &delay); +} + /* * s_lock(lock) - take a spinlock with backoff @@ -59,15 +70,11 @@ s_lock_stuck(volatile slock_t *lock, const char *file, const int line) void s_lock(volatile slock_t *lock, const char *file, const int line) { - int spins = 0; + unsigned spins = 0; while (TAS(lock)) { - struct timeval delay; - - delay.tv_sec = 0; - delay.tv_usec = s_spincycle[spins % S_NSPINCYCLE]; - (void) select(0, NULL, NULL, NULL, &delay); + s_lock_sleep(spins); if (++spins > S_MAX_BUSY) { /* It's been over a minute... */ diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index f6ce9eda241..47305f3f087 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.16 1998/09/01 03:25:10 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/ipci.c,v 1.17 1998/12/15 12:46:24 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -17,7 +17,6 @@ #include "postgres.h" #include "storage/ipc.h" -#include "storage/multilev.h" #include "storage/sinval.h" #include "storage/bufmgr.h" #include "storage/proc.h" @@ -92,7 +91,7 @@ CreateSharedMemoryAndSemaphores(IPCKey key) * ---------------- */ InitLocks(); - if (InitMultiLevelLocks() == INVALID_TABLEID) + if (InitLockTable() == INVALID_TABLEID) elog(FATAL, "Couldn't create the lock table"); /* ---------------- @@ -145,7 +144,7 @@ AttachSharedMemoryAndSemaphores(IPCKey key) * ---------------- */ InitLocks(); - if (InitMultiLevelLocks() == INVALID_TABLEID) + if (InitLockTable() == INVALID_TABLEID) elog(FATAL, "Couldn't attach to the lock table"); AttachSharedInvalidationState(key); diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c index 18b8d718d67..17416fc9eef 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.31 1998/09/01 04:31:49 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/ipc/shmem.c,v 1.32 1998/12/15 12:46:24 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -68,7 +68,8 @@ #include "utils/dynahash.h" #include "utils/hsearch.h" #include "utils/memutils.h" -#include "access/transam.h" +#include "access/xact.h" +#include "utils/tqual.h" /* shared memory global variables */ @@ -629,7 +630,6 @@ TransactionIdIsInProgress(TransactionId xid) return false; } -#ifdef LowLevelLocking /* * GetSnapshotData -- returns information about running transactions. * @@ -645,16 +645,15 @@ Snapshot GetSnapshotData(bool serialized) { Snapshot snapshot = (Snapshot) malloc(sizeof(SnapshotData)); - TransactionId snapshot->xip = (TransactionId *) - malloc(32 * sizeof(TransactionId)); ShmemIndexEnt *result; PROC *proc; TransactionId cid = GetCurrentTransactionId(); - uint count = 0; - unit free = 31; + uint32 count = 0; + uint32 have = 31; Assert(ShmemIndex); + snapshot->xip = (TransactionId *) malloc(32 * sizeof(TransactionId)); snapshot->xmax = cid; snapshot->xmin = cid; @@ -676,20 +675,20 @@ GetSnapshotData(bool serialized) continue; proc = (PROC *) MAKE_PTR(result->location); if (proc == MyProc || proc->xid < FirstTransactionId || - serialized && proc->xid >= cid) + (serialized && proc->xid >= cid)) continue; if (proc->xid < snapshot->xmin) snapshot->xmin = proc->xid; else if (proc->xid > snapshot->xmax) snapshot->xmax = proc->xid; - if (free == 0) + if (have == 0) { snapshot->xip = (TransactionId *) realloc(snapshot->xip, (count + 33) * sizeof(TransactionId)); - free = 32; + have = 32; } snapshot->xip[count] = proc->xid; - free--; + have--; count++; } @@ -699,5 +698,3 @@ GetSnapshotData(bool serialized) elog(ERROR, "GetSnapshotData: ShmemIndex corrupted"); return NULL; } - -#endif diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index 740a4132631..40460404197 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.43 1998/12/13 05:07:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/large_object/inv_api.c,v 1.44 1998/12/15 12:46:26 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -203,12 +203,12 @@ inv_create(int flags) if (flags & INV_WRITE) { - RelationSetLockForWrite(r); + LockRelation(r, ExclusiveLock); retval->flags = IFS_WRLOCK | IFS_RDLOCK; } else if (flags & INV_READ) { - RelationSetLockForRead(r); + LockRelation(r, ShareLock); retval->flags = IFS_RDLOCK; } retval->flags |= IFS_ATEOF; @@ -254,12 +254,12 @@ inv_open(Oid lobjId, int flags) if (flags & INV_WRITE) { - RelationSetLockForWrite(r); + LockRelation(r, ExclusiveLock); retval->flags = IFS_WRLOCK | IFS_RDLOCK; } else if (flags & INV_READ) { - RelationSetLockForRead(r); + LockRelation(r, ShareLock); retval->flags = IFS_RDLOCK; } @@ -328,7 +328,7 @@ inv_stat(LargeObjectDesc *obj_desc, struct pgstat * stbuf) /* need read lock for stat */ if (!(obj_desc->flags & IFS_RDLOCK)) { - RelationSetLockForRead(obj_desc->heap_r); + LockRelation(obj_desc->heap_r, ShareLock); obj_desc->flags |= IFS_RDLOCK; } @@ -376,7 +376,7 @@ inv_seek(LargeObjectDesc *obj_desc, int offset, int whence) /* need read lock for getsize */ if (!(obj_desc->flags & IFS_RDLOCK)) { - RelationSetLockForRead(obj_desc->heap_r); + LockRelation(obj_desc->heap_r, ShareLock); obj_desc->flags |= IFS_RDLOCK; } offset += _inv_getsize(obj_desc->heap_r, @@ -458,7 +458,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes) /* make sure we obey two-phase locking */ if (!(obj_desc->flags & IFS_RDLOCK)) { - RelationSetLockForRead(obj_desc->heap_r); + LockRelation(obj_desc->heap_r, ShareLock); obj_desc->flags |= IFS_RDLOCK; } @@ -516,7 +516,7 @@ inv_write(LargeObjectDesc *obj_desc, char *buf, int nbytes) if (!(obj_desc->flags & IFS_WRLOCK)) { - RelationSetLockForRead(obj_desc->heap_r); + LockRelation(obj_desc->heap_r, ShareLock); obj_desc->flags |= (IFS_WRLOCK | IFS_RDLOCK); } diff --git a/src/backend/storage/lmgr/Makefile b/src/backend/storage/lmgr/Makefile index 66fc25484a4..88cd9d060c4 100644 --- a/src/backend/storage/lmgr/Makefile +++ b/src/backend/storage/lmgr/Makefile @@ -4,7 +4,7 @@ # Makefile for storage/lmgr # # IDENTIFICATION -# $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Makefile,v 1.8 1998/07/26 04:30:40 scrappy Exp $ +# $Header: /cvsroot/pgsql/src/backend/storage/lmgr/Makefile,v 1.9 1998/12/15 12:46:29 vadim Exp $ # #------------------------------------------------------------------------- @@ -16,7 +16,7 @@ ifdef MULTIBYTE CFLAGS+= $(MBFLAGS) endif -OBJS = lmgr.o lock.o multi.o proc.o single.o +OBJS = lmgr.o lock.o proc.o all: SUBSYS.o diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 13adb8c48f8..307c54e39e1 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.19 1998/09/01 04:31:58 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lmgr.c,v 1.20 1998/12/15 12:46:30 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,85 @@ extern Oid MyDatabaseId; +static MASK LockConflicts[] = { + (int) NULL, + +/* AccessShareLock */ + (1 << AccessExclusiveLock), + +/* RowShareLock */ + (1 << ExclusiveLock) | (1 << AccessExclusiveLock), + +/* RowExclusiveLock */ + (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) | + (1 << AccessExclusiveLock), + +/* ShareLock */ + (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | + (1 << RowExclusiveLock) | (1 << AccessExclusiveLock), + +/* ShareRowExclusiveLock */ + (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | + (1 << ShareLock) | (1 << RowExclusiveLock) | (1 << AccessExclusiveLock), + +/* ExclusiveLock */ + (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) | + (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock), + +/* AccessExclusiveLock */ + (1 << ExclusiveLock) | (1 << ShareRowExclusiveLock) | (1 << ShareLock) | + (1 << RowExclusiveLock) | (1 << RowShareLock) | (1 << AccessExclusiveLock) | + (1 << AccessShareLock), + +/* ExtendLock */ + (1 << ExtendLock) + +}; + +static int LockPrios[] = { + (int) NULL, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 1 +}; + +LOCKMETHOD LockTableId = (LOCKMETHOD) NULL; +LOCKMETHOD LongTermTableId = (LOCKMETHOD) NULL; + +/* + * Create the lock table described by LockConflicts and LockPrios. + */ +LOCKMETHOD +InitLockTable() +{ + int lockmethod; + + lockmethod = LockMethodTableInit("LockTable", + LockConflicts, LockPrios, MAX_LOCKMODES - 1); + LockTableId = lockmethod; + if (!(LockTableId)) + elog(ERROR, "InitLockTable: couldnt initialize lock table"); + +#ifdef USER_LOCKS + /* + * Allocate another tableId for long-term locks + */ + LongTermTableId = LockMethodTableRename(LockTableId); + if (!(LongTermTableId)) + { + elog(ERROR, + "InitLockTable: couldn't rename long-term lock table"); + } +#endif + + return LockTableId; +} + /* * RelationInitLockInfo -- * Initializes the lock information in a relation descriptor. @@ -82,130 +161,49 @@ RelationInitLockInfo(Relation relation) else info->lockRelId.dbId = MyDatabaseId; -#ifdef LowLevelLocking - memset(info->lockHeld, 0, sizeof(info->lockHeld)); -#endif - relation->lockInfo = (Pointer) info; } /* - * RelationSetLockForDescriptorOpen -- - * Sets read locks for a relation descriptor. - */ -#ifdef LOCKDEBUGALL -#define LOCKDEBUGALL_30 \ -elog(DEBUG, "RelationSetLockForDescriptorOpen(%s[%d,%d]) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId) -#else -#define LOCKDEBUGALL_30 -#endif /* LOCKDEBUGALL */ - -void -RelationSetLockForDescriptorOpen(Relation relation) -{ - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - LOCKDEBUGALL_30; - - /* ---------------- - * read lock catalog tuples which compose the relation descriptor - * XXX race condition? XXX For now, do nothing. - * ---------------- - */ -} - -/* ---------------- - * RelationSetLockForRead - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_40 \ -elog(DEBUG, "RelationSetLockForRead(%s[%d,%d]) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId) -#else -#define LOCKDEBUG_40 -#endif /* LOCKDEBUG */ - -/* - * RelationSetLockForRead -- - * Sets relation level read lock. + * LockRelation */ void -RelationSetLockForRead(Relation relation) +LockRelation(Relation relation, LOCKMODE lockmode) { LockInfo lockinfo; + LOCKTAG tag; - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; - LOCKDEBUG_40; - - /* ---------------- - * If we don't have lock info on the reln just go ahead and - * lock it without trying to short circuit the lock manager. - * ---------------- - */ if (!LockInfoIsValid(relation->lockInfo)) - { RelationInitLockInfo(relation); - lockinfo = (LockInfo) relation->lockInfo; - MultiLockReln(lockinfo, READ_LOCK); - return; - } - else - lockinfo = (LockInfo) relation->lockInfo; - MultiLockReln(lockinfo, READ_LOCK); -} + lockinfo = (LockInfo) relation->lockInfo; -/* ---------------- - * RelationUnsetLockForRead - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_50 \ -elog(DEBUG, "RelationUnsetLockForRead(%s[%d,%d]) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId) -#else -#define LOCKDEBUG_50 -#endif /* LOCKDEBUG */ + MemSet(&tag, 0, sizeof(tag)); + tag.relId = lockinfo->lockRelId.relId; + tag.dbId = lockinfo->lockRelId.dbId; + tag.objId.blkno = InvalidBlockNumber; + + LockAcquire(LockTableId, &tag, lockmode); + return; +} /* - * RelationUnsetLockForRead -- - * Unsets relation level read lock. + * UnlockRelation */ void -RelationUnsetLockForRead(Relation relation) +UnlockRelation(Relation relation, LOCKMODE lockmode) { LockInfo lockinfo; + LOCKTAG tag; - /* ---------------- - * sanity check - * ---------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; lockinfo = (LockInfo) relation->lockInfo; - /* ---------------- - * If we don't have lock info on the reln just go ahead and - * release it. - * ---------------- - */ if (!LockInfoIsValid(lockinfo)) { elog(ERROR, @@ -213,84 +211,50 @@ RelationUnsetLockForRead(Relation relation) RelationGetRelationName(relation)); } - MultiReleaseReln(lockinfo, READ_LOCK); -} + MemSet(&tag, 0, sizeof(tag)); + tag.relId = lockinfo->lockRelId.relId; + tag.dbId = lockinfo->lockRelId.dbId; + tag.objId.blkno = InvalidBlockNumber; -/* ---------------- - * RelationSetLockForWrite(relation) - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_60 \ -elog(DEBUG, "RelationSetLockForWrite(%s[%d,%d]) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId) -#else -#define LOCKDEBUG_60 -#endif /* LOCKDEBUG */ + LockRelease(LockTableId, &tag, lockmode); + return; +} /* - * RelationSetLockForWrite -- - * Sets relation level write lock. + * LockPage */ void -RelationSetLockForWrite(Relation relation) +LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) { LockInfo lockinfo; + LOCKTAG tag; - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; - LOCKDEBUG_60; - - /* ---------------- - * If we don't have lock info on the reln just go ahead and - * lock it without trying to short circuit the lock manager. - * ---------------- - */ if (!LockInfoIsValid(relation->lockInfo)) - { RelationInitLockInfo(relation); - lockinfo = (LockInfo) relation->lockInfo; - MultiLockReln(lockinfo, WRITE_LOCK); - return; - } - else - lockinfo = (LockInfo) relation->lockInfo; - MultiLockReln(lockinfo, WRITE_LOCK); -} + lockinfo = (LockInfo) relation->lockInfo; -/* ---------------- - * RelationUnsetLockForWrite - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_70 \ -elog(DEBUG, "RelationUnsetLockForWrite(%s[%d,%d]) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId) -#else -#define LOCKDEBUG_70 -#endif /* LOCKDEBUG */ + MemSet(&tag, 0, sizeof(tag)); + tag.relId = lockinfo->lockRelId.relId; + tag.dbId = lockinfo->lockRelId.dbId; + tag.objId.blkno = blkno; + + LockAcquire(LockTableId, &tag, lockmode); + return; +} /* - * RelationUnsetLockForWrite -- - * Unsets relation level write lock. + * UnlockPage */ void -RelationUnsetLockForWrite(Relation relation) +UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode) { LockInfo lockinfo; + LOCKTAG tag; - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; @@ -303,309 +267,71 @@ RelationUnsetLockForWrite(Relation relation) RelationGetRelationName(relation)); } - MultiReleaseReln(lockinfo, WRITE_LOCK); -} + MemSet(&tag, 0, sizeof(tag)); + tag.relId = lockinfo->lockRelId.relId; + tag.dbId = lockinfo->lockRelId.dbId; + tag.objId.blkno = blkno; -/* ---------------- - * RelationSetLockForReadPage - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_90 \ -elog(DEBUG, "RelationSetLockForReadPage(%s[%d,%d], @%d) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page) -#else -#define LOCKDEBUG_90 -#endif /* LOCKDEBUG */ - -/* ---------------- - * RelationSetLockForWritePage - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_100 \ -elog(DEBUG, "RelationSetLockForWritePage(%s[%d,%d], @%d) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page) -#else -#define LOCKDEBUG_100 -#endif /* LOCKDEBUG */ - -/* - * RelationSetLockForWritePage -- - * Sets write lock on a page. - */ -void -RelationSetLockForWritePage(Relation relation, - ItemPointer itemPointer) -{ - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - /* --------------- - * Make sure lockinfo is initialized - * --------------- - */ - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); - - /* ---------------- - * attempt to set lock - * ---------------- - */ - MultiLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK); + LockRelease(LockTableId, &tag, lockmode); + return; } -/* ---------------- - * RelationUnsetLockForReadPage - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_110 \ -elog(DEBUG, "RelationUnsetLockForReadPage(%s[%d,%d], @%d) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page) -#else -#define LOCKDEBUG_110 -#endif /* LOCKDEBUG */ - -/* ---------------- - * RelationUnsetLockForWritePage - * ---------------- - */ -#ifdef LOCKDEBUG -#define LOCKDEBUG_120 \ -elog(DEBUG, "RelationUnsetLockForWritePage(%s[%d,%d], @%d) called", \ - RelationGetRelationName(relation), lockRelId.dbId, lockRelId.relId, page) -#else -#define LOCKDEBUG_120 -#endif /* LOCKDEBUG */ - -/* - * Set a single level write page lock. Assumes that you already - * have a write intent lock on the relation. - */ void -RelationSetSingleWLockPage(Relation relation, - ItemPointer itemPointer) +XactLockTableInsert(TransactionId xid) { + LOCKTAG tag; - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); + MemSet(&tag, 0, sizeof(tag)); + tag.relId = XactLockTableId; + tag.dbId = InvalidOid; + tag.objId.xid = xid; - SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, !UNLOCK); + LockAcquire(LockTableId, &tag, ExclusiveLock); + return; } -/* - * Unset a single level write page lock - */ void -RelationUnsetSingleWLockPage(Relation relation, - ItemPointer itemPointer) +XactLockTableDelete(TransactionId xid) { + LOCKTAG tag; - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; - if (!LockInfoIsValid(relation->lockInfo)) - elog(ERROR, - "Releasing a lock on %s with invalid lock information", - RelationGetRelationName(relation)); - - SingleLockPage((LockInfo) relation->lockInfo, itemPointer, WRITE_LOCK, UNLOCK); -} - -/* - * Set a single level read page lock. Assumes you already have a read - * intent lock set on the relation. - */ -void -RelationSetSingleRLockPage(Relation relation, - ItemPointer itemPointer) -{ - - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); - - SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, !UNLOCK); -} - -/* - * Unset a single level read page lock. - */ -void -RelationUnsetSingleRLockPage(Relation relation, - ItemPointer itemPointer) -{ - - /* ---------------- - * sanity checks - * ---------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - elog(ERROR, - "Releasing a lock on %s with invalid lock information", - RelationGetRelationName(relation)); - - SingleLockPage((LockInfo) relation->lockInfo, itemPointer, READ_LOCK, UNLOCK); -} - -/* - * Set a read intent lock on a relation. - * - * Usually these are set in a multi-level table when you acquiring a - * page level lock. i.e. To acquire a lock on a page you first acquire - * an intent lock on the entire relation. Acquiring an intent lock along - * allows one to use the single level locking routines later. Good for - * index scans that do a lot of page level locking. - */ -void -RelationSetRIntentLock(Relation relation) -{ - /* ----------------- - * Sanity check - * ----------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); - - SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, !UNLOCK); -} - -/* - * Unset a read intent lock on a relation - */ -void -RelationUnsetRIntentLock(Relation relation) -{ - /* ----------------- - * Sanity check - * ----------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); + MemSet(&tag, 0, sizeof(tag)); + tag.relId = XactLockTableId; + tag.dbId = InvalidOid; + tag.objId.xid = xid; - SingleLockReln((LockInfo) relation->lockInfo, READ_LOCK + INTENT, UNLOCK); + LockRelease(LockTableId, &tag, ExclusiveLock); + return; } -/* - * Set a write intent lock on a relation. For a more complete explanation - * see RelationSetRIntentLock() - */ void -RelationSetWIntentLock(Relation relation) +XactLockTableWait(TransactionId xid) { - /* ----------------- - * Sanity check - * ----------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); + LOCKTAG tag; - SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, !UNLOCK); -} - -/* - * Unset a write intent lock. - */ -void -RelationUnsetWIntentLock(Relation relation) -{ - /* ----------------- - * Sanity check - * ----------------- - */ - Assert(RelationIsValid(relation)); if (LockingDisabled()) return; - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); + MemSet(&tag, 0, sizeof(tag)); + tag.relId = XactLockTableId; + tag.dbId = InvalidOid; + tag.objId.xid = xid; - SingleLockReln((LockInfo) relation->lockInfo, WRITE_LOCK + INTENT, UNLOCK); -} + LockAcquire(LockTableId, &tag, ShareLock); -/* - * Extend locks are used primarily in tertiary storage devices such as - * a WORM disk jukebox. Sometimes need exclusive access to extend a - * file by a block. - */ -#ifdef NOT_USED -void -RelationSetLockForExtend(Relation relation) -{ - /* ----------------- - * Sanity check - * ----------------- + /* + * Transaction was committed/aborted/crashed - + * we have to update pg_log if transaction is still + * marked as running. */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); + if (!TransactionIdDidCommit(xid) && !TransactionIdDidAbort(xid)) + TransactionIdAbort(xid); - MultiLockReln((LockInfo) relation->lockInfo, EXTEND_LOCK); + return; } - -#endif - -#ifdef NOT_USED -void -RelationUnsetLockForExtend(Relation relation) -{ - /* ----------------- - * Sanity check - * ----------------- - */ - Assert(RelationIsValid(relation)); - if (LockingDisabled()) - return; - - if (!LockInfoIsValid(relation->lockInfo)) - RelationInitLockInfo(relation); - - MultiReleaseReln((LockInfo) relation->lockInfo, EXTEND_LOCK); -} - -#endif diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index adc4d1a42ea..7fdd8fec843 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.38 1998/10/08 18:29:57 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.39 1998/12/15 12:46:30 vadim Exp $ * * NOTES * Outside modules can create a lock table and acquire/release @@ -84,7 +84,7 @@ static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode, #define LOCK_PRINT_AUX(where,lock,type) \ TPRINTF(TRACE_ALL, \ - "%s: lock(%x) tbl(%d) rel(%d) db(%d) tid(%d,%d) mask(%x) " \ + "%s: lock(%x) tbl(%d) rel(%d) db(%d) obj(%u) mask(%x) " \ "hold(%d,%d,%d,%d,%d)=%d " \ "act(%d,%d,%d,%d,%d)=%d wait(%d) type(%s)", \ where, \ @@ -92,9 +92,7 @@ static int WaitOnLock(LOCKMETHOD lockmethod, LOCK *lock, LOCKMODE lockmode, lock->tag.lockmethod, \ lock->tag.relId, \ lock->tag.dbId, \ - ((lock->tag.tupleId.ip_blkid.bi_hi<<16)+ \ - lock->tag.tupleId.ip_blkid.bi_lo), \ - lock->tag.tupleId.ip_posid, \ + lock->tag.objId.blkno, \ lock->mask, \ lock->holders[1], \ lock->holders[2], \ @@ -498,10 +496,8 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode) if (is_user_lock) { #ifdef USER_LOCKS_DEBUG - TPRINTF(TRACE_USERLOCKS, "LockAcquire: user lock [%u,%u] %s", - locktag->tupleId.ip_posid, - ((locktag->tupleId.ip_blkid.bi_hi << 16) + - locktag->tupleId.ip_blkid.bi_lo), + TPRINTF(TRACE_USERLOCKS, "LockAcquire: user lock [%u] %s", + locktag->objId.blkno, lock_types[lockmode]); #endif } @@ -550,8 +546,7 @@ LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode) MemSet((char *) lock->holders, 0, sizeof(int) * MAX_LOCKMODES); MemSet((char *) lock->activeHolders, 0, sizeof(int) * MAX_LOCKMODES); ProcQueueInit(&(lock->waitProcs)); - Assert(BlockIdEquals(&(lock->tag.tupleId.ip_blkid), - &(locktag->tupleId.ip_blkid))); + Assert(lock->tag.objId.blkno == locktag->objId.blkno); LOCK_PRINT("LockAcquire: new", lock, lockmode); } else @@ -993,10 +988,8 @@ LockRelease(LOCKMETHOD lockmethod, LOCKTAG *locktag, LOCKMODE lockmode) is_user_lock = (lockmethod == USER_LOCKMETHOD); if (is_user_lock) { - TPRINTF(TRACE_USERLOCKS, "LockRelease: user lock tag [%u,%u] %d", - locktag->tupleId.ip_posid, - ((locktag->tupleId.ip_blkid.bi_hi << 16) + - locktag->tupleId.ip_blkid.bi_lo), + TPRINTF(TRACE_USERLOCKS, "LockRelease: user lock tag [%u] %d", + locktag->objId.blkno, lockmode); } #endif @@ -1336,19 +1329,15 @@ LockReleaseAll(LOCKMETHOD lockmethod, SHM_QUEUE *lockQueue) { /* Should never happen */ elog(NOTICE, - "LockReleaseAll: INVALID PID: [%u,%u] [%d,%d,%d]", - lock->tag.tupleId.ip_posid, - ((lock->tag.tupleId.ip_blkid.bi_hi << 16) + - lock->tag.tupleId.ip_blkid.bi_lo), + "LockReleaseAll: INVALID PID: [%u] [%d,%d,%d]", + lock->tag.objId.blkno, xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid); nleft++; goto next_item; } TPRINTF(TRACE_USERLOCKS, - "LockReleaseAll: releasing user lock [%u,%u] [%d,%d,%d]", - lock->tag.tupleId.ip_posid, - ((lock->tag.tupleId.ip_blkid.bi_hi << 16) + - lock->tag.tupleId.ip_blkid.bi_lo), + "LockReleaseAll: releasing user lock [%u] [%d,%d,%d]", + lock->tag.objId.blkno, xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid); } else @@ -1361,10 +1350,8 @@ LockReleaseAll(LOCKMETHOD lockmethod, SHM_QUEUE *lockQueue) if (xidLook->tag.pid != 0) { TPRINTF(TRACE_LOCKS, - "LockReleaseAll: skiping user lock [%u,%u] [%d,%d,%d]", - lock->tag.tupleId.ip_posid, - ((lock->tag.tupleId.ip_blkid.bi_hi << 16) + - lock->tag.tupleId.ip_blkid.bi_lo), + "LockReleaseAll: skiping user lock [%u] [%d,%d,%d]", + lock->tag.objId.blkno, xidLook->tag.lock, xidLook->tag.pid, xidLook->tag.xid); nleft++; goto next_item; @@ -1649,7 +1636,7 @@ DeadLockCheck(SHM_QUEUE *lockQueue, LOCK *findlock, bool skip_check) */ Assert(skip_check); - Assert(MyProc->prio == 2); + Assert(MyProc->prio >= 2); lockMethodTable = LockMethodTable[1]; xidTable = lockMethodTable->xidHash; @@ -1747,10 +1734,8 @@ LockOwners(LOCKMETHOD lockmethod, LOCKTAG *locktag) is_user_lock = (lockmethod == USER_LOCKMETHOD); if (is_user_lock) { - TPRINTF(TRACE_USERLOCKS, "LockOwners: user lock tag [%u,%u]", - locktag->tupleId.ip_posid, - ((locktag->tupleId.ip_blkid.bi_hi << 16) + - locktag->tupleId.ip_blkid.bi_lo)); + TPRINTF(TRACE_USERLOCKS, "LockOwners: user lock tag [%u]", + locktag->objId.blkno;, } #endif diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c index a9c669bc3aa..6553e73214c 100644 --- a/src/backend/utils/adt/sets.c +++ b/src/backend/utils/adt/sets.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.19 1998/11/27 19:52:23 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.20 1998/12/15 12:46:34 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -109,7 +109,7 @@ SetDefine(char *querystr, char *typename) /* change the pg_proc tuple */ procrel = heap_openr(ProcedureRelationName); - RelationSetLockForWrite(procrel); + LockRelation(procrel, AccessExclusiveLock); tup = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(setoid), @@ -123,7 +123,7 @@ SetDefine(char *querystr, char *typename) repl); setheapoverride(true); - heap_replace(procrel, &tup->t_self, newtup); + heap_replace(procrel, &tup->t_self, newtup, NULL); setheapoverride(false); setoid = newtup->t_data->t_oid; @@ -139,7 +139,7 @@ SetDefine(char *querystr, char *typename) CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup); CatalogCloseIndices(Num_pg_proc_indices, idescs); } - RelationUnsetLockForWrite(procrel); + UnlockRelation(procrel, AccessExclusiveLock); heap_close(procrel); } return setoid; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 492eba6f659..99ee3d2fc54 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.51 1998/11/27 19:52:28 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.52 1998/12/15 12:46:37 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -363,8 +363,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo) * ---------------- */ pg_class_desc = heap_openr(RelationRelationName); - if (!IsInitProcessingMode()) - RelationSetLockForRead(pg_class_desc); pg_class_scan = heap_beginscan(pg_class_desc, 0, SnapshotNow, 1, &key); pg_class_tuple = heap_getnext(pg_class_scan, 0); @@ -388,8 +386,6 @@ scan_pg_rel_seq(RelationBuildDescInfo buildinfo) /* all done */ heap_endscan(pg_class_scan); - if (!IsInitProcessingMode()) - RelationUnsetLockForRead(pg_class_desc); heap_close(pg_class_desc); return return_tuple; @@ -403,7 +399,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo) pg_class_desc = heap_openr(RelationRelationName); if (!IsInitProcessingMode()) - RelationSetLockForRead(pg_class_desc); + LockRelation(pg_class_desc, AccessShareLock); switch (buildinfo.infotype) { @@ -428,7 +424,7 @@ scan_pg_rel_ind(RelationBuildDescInfo buildinfo) /* all done */ if (!IsInitProcessingMode()) - RelationUnsetLockForRead(pg_class_desc); + UnlockRelation(pg_class_desc, AccessShareLock); heap_close(pg_class_desc); return return_tuple; @@ -1126,7 +1122,6 @@ RelationIdCacheGetRelation(Oid relationId) } RelationIncrementReferenceCount(rd); - RelationSetLockForDescriptorOpen(rd); } @@ -1159,7 +1154,6 @@ RelationNameCacheGetRelation(char *relationName) } RelationIncrementReferenceCount(rd); - RelationSetLockForDescriptorOpen(rd); } diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index c88646151a7..f53fdd72720 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.20 1998/11/27 19:52:36 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/time/tqual.c,v 1.21 1998/12/15 12:46:40 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -26,6 +26,9 @@ extern bool PostgresIsInitialized; +SnapshotData SnapshotDirtyData; +Snapshot SnapshotDirty = &SnapshotDirtyData; + /* * XXX Transaction system override hacks start here */ @@ -88,8 +91,9 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) { if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return true; - else - return false; + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + return false; } if (!TransactionIdDidCommit(tuple->t_xmin)) @@ -107,10 +111,18 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) return true; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) - return false; + { + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + return false; /* updated by other */ + } if (TransactionIdIsCurrentTransactionId(tuple->t_xmax)) + { + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; return false; + } if (!TransactionIdDidCommit(tuple->t_xmax)) { @@ -122,6 +134,9 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) /* by here, deleting transaction has committed */ tuple->t_infomask |= HEAP_XMAX_COMMITTED; + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + return false; } @@ -152,13 +167,6 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple) * (Xmax is not committed && the row was deleted by another transaction * Xmax != my-transaction)))) that has not been committed * - * XXX - * CommandId stuff didn't work properly if one used SQL-functions in - * UPDATE/INSERT(fromSELECT)/DELETE scans: SQL-funcs call - * CommandCounterIncrement and made tuples changed/inserted by - * current command visible to command itself (so we had multiple - * update of updated tuples, etc). - vadim 08/29/97 - * * mao says 17 march 1993: the tests in this routine are correct; * if you think they're not, you're wrong, and you should think * about it again. i know, it happened to me. we don't need to @@ -203,6 +211,9 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax)); + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + if (CommandIdGEScanCommandId(tuple->t_cmax)) return true; /* deleted after scan started */ else @@ -229,10 +240,16 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) return true; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) + { + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; return false; + } if (TransactionIdIsCurrentTransactionId(tuple->t_xmax)) { + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; if (CommandIdGEScanCommandId(tuple->t_cmax)) return true; /* deleted after scan started */ else @@ -249,5 +266,173 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple) /* xmax transaction committed */ tuple->t_infomask |= HEAP_XMAX_COMMITTED; + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + return false; } + +int +HeapTupleSatisfiesUpdate(HeapTuple tuple) +{ + HeapTupleHeader th = tuple->t_data; + + if (AMI_OVERRIDE) + return HeapTupleMayBeUpdated; + + if (!(th->t_infomask & HEAP_XMIN_COMMITTED)) + { + if (th->t_infomask & HEAP_XMIN_INVALID) /* xid invalid or aborted */ + return HeapTupleInvisible; + + if (TransactionIdIsCurrentTransactionId(th->t_xmin)) + { + if (CommandIdGEScanCommandId(th->t_cmin) && !heapisoverride()) + return HeapTupleInvisible; /* inserted after scan started */ + + if (th->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ + return HeapTupleMayBeUpdated; + + Assert(TransactionIdIsCurrentTransactionId(th->t_xmax)); + + if (th->t_infomask & HEAP_MARKED_FOR_UPDATE) + return HeapTupleMayBeUpdated; + + if (CommandIdGEScanCommandId(th->t_cmax)) + return HeapTupleSelfUpdated;/* updated after scan started */ + else + return HeapTupleInvisible; /* updated before scan started */ + } + + /* + * This call is VERY expensive - requires a log table lookup. + * Actually, this should be done by query before... + */ + + if (!TransactionIdDidCommit(th->t_xmin)) + { + if (TransactionIdDidAbort(th->t_xmin)) + th->t_infomask |= HEAP_XMIN_INVALID; /* aborted */ + return HeapTupleInvisible; + } + + th->t_infomask |= HEAP_XMIN_COMMITTED; + } + + /* by here, the inserting transaction has committed */ + + if (th->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ + return HeapTupleMayBeUpdated; + + if (th->t_infomask & HEAP_XMAX_COMMITTED) + { + if (th->t_infomask & HEAP_MARKED_FOR_UPDATE) + return HeapTupleMayBeUpdated; + return HeapTupleUpdated; /* updated by other */ + } + + if (TransactionIdIsCurrentTransactionId(th->t_xmax)) + { + if (th->t_infomask & HEAP_MARKED_FOR_UPDATE) + return HeapTupleMayBeUpdated; + if (CommandIdGEScanCommandId(th->t_cmax)) + return HeapTupleSelfUpdated;/* updated after scan started */ + else + return HeapTupleInvisible; /* updated before scan started */ + } + + if (!TransactionIdDidCommit(th->t_xmax)) + { + if (TransactionIdDidAbort(th->t_xmax)) + { + th->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + return HeapTupleMayBeUpdated; + } + /* running xact */ + return HeapTupleBeingUpdated; /* in updation by other */ + } + + /* xmax transaction committed */ + th->t_infomask |= HEAP_XMAX_COMMITTED; + + if (th->t_infomask & HEAP_MARKED_FOR_UPDATE) + return HeapTupleMayBeUpdated; + + return HeapTupleUpdated; /* updated by other */ +} + +bool +HeapTupleSatisfiesDirty(HeapTupleHeader tuple) +{ + SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId; + + if (AMI_OVERRIDE) + return true; + + if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) + { + if (tuple->t_infomask & HEAP_XMIN_INVALID) /* xid invalid or aborted */ + return false; + + if (TransactionIdIsCurrentTransactionId(tuple->t_xmin)) + { + if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ + return true; + + Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax)); + + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + + return false; + } + + if (!TransactionIdDidCommit(tuple->t_xmin)) + { + if (TransactionIdDidAbort(tuple->t_xmin)) + { + tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */ + return false; + } + SnapshotDirty->xmin = tuple->t_xmin; + return true; /* in insertion by other */ + } + + tuple->t_infomask |= HEAP_XMIN_COMMITTED; + } + + /* by here, the inserting transaction has committed */ + + if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ + return true; + + if (tuple->t_infomask & HEAP_XMAX_COMMITTED) + { + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + return false; /* updated by other */ + } + + if (TransactionIdIsCurrentTransactionId(tuple->t_xmax)) + return false; + + if (!TransactionIdDidCommit(tuple->t_xmax)) + { + if (TransactionIdDidAbort(tuple->t_xmax)) + { + tuple->t_infomask |= HEAP_XMAX_INVALID; /* aborted */ + return true; + } + /* running xact */ + SnapshotDirty->xmax = tuple->t_xmax; + return true; /* in updation by other */ + } + + /* xmax transaction committed */ + tuple->t_infomask |= HEAP_XMAX_COMMITTED; + + if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE) + return true; + + return false; /* updated by other */ +} diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 0c756e0beba..e883c7f0a50 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: heapam.h,v 1.39 1998/11/27 19:33:31 vadim Exp $ + * $Id: heapam.h,v 1.40 1998/12/15 12:46:44 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -42,6 +42,7 @@ typedef struct HeapAccessStatisticsData int global_insert; int global_delete; int global_replace; + int global_mark4update; int global_markpos; int global_restrpos; int global_BufferGetRelation; @@ -64,6 +65,7 @@ typedef struct HeapAccessStatisticsData int local_insert; int local_delete; int local_replace; + int local_mark4update; int local_markpos; int local_restrpos; int local_BufferGetRelation; @@ -253,9 +255,10 @@ extern void heap_endscan(HeapScanDesc scan); extern HeapTuple heap_getnext(HeapScanDesc scandesc, int backw); extern void heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tup, Buffer *userbuf); extern Oid heap_insert(Relation relation, HeapTuple tup); -extern int heap_delete(Relation relation, ItemPointer tid); -extern int heap_replace(Relation relation, ItemPointer otid, - HeapTuple tup); +extern int heap_delete(Relation relation, ItemPointer tid, ItemPointer ctid); +extern int heap_replace(Relation relation, ItemPointer otid, HeapTuple tup, + ItemPointer ctid); +extern int heap_mark4update(Relation relation, HeapTuple tup, Buffer *userbuf); extern void heap_markpos(HeapScanDesc scan); extern void heap_restrpos(HeapScanDesc scan); @@ -281,9 +284,4 @@ HeapTuple heap_addheader(uint32 natts, int structlen, char *structure); extern void PrintHeapAccessStatistics(HeapAccessStatistics stats); extern void initam(void); -/* hio.c */ -extern void RelationPutHeapTuple(Relation relation, BlockNumber blockIndex, - HeapTuple tuple); -extern void RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple); - #endif /* HEAPAM_H */ diff --git a/src/include/access/hio.h b/src/include/access/hio.h index caa5380083d..eb8a955b4d0 100644 --- a/src/include/access/hio.h +++ b/src/include/access/hio.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: hio.h,v 1.8 1998/09/01 04:34:13 momjian Exp $ + * $Id: hio.h,v 1.9 1998/12/15 12:46:45 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -17,8 +17,8 @@ #include <utils/rel.h> -extern void RelationPutHeapTuple(Relation relation, BlockNumber blockIndex, - HeapTuple tuple); +extern void RelationPutHeapTuple(Relation relation, Buffer buffer, + HeapTuple tuple); extern void RelationPutHeapTupleAtEnd(Relation relation, HeapTuple tuple); #endif /* HIO_H */ diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 56197048ba0..06c62a9a4d9 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: htup.h,v 1.11 1998/11/27 19:33:31 vadim Exp $ + * $Id: htup.h,v 1.12 1998/12/15 12:46:46 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -116,6 +116,7 @@ typedef HeapTupleData *HeapTuple; #define HEAP_XMIN_INVALID 0x0200 /* t_xmin invalid/aborted */ #define HEAP_XMAX_COMMITTED 0x0400 /* t_xmax committed */ #define HEAP_XMAX_INVALID 0x0800 /* t_xmax invalid/aborted */ +#define HEAP_MARKED_FOR_UPDATE 0x1000 /* marked for UPDATE */ #define HEAP_XACT_MASK 0x0F00 /* */ diff --git a/src/include/access/xact.h b/src/include/access/xact.h index e4c1e0a88ce..6b0aae443f0 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: xact.h,v 1.17 1998/10/08 18:30:23 momjian Exp $ + * $Id: xact.h,v 1.18 1998/12/15 12:46:47 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -38,6 +38,8 @@ typedef struct TransactionStateData #define XACT_REPEATABLE_READ 2 /* not implemented */ #define XACT_SERIALIZED 3 +extern int XactIsoLevel; + /* ---------------- * transaction states * ---------------- diff --git a/src/include/catalog/pg_am.h b/src/include/catalog/pg_am.h index 3106ffa7cc1..bc3b9da1def 100644 --- a/src/include/catalog/pg_am.h +++ b/src/include/catalog/pg_am.h @@ -7,7 +7,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pg_am.h,v 1.9 1998/09/01 04:34:47 momjian Exp $ + * $Id: pg_am.h,v 1.10 1998/12/15 12:46:49 vadim Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -106,6 +106,7 @@ DESCR(""); #define BTREE_AM_OID 403 DATA(insert OID = 405 ( hash PGUID "o" 1 1 hashgettuple hashinsert hashdelete - - - - hashbeginscan hashrescan hashendscan hashmarkpos hashrestrpos - - hashbuild - - )); DESCR(""); +#define HASH_AM_OID 405 DATA(insert OID = 783 ( gist PGUID "o" 100 7 gistgettuple gistinsert gistdelete - - - - gistbeginscan gistrescan gistendscan gistmarkpos gistrestrpos - - gistbuild - - )); DESCR(""); diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index c96e05e3939..c657375241a 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -7,7 +7,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: pg_class.h,v 1.25 1998/09/10 15:32:31 vadim Exp $ + * $Id: pg_class.h,v 1.26 1998/12/15 12:46:50 vadim Exp $ * * NOTES * ``pg_relation'' is being replaced by ``pg_class''. currently @@ -144,6 +144,8 @@ DATA(insert OID = 1264 ( pg_variable 90 PGUID 0 0 0 f t s 2 0 0 0 0 0 f f _n DESCR(""); DATA(insert OID = 1269 ( pg_log 99 PGUID 0 0 0 f t s 1 0 0 0 0 0 f f _null_ )); DESCR(""); +DATA(insert OID = 376 ( pg_xactlock 0 PGUID 0 0 0 f t s 1 0 0 0 0 0 f f _null_ )); +DESCR(""); DATA(insert OID = 1215 ( pg_attrdef 109 PGUID 0 0 0 t t r 4 0 0 0 0 0 f f _null_ )); DESCR(""); DATA(insert OID = 1216 ( pg_relcheck 110 PGUID 0 0 0 t t r 4 0 0 0 0 0 f f _null_ )); @@ -164,6 +166,9 @@ DESCR(""); #define RelOid_pg_relcheck 1216 #define RelOid_pg_trigger 1219 +/* Xact lock pseudo-table */ +#define XactLockTableId 376 + #define RELKIND_INDEX 'i' /* secondary index */ #define RELKIND_LOBJECT 'l' /* large objects */ #define RELKIND_RELATION 'r' /* cataloged heap */ diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h index 3cc0fdcc066..b52c81dc726 100644 --- a/src/include/commands/trigger.h +++ b/src/include/commands/trigger.h @@ -12,6 +12,7 @@ #include "access/tupdesc.h" #include "access/htup.h" #include "nodes/parsenodes.h" +#include "nodes/execnodes.h" #include "utils/rel.h" typedef uint32 TriggerEvent; @@ -65,9 +66,9 @@ extern void RelationRemoveTriggers(Relation rel); extern HeapTuple ExecBRInsertTriggers(Relation rel, HeapTuple tuple); extern void ExecARInsertTriggers(Relation rel, HeapTuple tuple); -extern bool ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid); -extern void ExecARDeleteTriggers(Relation rel, ItemPointer tupleid); -extern HeapTuple ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple); -extern void ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple); +extern bool ExecBRDeleteTriggers(EState *estate, ItemPointer tupleid); +extern void ExecARDeleteTriggers(EState *estate, ItemPointer tupleid); +extern HeapTuple ExecBRUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple tuple); +extern void ExecARUpdateTriggers(EState *estate, ItemPointer tupleid, HeapTuple tuple); #endif /* TRIGGER_H */ diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 61f567b6d3b..383204c3f0f 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: buf_internals.h,v 1.26 1998/09/01 04:38:10 momjian Exp $ + * $Id: buf_internals.h,v 1.27 1998/12/15 12:46:55 vadim Exp $ * * NOTE * If BUFFERPAGE0 is defined, then 0 will be used as a @@ -83,32 +83,6 @@ struct buftag * Dbname, relname, dbid, and relid are enough to determine where * to put the buffer, for all storage managers. */ - -#define PADDED_SBUFDESC_SIZE 128 - -/* DO NOT CHANGE THIS NEXT STRUCTURE: - It is used only to get padding information for the real sbufdesc structure - It should match the sbufdesc structure exactly except for a missing sb_pad -*/ -struct sbufdesc_unpadded -{ - Buffer freeNext; - Buffer freePrev; - SHMEM_OFFSET data; - BufferTag tag; - int buf_id; - BufFlags flags; - unsigned refcount; -#ifdef HAS_TEST_AND_SET - slock_t io_in_progress_lock; -#endif /* HAS_TEST_AND_SET */ - char sb_dbname[NAMEDATALEN]; - - /* NOTE NO PADDING OF THE MEMBER HERE */ - char sb_relname[NAMEDATALEN]; -}; - -/* THE REAL STRUCTURE - the structure above must match it, minus sb_pad */ struct sbufdesc { Buffer freeNext; /* link for freelist chain */ @@ -125,31 +99,25 @@ struct sbufdesc #ifdef HAS_TEST_AND_SET /* can afford a dedicated lock if test-and-set locks are available */ slock_t io_in_progress_lock; + slock_t cntx_lock; /* to lock access to page context */ #endif /* HAS_TEST_AND_SET */ + unsigned r_locks; /* # of shared locks */ + bool ri_lock; /* read-intent lock */ + bool w_lock; /* context exclusively locked */ char sb_dbname[NAMEDATALEN]; /* name of db in which buf belongs */ - - /* - * I padded this structure to a power of 2 (PADDED_SBUFDESC_SIZE) - * because BufferDescriptorGetBuffer is called a billion times and it - * does an C pointer subtraction (i.e., "x - y" -> array index of x - * relative to y, which is calculated using division by struct size). - * Integer ".div" hits you for 35 cycles, as opposed to a 1-cycle - * "sra" ... this hack cut 10% off of the time to create the Wisconsin - * database! It eats up more shared memory, of course, but we're - * (allegedly) going to make some of these types bigger soon anyway... - * -pma 1/2/93 - */ - - /* - * please, don't take the sizeof() this member and use it for - * something important - */ - - char sb_relname[NAMEDATALEN + /* name of reln */ - PADDED_SBUFDESC_SIZE - sizeof(struct sbufdesc_unpadded)]; + char sb_relname[NAMEDATALEN];/* name of reln */ }; +/* + * Buffer lock infos in BufferLocks below. + * We have to free these locks in elog(ERROR)... + */ +#define BL_IO_IN_PROGRESS (1 << 0) /* unimplemented */ +#define BL_R_LOCK (1 << 1) +#define BL_RI_LOCK (1 << 2) +#define BL_W_LOCK (1 << 3) + /* * mao tracing buffer allocation */ @@ -201,6 +169,7 @@ extern BufferDesc *BufferDescriptors; extern BufferBlock BufferBlocks; extern long *PrivateRefCount; extern long *LastRefCount; +extern bits8 *BufferLocks; extern long *CommitInfoNeedsSave; extern SPINLOCK BufMgrLock; diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h index 1948e813ee3..22f66c2295b 100644 --- a/src/include/storage/bufmgr.h +++ b/src/include/storage/bufmgr.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: bufmgr.h,v 1.23 1998/10/08 18:30:43 momjian Exp $ + * $Id: bufmgr.h,v 1.24 1998/12/15 12:46:56 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -73,6 +73,14 @@ extern int ShowPinTrace; #define BUFFER_FLUSH_WRITE 0 /* immediate write */ #define BUFFER_LATE_WRITE 1 /* delayed write: mark as DIRTY */ +/* + * Buffer context lock modes + */ +#define BUFFER_LOCK_UNLOCK 0 +#define BUFFER_LOCK_SHARE 1 +#define BUFFER_LOCK_EXCLUSIVE 2 + + /* * BufferIsValid -- * True iff the refcnt of the local buffer is > 0 @@ -155,4 +163,7 @@ extern void BufferRefCountRestore(int *refcountsave); extern int SetBufferWriteMode(int mode); extern void SetBufferCommitInfoNeedsSave(Buffer buffer); +extern void UnlockBuffers(void); +extern void LockBuffer(Buffer buffer, int mode); + #endif /* !defined(BufMgrIncluded) */ diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index 4733b34bbc8..2163aa79d59 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: ipc.h,v 1.30 1998/09/01 04:38:16 momjian Exp $ + * $Id: ipc.h,v 1.31 1998/12/15 12:46:57 vadim Exp $ * * NOTES * This file is very architecture-specific. This stuff should actually @@ -186,6 +186,8 @@ typedef enum _LockId_ ((key == PrivateIPCKey) ? key : 11 + (key)) #define IPCKeyGetWaitIOSemaphoreKey(key) \ ((key == PrivateIPCKey) ? key : 12 + (key)) +#define IPCKeyGetWaitCLSemaphoreKey(key) \ + ((key == PrivateIPCKey) ? key : 13 + (key)) /* -------------------------- * NOTE: This macro must always give the highest numbered key as every backend diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h index 4082811bcc8..a85ba1e8ff7 100644 --- a/src/include/storage/lmgr.h +++ b/src/include/storage/lmgr.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: lmgr.h,v 1.15 1998/09/01 04:38:23 momjian Exp $ + * $Id: lmgr.h,v 1.16 1998/12/15 12:46:57 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -17,64 +17,48 @@ #include <utils/rel.h> #include <catalog/catname.h> -/* - * This was moved from pladt.h for the new lock manager. Want to obsolete - * all of the old code. - */ +#define AccessShareLock 1 /* SELECT */ +#define RowShareLock 2 /* SELECT FOR UPDATE */ +#define RowExclusiveLock 3 /* INSERT, UPDATE, DELETE */ +#define ShareLock 4 +#define ShareRowExclusiveLock 5 +#define ExclusiveLock 6 +#define AccessExclusiveLock 7 + +#define ExtendLock 8 + +extern LOCKMETHOD LockTableId; + + typedef struct LockRelId { Oid relId; /* a relation identifier */ Oid dbId; /* a database identifier */ } LockRelId; -#ifdef LowLevelLocking typedef struct LockInfoData { LockRelId lockRelId; - bool lockHeld[MAX_LOCKMODES]; /* on table level */ } LockInfoData; -#else -typedef struct LockInfoData -{ - LockRelId lockRelId; -} LockInfoData; - -#endif - typedef LockInfoData *LockInfo; #define LockInfoIsValid(lockinfo) PointerIsValid(lockinfo) +extern LOCKMETHOD InitLockTable(void); extern void RelationInitLockInfo(Relation relation); -extern void RelationSetLockForDescriptorOpen(Relation relation); -extern void RelationSetLockForRead(Relation relation); -extern void RelationUnsetLockForRead(Relation relation); -extern void RelationSetLockForWrite(Relation relation); -extern void RelationUnsetLockForWrite(Relation relation); -/* used in vaccum.c */ -extern void RelationSetLockForWritePage(Relation relation, - ItemPointer itemPointer); +extern void LockRelation(Relation relation, LOCKMODE lockmode); +extern void UnlockRelation(Relation relation, LOCKMODE lockmode); -/* used in nbtpage.c, hashpage.c */ -extern void RelationSetSingleWLockPage(Relation relation, - ItemPointer itemPointer); -extern void RelationUnsetSingleWLockPage(Relation relation, - ItemPointer itemPointer); -extern void RelationSetSingleRLockPage(Relation relation, - ItemPointer itemPointer); -extern void RelationUnsetSingleRLockPage(Relation relation, - ItemPointer itemPointer); -extern void RelationSetRIntentLock(Relation relation); -extern void RelationUnsetRIntentLock(Relation relation); -extern void RelationSetWIntentLock(Relation relation); -extern void RelationUnsetWIntentLock(Relation relation); +/* this is for indices */ +extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); +extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode); -/* single.c */ -extern bool SingleLockReln(LockInfo lockinfo, LOCKMODE lockmode, int action); -extern bool SingleLockPage(LockInfo lockinfo, ItemPointer tidPtr, - LOCKMODE lockmode, int action); +/* and this is for transactions */ +extern void XactLockTableInsert(TransactionId xid); +extern void XactLockTableDelete(TransactionId xid); +extern void XactLockTableWait(TransactionId xid); /* proc.c */ extern void InitProcGlobal(IPCKey key); diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 329aa758a7f..9c803ef8a12 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: lock.h,v 1.19 1998/10/08 18:30:45 momjian Exp $ + * $Id: lock.h,v 1.20 1998/12/15 12:46:58 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -42,11 +42,7 @@ typedef int LOCKMODE; typedef int LOCKMETHOD; /* MAX_LOCKMODES cannot be larger than the bits in MASK */ -#ifdef LowLevelLocking #define MAX_LOCKMODES 9 -#else -#define MAX_LOCKMODES 6 -#endif /* * MAX_LOCK_METHODS corresponds to the number of spin locks allocated in @@ -69,7 +65,11 @@ typedef struct LTAG { Oid relId; Oid dbId; - ItemPointerData tupleId; + union + { + BlockNumber blkno; + TransactionId xid; + } objId; uint16 lockmethod; /* needed by user locks */ } LOCKTAG; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 4a62fac18ab..914d934524f 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: proc.h,v 1.15 1998/09/01 04:38:31 momjian Exp $ + * $Id: proc.h,v 1.16 1998/12/15 12:46:59 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -44,11 +44,9 @@ typedef struct proc TransactionId xid; /* transaction currently being executed by * this proc */ -#ifdef LowLevelLocking TransactionId xmin; /* minimal running XID as it was when we * were starting our xact: vacuum must not * remove tuples deleted by xid >= xmin ! */ -#endif LOCK *waitLock; /* Lock we're sleeping on */ int token; /* info for proc wakeup routines */ diff --git a/src/include/storage/s_lock.h b/src/include/storage/s_lock.h index d47f5ab53b9..aa20a328bdc 100644 --- a/src/include/storage/s_lock.h +++ b/src/include/storage/s_lock.h @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.56 1998/10/31 02:06:08 momjian Exp $ + * $Header: /cvsroot/pgsql/src/include/storage/s_lock.h,v 1.57 1998/12/15 12:46:59 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -68,6 +68,8 @@ #include "storage/ipc.h" +extern void s_lock_sleep(unsigned spin); + #if defined(HAS_TEST_AND_SET) diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 3d2f8531f47..cb15a60ca0d 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -7,7 +7,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: tqual.h,v 1.15 1998/11/27 19:33:35 vadim Exp $ + * $Id: tqual.h,v 1.16 1998/12/15 12:47:01 vadim Exp $ * *------------------------------------------------------------------------- */ @@ -18,17 +18,20 @@ typedef struct SnapshotData { - TransactionId xmin; /* XID < xmin are visible to me */ - TransactionId xmax; /* XID > xmax are invisible to me */ - TransactionId *xip; /* array of xacts in progress */ + TransactionId xmin; /* XID < xmin are visible to me */ + TransactionId xmax; /* XID > xmax are invisible to me */ + TransactionId *xip; /* array of xacts in progress */ } SnapshotData; typedef SnapshotData *Snapshot; -#define IsSnapshotNow(snapshot) ((Snapshot) snapshot == (Snapshot) 0x0) -#define IsSnapshotSelf(snapshot) ((Snapshot) snapshot == (Snapshot) 0x1) #define SnapshotNow ((Snapshot) 0x0) #define SnapshotSelf ((Snapshot) 0x1) +extern Snapshot SnapshotDirty; + +#define IsSnapshotNow(snapshot) ((Snapshot) snapshot == SnapshotNow) +#define IsSnapshotSelf(snapshot) ((Snapshot) snapshot == SnapshotSelf) +#define IsSnapshotDirty(snapshot) ((Snapshot) snapshot == SnapshotDirty) extern TransactionId HeapSpecialTransactionId; extern CommandId HeapSpecialCommandId; @@ -49,7 +52,11 @@ extern CommandId HeapSpecialCommandId; (IsSnapshotSelf(snapshot) || heapisoverride()) ? \ HeapTupleSatisfiesItself((tuple)->t_data) \ : \ - HeapTupleSatisfiesNow((tuple)->t_data) \ + ((IsSnapshotDirty(snapshot)) ? \ + HeapTupleSatisfiesDirty((tuple)->t_data) \ + : \ + HeapTupleSatisfiesNow((tuple)->t_data) \ + ) \ ) \ ) @@ -71,10 +78,18 @@ extern CommandId HeapSpecialCommandId; ) \ ) -extern bool HeapTupleSatisfiesItself(HeapTupleHeader tuple); -extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple); +#define HeapTupleMayBeUpdated 0 +#define HeapTupleInvisible 1 +#define HeapTupleSelfUpdated 2 +#define HeapTupleUpdated 3 +#define HeapTupleBeingUpdated 4 -extern void setheapoverride(bool on); +extern bool HeapTupleSatisfiesItself(HeapTupleHeader tuple); +extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple); +extern bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple); +extern int HeapTupleSatisfiesUpdate(HeapTuple tuple); +extern void setheapoverride(bool on); +extern Snapshot GetSnapshotData(bool serialized); #endif /* TQUAL_H */ -- GitLab