OSDN Git Service

pgindent run.
[pg-rex/syncrep.git] / src / backend / access / hash / hashscan.c
1 /*-------------------------------------------------------------------------
2  *
3  * hashscan.c
4  *        manage scans on hash tables
5  *
6  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.29 2002/09/04 20:31:09 momjian Exp $
12  *
13  * NOTES
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.
21  *
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.
27  *
28  *-------------------------------------------------------------------------
29  */
30
31 #include "postgres.h"
32
33 #include "access/hash.h"
34
35
36 typedef struct HashScanListData
37 {
38         IndexScanDesc hashsl_scan;
39         struct HashScanListData *hashsl_next;
40 } HashScanListData;
41
42 typedef HashScanListData *HashScanList;
43
44 static HashScanList HashScans = (HashScanList) NULL;
45
46
47 static void _hash_scandel(IndexScanDesc scan,
48                           BlockNumber blkno, OffsetNumber offno);
49
50
51 /*
52  * AtEOXact_hash() --- clean up hash subsystem at xact abort or commit.
53  *
54  * This is here because it needs to touch this module's static var HashScans.
55  */
56 void
57 AtEOXact_hash(void)
58 {
59         /*
60          * Note: these actions should only be necessary during xact abort; but
61          * they can't hurt during a commit.
62          */
63
64         /*
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.
68          */
69         HashScans = NULL;
70
71         /* If we were building a hash, we ain't anymore. */
72         BuildingHash = false;
73 }
74
75 /*
76  *      _Hash_regscan() -- register a new scan.
77  */
78 void
79 _hash_regscan(IndexScanDesc scan)
80 {
81         HashScanList new_el;
82
83         new_el = (HashScanList) palloc(sizeof(HashScanListData));
84         new_el->hashsl_scan = scan;
85         new_el->hashsl_next = HashScans;
86         HashScans = new_el;
87 }
88
89 /*
90  *      _hash_dropscan() -- drop a scan from the scan list
91  */
92 void
93 _hash_dropscan(IndexScanDesc scan)
94 {
95         HashScanList chk,
96                                 last;
97
98         last = (HashScanList) NULL;
99         for (chk = HashScans;
100                  chk != (HashScanList) NULL && chk->hashsl_scan != scan;
101                  chk = chk->hashsl_next)
102                 last = chk;
103
104         if (chk == (HashScanList) NULL)
105                 elog(ERROR, "hash scan list trashed; can't find 0x%p", (void *) scan);
106
107         if (last == (HashScanList) NULL)
108                 HashScans = chk->hashsl_next;
109         else
110                 last->hashsl_next = chk->hashsl_next;
111
112         pfree(chk);
113 }
114
115 void
116 _hash_adjscans(Relation rel, ItemPointer tid)
117 {
118         HashScanList l;
119         Oid                     relid;
120
121         relid = RelationGetRelid(rel);
122         for (l = HashScans; l != (HashScanList) NULL; l = l->hashsl_next)
123         {
124                 if (relid == l->hashsl_scan->indexRelation->rd_id)
125                         _hash_scandel(l->hashsl_scan, ItemPointerGetBlockNumber(tid),
126                                                   ItemPointerGetOffsetNumber(tid));
127         }
128 }
129
130 static void
131 _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
132 {
133         ItemPointer current;
134         ItemPointer mark;
135         Buffer          buf;
136         Buffer          metabuf;
137         HashScanOpaque so;
138
139         so = (HashScanOpaque) scan->opaque;
140         current = &(scan->currentItemData);
141         mark = &(scan->currentMarkData);
142
143         if (ItemPointerIsValid(current)
144                 && ItemPointerGetBlockNumber(current) == blkno
145                 && ItemPointerGetOffsetNumber(current) >= offno)
146         {
147                 metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
148                 buf = so->hashso_curbuf;
149                 _hash_step(scan, &buf, BackwardScanDirection, metabuf);
150         }
151
152         if (ItemPointerIsValid(mark)
153                 && ItemPointerGetBlockNumber(mark) == blkno
154                 && ItemPointerGetOffsetNumber(mark) >= offno)
155         {
156                 /*
157                  * The idea here is to exchange the current and mark positions,
158                  * then step backwards (affecting current), then exchange again.
159                  */
160                 ItemPointerData tmpitem;
161                 Buffer          tmpbuf;
162
163                 tmpitem = *mark;
164                 *mark = *current;
165                 *current = tmpitem;
166                 tmpbuf = so->hashso_mrkbuf;
167                 so->hashso_mrkbuf = so->hashso_curbuf;
168                 so->hashso_curbuf = tmpbuf;
169
170                 metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
171                 buf = so->hashso_curbuf;
172                 _hash_step(scan, &buf, BackwardScanDirection, metabuf);
173
174                 tmpitem = *mark;
175                 *mark = *current;
176                 *current = tmpitem;
177                 tmpbuf = so->hashso_mrkbuf;
178                 so->hashso_mrkbuf = so->hashso_curbuf;
179                 so->hashso_curbuf = tmpbuf;
180         }
181 }