1 /*-------------------------------------------------------------------------
4 * manage scans on hash tables
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.29 2002/09/04 20:31:09 momjian Exp $
14 * Because we can be doing an index scan on a relation while we
15 * update it, we need to avoid missing data that moves around in
16 * the index. The routines and global variables in this file
17 * guarantee that all scans in the local address space stay
18 * correctly positioned. This is all we need to worry about, since
19 * write locking guarantees that no one else will be on the same
20 * page at the same time as we are.
22 * The scheme is to manage a list of active scans in the current
23 * backend. Whenever we add or remove records from an index, we
24 * check the list of active scans to see if any has been affected.
25 * A scan is affected only if it is on the same relation, and the
26 * same page, as the update.
28 *-------------------------------------------------------------------------
33 #include "access/hash.h"
36 typedef struct HashScanListData
38 IndexScanDesc hashsl_scan;
39 struct HashScanListData *hashsl_next;
42 typedef HashScanListData *HashScanList;
44 static HashScanList HashScans = (HashScanList) NULL;
47 static void _hash_scandel(IndexScanDesc scan,
48 BlockNumber blkno, OffsetNumber offno);
52 * AtEOXact_hash() --- clean up hash subsystem at xact abort or commit.
54 * This is here because it needs to touch this module's static var HashScans.
60 * Note: these actions should only be necessary during xact abort; but
61 * they can't hurt during a commit.
65 * Reset the active-scans list to empty. We do not need to free the
66 * list elements, because they're all palloc()'d, so they'll go away
67 * at end of transaction anyway.
71 /* If we were building a hash, we ain't anymore. */
76 * _Hash_regscan() -- register a new scan.
79 _hash_regscan(IndexScanDesc scan)
83 new_el = (HashScanList) palloc(sizeof(HashScanListData));
84 new_el->hashsl_scan = scan;
85 new_el->hashsl_next = HashScans;
90 * _hash_dropscan() -- drop a scan from the scan list
93 _hash_dropscan(IndexScanDesc scan)
98 last = (HashScanList) NULL;
100 chk != (HashScanList) NULL && chk->hashsl_scan != scan;
101 chk = chk->hashsl_next)
104 if (chk == (HashScanList) NULL)
105 elog(ERROR, "hash scan list trashed; can't find 0x%p", (void *) scan);
107 if (last == (HashScanList) NULL)
108 HashScans = chk->hashsl_next;
110 last->hashsl_next = chk->hashsl_next;
116 _hash_adjscans(Relation rel, ItemPointer tid)
121 relid = RelationGetRelid(rel);
122 for (l = HashScans; l != (HashScanList) NULL; l = l->hashsl_next)
124 if (relid == l->hashsl_scan->indexRelation->rd_id)
125 _hash_scandel(l->hashsl_scan, ItemPointerGetBlockNumber(tid),
126 ItemPointerGetOffsetNumber(tid));
131 _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
139 so = (HashScanOpaque) scan->opaque;
140 current = &(scan->currentItemData);
141 mark = &(scan->currentMarkData);
143 if (ItemPointerIsValid(current)
144 && ItemPointerGetBlockNumber(current) == blkno
145 && ItemPointerGetOffsetNumber(current) >= offno)
147 metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
148 buf = so->hashso_curbuf;
149 _hash_step(scan, &buf, BackwardScanDirection, metabuf);
152 if (ItemPointerIsValid(mark)
153 && ItemPointerGetBlockNumber(mark) == blkno
154 && ItemPointerGetOffsetNumber(mark) >= offno)
157 * The idea here is to exchange the current and mark positions,
158 * then step backwards (affecting current), then exchange again.
160 ItemPointerData tmpitem;
166 tmpbuf = so->hashso_mrkbuf;
167 so->hashso_mrkbuf = so->hashso_curbuf;
168 so->hashso_curbuf = tmpbuf;
170 metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
171 buf = so->hashso_curbuf;
172 _hash_step(scan, &buf, BackwardScanDirection, metabuf);
177 tmpbuf = so->hashso_mrkbuf;
178 so->hashso_mrkbuf = so->hashso_curbuf;
179 so->hashso_curbuf = tmpbuf;