]> granicus.if.org Git - postgresql/blob - src/backend/access/hash/hashscan.c
c4cce0e70d98435d643ef8eef3e25eea8fb24194
[postgresql] / src / backend / access / hash / hashscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * hashscan.c--
4  *    manage scans on hash tables
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *    $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.1.1.1 1996/07/09 06:21:10 scrappy Exp $
11  *
12  * NOTES
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.
20  *
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.
26  *
27  *-------------------------------------------------------------------------
28  */
29 #include "postgres.h"
30
31 #include "storage/bufmgr.h"
32 #include "storage/bufpage.h"
33
34 #include "utils/elog.h"
35 #include "utils/palloc.h"
36 #include "utils/rel.h"
37 #include "utils/excid.h"
38
39 #include "access/heapam.h"
40 #include "access/genam.h"
41 #include "access/sdir.h"
42 #include "access/hash.h"
43
44 static void _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
45 static bool _hash_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
46
47 typedef struct HashScanListData {
48     IndexScanDesc               hashsl_scan;
49     struct HashScanListData     *hashsl_next;
50 } HashScanListData;
51
52 typedef HashScanListData        *HashScanList;
53
54 static HashScanList     HashScans = (HashScanList) NULL;
55
56 /*
57  *  _Hash_regscan() -- register a new scan.
58  */
59 void
60 _hash_regscan(IndexScanDesc scan)
61 {
62     HashScanList new_el;
63     
64     new_el = (HashScanList) palloc(sizeof(HashScanListData));
65     new_el->hashsl_scan = scan;
66     new_el->hashsl_next = HashScans;
67     HashScans = new_el;
68 }
69
70 /*
71  *  _hash_dropscan() -- drop a scan from the scan list
72  */
73 void
74 _hash_dropscan(IndexScanDesc scan)
75 {
76     HashScanList chk, last;
77     
78     last = (HashScanList) NULL;
79     for (chk = HashScans;
80          chk != (HashScanList) NULL && chk->hashsl_scan != scan;
81          chk = chk->hashsl_next) {
82         last = chk;
83     }
84     
85     if (chk == (HashScanList) NULL)
86         elog(WARN, "hash scan list trashed; can't find 0x%lx", scan);
87     
88     if (last == (HashScanList) NULL)
89         HashScans = chk->hashsl_next;
90     else
91         last->hashsl_next = chk->hashsl_next;
92     
93 #ifdef PERFECT_MEM
94     pfree (chk);
95 #endif /* PERFECT_MEM */
96 }
97
98 void
99 _hash_adjscans(Relation rel, ItemPointer tid)
100 {
101     HashScanList l;
102     Oid relid;
103     
104     relid = rel->rd_id;
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));
109     }
110 }
111
112 static void
113 _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
114 {
115     ItemPointer current;
116     Buffer buf;
117     Buffer metabuf;
118     HashScanOpaque so;
119     
120     if (!_hash_scantouched(scan, blkno, offno))
121         return;
122     
123     metabuf = _hash_getbuf(scan->relation, HASH_METAPAGE, HASH_READ);
124     
125     so = (HashScanOpaque) scan->opaque;
126     buf = so->hashso_curbuf;
127     
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;
134     }
135     
136     current = &(scan->currentMarkData);
137     if (ItemPointerIsValid(current)
138         && ItemPointerGetBlockNumber(current) == blkno
139         && ItemPointerGetOffsetNumber(current) >= offno) {
140         ItemPointerData tmp;
141         tmp = *current;
142         *current = scan->currentItemData;
143         scan->currentItemData = tmp;
144         _hash_step(scan, &buf, BackwardScanDirection, metabuf);
145         so->hashso_mrkbuf = buf;
146         tmp = *current;
147         *current = scan->currentItemData;
148         scan->currentItemData = tmp;
149     }
150 }
151
152 static bool
153 _hash_scantouched(IndexScanDesc scan,
154                   BlockNumber blkno,
155                   OffsetNumber offno)
156 {
157     ItemPointer current;
158     
159     current = &(scan->currentItemData);
160     if (ItemPointerIsValid(current)
161         && ItemPointerGetBlockNumber(current) == blkno
162         && ItemPointerGetOffsetNumber(current) >= offno)
163         return (true);
164     
165     current = &(scan->currentMarkData);
166     if (ItemPointerIsValid(current)
167         && ItemPointerGetBlockNumber(current) == blkno
168         && ItemPointerGetOffsetNumber(current) >= offno)
169         return (true);
170     
171     return (false);
172 }