1 /*-------------------------------------------------------------------------
4 * manage scans on hash tables
6 * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/hash/hashscan.c
13 *-------------------------------------------------------------------------
18 #include "access/hash.h"
19 #include "access/relscan.h"
20 #include "utils/memutils.h"
21 #include "utils/rel.h"
22 #include "utils/resowner.h"
26 * We track all of a backend's active scans on hash indexes using a list
27 * of HashScanListData structs, which are allocated in TopMemoryContext.
28 * It's okay to use a long-lived context because we rely on the ResourceOwner
29 * mechanism to clean up unused entries after transaction or subtransaction
30 * abort. We can't safely keep the entries in the executor's per-query
31 * context, because that might be already freed before we get a chance to
32 * clean up the list. (XXX seems like there should be a better way to
35 typedef struct HashScanListData
37 IndexScanDesc hashsl_scan;
38 ResourceOwner hashsl_owner;
39 struct HashScanListData *hashsl_next;
42 typedef HashScanListData *HashScanList;
44 static HashScanList HashScans = NULL;
48 * ReleaseResources_hash() --- clean up hash subsystem resources.
50 * This is here because it needs to touch this module's static var HashScans.
53 ReleaseResources_hash(void)
60 * Release all HashScanList items belonging to the current ResourceOwner.
61 * Note that we do not release the underlying IndexScanDesc; that's in
62 * executor memory and will go away on its own (in fact quite possibly has
63 * gone away already, so we mustn't try to touch it here).
65 * Note: this should be a no-op during normal query shutdown. However, in
66 * an abort situation ExecutorEnd is not called and so there may be open
67 * index scans to clean up.
71 for (l = HashScans; l != NULL; l = next)
73 next = l->hashsl_next;
74 if (l->hashsl_owner == CurrentResourceOwner)
79 prev->hashsl_next = next;
82 /* prev does not change */
90 * _hash_regscan() -- register a new scan.
93 _hash_regscan(IndexScanDesc scan)
97 new_el = (HashScanList) MemoryContextAlloc(TopMemoryContext,
98 sizeof(HashScanListData));
99 new_el->hashsl_scan = scan;
100 new_el->hashsl_owner = CurrentResourceOwner;
101 new_el->hashsl_next = HashScans;
106 * _hash_dropscan() -- drop a scan from the scan list
109 _hash_dropscan(IndexScanDesc scan)
115 for (chk = HashScans;
116 chk != NULL && chk->hashsl_scan != scan;
117 chk = chk->hashsl_next)
121 elog(ERROR, "hash scan list trashed; cannot find 0x%p", (void *) scan);
124 HashScans = chk->hashsl_next;
126 last->hashsl_next = chk->hashsl_next;
132 * Is there an active scan in this bucket?
135 _hash_has_active_scan(Relation rel, Bucket bucket)
137 Oid relid = RelationGetRelid(rel);
140 for (l = HashScans; l != NULL; l = l->hashsl_next)
142 if (relid == l->hashsl_scan->indexRelation->rd_id)
144 HashScanOpaque so = (HashScanOpaque) l->hashsl_scan->opaque;
146 if (so->hashso_bucket_valid &&
147 so->hashso_bucket == bucket)