aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/nbtree/nbtscan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/nbtree/nbtscan.c')
-rw-r--r--src/backend/access/nbtree/nbtscan.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/src/backend/access/nbtree/nbtscan.c b/src/backend/access/nbtree/nbtscan.c
new file mode 100644
index 00000000000..62a029bc06f
--- /dev/null
+++ b/src/backend/access/nbtree/nbtscan.c
@@ -0,0 +1,164 @@
+/*-------------------------------------------------------------------------
+ *
+ * btscan.c--
+ * manage scans on btrees.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/access/nbtree/Attic/nbtscan.c,v 1.1.1.1 1996/07/09 06:21:12 scrappy Exp $
+ *
+ *
+ * NOTES
+ * 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 "postgres.h"
+
+#include "storage/bufmgr.h"
+#include "storage/bufpage.h"
+
+#include "utils/elog.h"
+#include "utils/palloc.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"
+
+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(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(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(Relation rel, ItemPointer tid)
+{
+ BTScanList l;
+ Oid relid;
+
+ 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));
+ }
+}
+
+void
+_bt_scandel(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) >= offno) {
+ _bt_step(scan, &buf, BackwardScanDirection);
+ so->btso_curbuf = buf;
+ }
+
+ current = &(scan->currentMarkData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= 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(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
+{
+ ItemPointer current;
+
+ current = &(scan->currentItemData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ return (true);
+
+ current = &(scan->currentMarkData);
+ if (ItemPointerIsValid(current)
+ && ItemPointerGetBlockNumber(current) == blkno
+ && ItemPointerGetOffsetNumber(current) >= offno)
+ return (true);
+
+ return (false);
+}