head 1.4; access; symbols; locks; strict; comment @ * @; 1.4 date 92.03.01.13.13.47; author mao; state Exp; branches; next 1.3; 1.3 date 91.05.05.19.45.03; author mao; state Exp; branches; next 1.2; 1.2 date 91.04.28.15.16.12; author mao; state Exp; branches; next 1.1; 1.1 date 91.04.27.12.10.01; author mao; state Exp; branches; next ; desc @scan synchronization code -- if we are doing a scan on a tree we're also modifying, we need to be sure we don't lose our place in the scan. @ 1.4 log @hack to fix memory management botch in inversion file system code -- turn off frees of small items in scan for testing. @ text @/* * btscan.c -- manage scans on btrees. * * Because we can be doing an index scan on a relation while we update * it, we need to avoid missing data that moves around in the index. * The routines and global variables in this file guarantee that all * scans in the local address space stay correctly positioned. This * is all we need to worry about, since write locking guarantees that * no one else will be on the same page at the same time as we are. * * The scheme is to manage a list of active scans in the current backend. * Whenever we add or remove records from an index, or whenever we * split a leaf page, we check the list of active scans to see if any * has been affected. A scan is affected only if it is on the same * relation, and the same page, as the update. */ #include "tmp/c.h" #include "tmp/postgres.h" #include "storage/bufmgr.h" #include "storage/bufpage.h" #include "storage/page.h" #include "utils/log.h" #include "utils/rel.h" #include "utils/excid.h" #include "access/heapam.h" #include "access/genam.h" #include "access/sdir.h" #include "access/nbtree.h" RcsId("$Header: RCS/nbtscan.c,v 1.3 91/05/05 19:45:03 mao Exp Locker: mao $"); typedef struct BTScanListData { IndexScanDesc btsl_scan; struct BTScanListData *btsl_next; } BTScanListData; typedef BTScanListData *BTScanList; static BTScanList BTScans = (BTScanList) NULL; /* * _bt_regscan() -- register a new scan. */ void _bt_regscan(scan) IndexScanDesc scan; { BTScanList new_el; new_el = (BTScanList) palloc(sizeof(BTScanListData)); new_el->btsl_scan = scan; new_el->btsl_next = BTScans; BTScans = new_el; } /* * _bt_dropscan() -- drop a scan from the scan list */ void _bt_dropscan(scan) IndexScanDesc scan; { BTScanList chk, last; last = (BTScanList) NULL; for (chk = BTScans; chk != (BTScanList) NULL && chk->btsl_scan != scan; chk = chk->btsl_next) { last = chk; } if (chk == (BTScanList) NULL) elog(WARN, "btree scan list trashed; can't find 0x%lx", scan); if (last == (BTScanList) NULL) BTScans = chk->btsl_next; else last->btsl_next = chk->btsl_next; #ifdef PERFECT_MEM pfree (chk); #endif /* PERFECT_MEM */ } void _bt_adjscans(rel, tid) Relation rel; ItemPointer tid; { BTScanList l; ObjectId relid, chkrelid; relid = rel->rd_id; for (l = BTScans; l != (BTScanList) NULL; l = l->btsl_next) { if (relid == l->btsl_scan->relation->rd_id) _bt_scandel(l->btsl_scan, ItemPointerGetBlockNumber(tid), ItemPointerGetOffsetNumber(tid, 0)); } } void _bt_scandel(scan, blkno, offno) IndexScanDesc scan; BlockNumber blkno; OffsetNumber offno; { ItemPointer current; Buffer buf; BTScanOpaque so; if (!_bt_scantouched(scan, blkno, offno)) return; so = (BTScanOpaque) scan->opaque; buf = so->btso_curbuf; current = &(scan->currentItemData); if (ItemPointerIsValid(current) && ItemPointerGetBlockNumber(current) == blkno && ItemPointerGetOffsetNumber(current, 0) >= offno) { _bt_step(scan, &buf, BackwardScanDirection); so->btso_curbuf = buf; } current = &(scan->currentMarkData); if (ItemPointerIsValid(current) && ItemPointerGetBlockNumber(current) == blkno && ItemPointerGetOffsetNumber(current, 0) >= offno) { ItemPointerData tmp; tmp = *current; *current = scan->currentItemData; scan->currentItemData = tmp; _bt_step(scan, &buf, BackwardScanDirection); so->btso_mrkbuf = buf; tmp = *current; *current = scan->currentItemData; scan->currentItemData = tmp; } } bool _bt_scantouched(scan, blkno, offno) IndexScanDesc scan; BlockNumber blkno; OffsetNumber offno; { ItemPointer current; current = &(scan->currentItemData); if (ItemPointerIsValid(current) && ItemPointerGetBlockNumber(current) == blkno && ItemPointerGetOffsetNumber(current, 0) >= offno) return (true); current = &(scan->currentMarkData); if (ItemPointerIsValid(current) && ItemPointerGetBlockNumber(current) == blkno && ItemPointerGetOffsetNumber(current, 0) >= offno) return (true); return (false); } @ 1.3 log @fix deletion, scan management code due to vacuum cleaner testing @ text @d34 1 a34 1 RcsId("$Header: RCS/nbtscan.c,v 1.2 91/04/28 15:16:12 mao Exp Locker: mao $"); d86 1 d88 1 @ 1.2 log @get rid of BT_NONE accesses to pages; cache current, marked buffers for scans to avoid unnecessary semop() calls; fix buffer leak reported by wei (equality joins that failed used to not unpin buffers). @ text @d34 1 a34 1 RcsId("$Header: RCS/nbtscan.c,v 1.1 91/04/27 12:10:01 mao Exp Locker: mao $"); d106 1 a106 1 _bt_scandel(scan, blkno, offind) d109 1 a109 1 OffsetIndex offind; a112 2 Page page; OffsetIndex maxoff; d115 1 a115 1 if (!_bt_scantouched(scan, blkno, offind)) a119 2 page = BufferGetPage(buf, 0); maxoff = PageGetMaxOffsetIndex(page); d124 1 a124 1 && ItemPointerGetOffsetNumber(current, 0) >= offind + 1) { d132 1 a132 1 && ItemPointerGetOffsetNumber(current, 0) >= offind + 1) { d146 1 a146 1 _bt_scantouched(scan, blkno, offind) d149 1 a149 1 OffsetIndex offind; d156 1 a156 1 && ItemPointerGetOffsetNumber(current, 0) >= offind + 1) d162 1 a162 1 && ItemPointerGetOffsetNumber(current, 0) >= offind + 1) @ 1.1 log @Initial revision @ text @d34 1 a34 1 RcsId("$Header$"); d43 1 a43 1 BTScanList BTScans = (BTScanList) NULL; d115 1 d120 2 a121 1 buf = _bt_getbuf(scan->relation, blkno, BT_NONE); d129 2 a130 1 _bt_step(scan, BackwardScanDirection); d141 2 a142 1 _bt_step(scan, BackwardScanDirection); a146 1 _bt_relbuf(scan->relation, buf, BT_NONE); @