1 /*-------------------------------------------------------------------------
4 * manage scans on hash tables
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.1.1.1 1996/07/09 06:21:10 scrappy Exp $
13 * Because we can be doing an index scan on a relation while we
14 * update it, we need to avoid missing data that moves around in
15 * the index. The routines and global variables in this file
16 * guarantee that all scans in the local address space stay
17 * correctly positioned. This is all we need to worry about, since
18 * write locking guarantees that no one else will be on the same
19 * page at the same time as we are.
21 * The scheme is to manage a list of active scans in the current
22 * backend. Whenever we add or remove records from an index, we
23 * check the list of active scans to see if any has been affected.
24 * A scan is affected only if it is on the same relation, and the
25 * same page, as the update.
27 *-------------------------------------------------------------------------
31 #include "storage/bufmgr.h"
32 #include "storage/bufpage.h"
34 #include "utils/elog.h"
35 #include "utils/palloc.h"
36 #include "utils/rel.h"
37 #include "utils/excid.h"
39 #include "access/heapam.h"
40 #include "access/genam.h"
41 #include "access/sdir.h"
42 #include "access/hash.h"
44 static void _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
45 static bool _hash_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
47 typedef struct HashScanListData {
48 IndexScanDesc hashsl_scan;
49 struct HashScanListData *hashsl_next;
52 typedef HashScanListData *HashScanList;
54 static HashScanList HashScans = (HashScanList) NULL;
57 * _Hash_regscan() -- register a new scan.
60 _hash_regscan(IndexScanDesc scan)
64 new_el = (HashScanList) palloc(sizeof(HashScanListData));
65 new_el->hashsl_scan = scan;
66 new_el->hashsl_next = HashScans;
71 * _hash_dropscan() -- drop a scan from the scan list
74 _hash_dropscan(IndexScanDesc scan)
76 HashScanList chk, last;
78 last = (HashScanList) NULL;
80 chk != (HashScanList) NULL && chk->hashsl_scan != scan;
81 chk = chk->hashsl_next) {
85 if (chk == (HashScanList) NULL)
86 elog(WARN, "hash scan list trashed; can't find 0x%lx", scan);
88 if (last == (HashScanList) NULL)
89 HashScans = chk->hashsl_next;
91 last->hashsl_next = chk->hashsl_next;
95 #endif /* PERFECT_MEM */
99 _hash_adjscans(Relation rel, ItemPointer tid)
105 for (l = HashScans; l != (HashScanList) NULL; l = l->hashsl_next) {
106 if (relid == l->hashsl_scan->relation->rd_id)
107 _hash_scandel(l->hashsl_scan, ItemPointerGetBlockNumber(tid),
108 ItemPointerGetOffsetNumber(tid));
113 _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
120 if (!_hash_scantouched(scan, blkno, offno))
123 metabuf = _hash_getbuf(scan->relation, HASH_METAPAGE, HASH_READ);
125 so = (HashScanOpaque) scan->opaque;
126 buf = so->hashso_curbuf;
128 current = &(scan->currentItemData);
129 if (ItemPointerIsValid(current)
130 && ItemPointerGetBlockNumber(current) == blkno
131 && ItemPointerGetOffsetNumber(current) >= offno) {
132 _hash_step(scan, &buf, BackwardScanDirection, metabuf);
133 so->hashso_curbuf = buf;
136 current = &(scan->currentMarkData);
137 if (ItemPointerIsValid(current)
138 && ItemPointerGetBlockNumber(current) == blkno
139 && ItemPointerGetOffsetNumber(current) >= offno) {
142 *current = scan->currentItemData;
143 scan->currentItemData = tmp;
144 _hash_step(scan, &buf, BackwardScanDirection, metabuf);
145 so->hashso_mrkbuf = buf;
147 *current = scan->currentItemData;
148 scan->currentItemData = tmp;
153 _hash_scantouched(IndexScanDesc scan,
159 current = &(scan->currentItemData);
160 if (ItemPointerIsValid(current)
161 && ItemPointerGetBlockNumber(current) == blkno
162 && ItemPointerGetOffsetNumber(current) >= offno)
165 current = &(scan->currentMarkData);
166 if (ItemPointerIsValid(current)
167 && ItemPointerGetBlockNumber(current) == blkno
168 && ItemPointerGetOffsetNumber(current) >= offno)