1 : /*-------------------------------------------------------------------------
2 : *
3 : * hashscan.c
4 : * manage scans on hash tables
5 : *
6 : * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.42 2007/02/01 19:10:25 momjian Exp $
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "postgres.h"
17 :
18 : #include "access/hash.h"
19 : #include "utils/resowner.h"
20 :
21 :
22 : typedef struct HashScanListData
23 : {
24 : IndexScanDesc hashsl_scan;
25 : ResourceOwner hashsl_owner;
26 : struct HashScanListData *hashsl_next;
27 : } HashScanListData;
28 :
29 : typedef HashScanListData *HashScanList;
30 :
31 : static HashScanList HashScans = NULL;
32 :
33 :
34 : /*
35 : * ReleaseResources_hash() --- clean up hash subsystem resources.
36 : *
37 : * This is here because it needs to touch this module's static var HashScans.
38 : */
39 : void
40 : ReleaseResources_hash(void)
41 23537 : {
42 : HashScanList l;
43 : HashScanList prev;
44 : HashScanList next;
45 :
46 : /*
47 : * Note: this should be a no-op during normal query shutdown. However, in
48 : * an abort situation ExecutorEnd is not called and so there may be open
49 : * index scans to clean up.
50 : */
51 23537 : prev = NULL;
52 :
53 23537 : for (l = HashScans; l != NULL; l = next)
54 : {
55 0 : next = l->hashsl_next;
56 0 : if (l->hashsl_owner == CurrentResourceOwner)
57 : {
58 0 : if (prev == NULL)
59 0 : HashScans = next;
60 : else
61 0 : prev->hashsl_next = next;
62 :
63 0 : pfree(l);
64 : /* prev does not change */
65 : }
66 : else
67 0 : prev = l;
68 : }
69 23537 : }
70 :
71 : /*
72 : * _Hash_regscan() -- register a new scan.
73 : */
74 : void
75 : _hash_regscan(IndexScanDesc scan)
76 21 : {
77 : HashScanList new_el;
78 :
79 21 : new_el = (HashScanList) palloc(sizeof(HashScanListData));
80 21 : new_el->hashsl_scan = scan;
81 21 : new_el->hashsl_owner = CurrentResourceOwner;
82 21 : new_el->hashsl_next = HashScans;
83 21 : HashScans = new_el;
84 21 : }
85 :
86 : /*
87 : * _hash_dropscan() -- drop a scan from the scan list
88 : */
89 : void
90 : _hash_dropscan(IndexScanDesc scan)
91 21 : {
92 : HashScanList chk,
93 : last;
94 :
95 21 : last = NULL;
96 21 : for (chk = HashScans;
97 42 : chk != NULL && chk->hashsl_scan != scan;
98 0 : chk = chk->hashsl_next)
99 0 : last = chk;
100 :
101 21 : if (chk == NULL)
102 0 : elog(ERROR, "hash scan list trashed; cannot find 0x%p", (void *) scan);
103 :
104 21 : if (last == NULL)
105 21 : HashScans = chk->hashsl_next;
106 : else
107 0 : last->hashsl_next = chk->hashsl_next;
108 :
109 21 : pfree(chk);
110 21 : }
111 :
112 : /*
113 : * Is there an active scan in this bucket?
114 : */
115 : bool
116 : _hash_has_active_scan(Relation rel, Bucket bucket)
117 500 : {
118 500 : Oid relid = RelationGetRelid(rel);
119 : HashScanList l;
120 :
121 500 : for (l = HashScans; l != NULL; l = l->hashsl_next)
122 : {
123 0 : if (relid == l->hashsl_scan->indexRelation->rd_id)
124 : {
125 0 : HashScanOpaque so = (HashScanOpaque) l->hashsl_scan->opaque;
126 :
127 0 : if (so->hashso_bucket_valid &&
128 : so->hashso_bucket == bucket)
129 0 : return true;
130 : }
131 : }
132 :
133 500 : return false;
134 : }
|