00001 /*------------------------------------------------------------------------- 00002 * 00003 * hashscan.c 00004 * manage scans on hash tables 00005 * 00006 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group 00007 * Portions Copyright (c) 1994, Regents of the University of California 00008 * 00009 * 00010 * IDENTIFICATION 00011 * src/backend/access/hash/hashscan.c 00012 * 00013 *------------------------------------------------------------------------- 00014 */ 00015 00016 #include "postgres.h" 00017 00018 #include "access/hash.h" 00019 #include "access/relscan.h" 00020 #include "utils/memutils.h" 00021 #include "utils/rel.h" 00022 #include "utils/resowner.h" 00023 00024 00025 /* 00026 * We track all of a backend's active scans on hash indexes using a list 00027 * of HashScanListData structs, which are allocated in TopMemoryContext. 00028 * It's okay to use a long-lived context because we rely on the ResourceOwner 00029 * mechanism to clean up unused entries after transaction or subtransaction 00030 * abort. We can't safely keep the entries in the executor's per-query 00031 * context, because that might be already freed before we get a chance to 00032 * clean up the list. (XXX seems like there should be a better way to 00033 * manage this...) 00034 */ 00035 typedef struct HashScanListData 00036 { 00037 IndexScanDesc hashsl_scan; 00038 ResourceOwner hashsl_owner; 00039 struct HashScanListData *hashsl_next; 00040 } HashScanListData; 00041 00042 typedef HashScanListData *HashScanList; 00043 00044 static HashScanList HashScans = NULL; 00045 00046 00047 /* 00048 * ReleaseResources_hash() --- clean up hash subsystem resources. 00049 * 00050 * This is here because it needs to touch this module's static var HashScans. 00051 */ 00052 void 00053 ReleaseResources_hash(void) 00054 { 00055 HashScanList l; 00056 HashScanList prev; 00057 HashScanList next; 00058 00059 /* 00060 * Release all HashScanList items belonging to the current ResourceOwner. 00061 * Note that we do not release the underlying IndexScanDesc; that's in 00062 * executor memory and will go away on its own (in fact quite possibly has 00063 * gone away already, so we mustn't try to touch it here). 00064 * 00065 * Note: this should be a no-op during normal query shutdown. However, in 00066 * an abort situation ExecutorEnd is not called and so there may be open 00067 * index scans to clean up. 00068 */ 00069 prev = NULL; 00070 00071 for (l = HashScans; l != NULL; l = next) 00072 { 00073 next = l->hashsl_next; 00074 if (l->hashsl_owner == CurrentResourceOwner) 00075 { 00076 if (prev == NULL) 00077 HashScans = next; 00078 else 00079 prev->hashsl_next = next; 00080 00081 pfree(l); 00082 /* prev does not change */ 00083 } 00084 else 00085 prev = l; 00086 } 00087 } 00088 00089 /* 00090 * _hash_regscan() -- register a new scan. 00091 */ 00092 void 00093 _hash_regscan(IndexScanDesc scan) 00094 { 00095 HashScanList new_el; 00096 00097 new_el = (HashScanList) MemoryContextAlloc(TopMemoryContext, 00098 sizeof(HashScanListData)); 00099 new_el->hashsl_scan = scan; 00100 new_el->hashsl_owner = CurrentResourceOwner; 00101 new_el->hashsl_next = HashScans; 00102 HashScans = new_el; 00103 } 00104 00105 /* 00106 * _hash_dropscan() -- drop a scan from the scan list 00107 */ 00108 void 00109 _hash_dropscan(IndexScanDesc scan) 00110 { 00111 HashScanList chk, 00112 last; 00113 00114 last = NULL; 00115 for (chk = HashScans; 00116 chk != NULL && chk->hashsl_scan != scan; 00117 chk = chk->hashsl_next) 00118 last = chk; 00119 00120 if (chk == NULL) 00121 elog(ERROR, "hash scan list trashed; cannot find 0x%p", (void *) scan); 00122 00123 if (last == NULL) 00124 HashScans = chk->hashsl_next; 00125 else 00126 last->hashsl_next = chk->hashsl_next; 00127 00128 pfree(chk); 00129 } 00130 00131 /* 00132 * Is there an active scan in this bucket? 00133 */ 00134 bool 00135 _hash_has_active_scan(Relation rel, Bucket bucket) 00136 { 00137 Oid relid = RelationGetRelid(rel); 00138 HashScanList l; 00139 00140 for (l = HashScans; l != NULL; l = l->hashsl_next) 00141 { 00142 if (relid == l->hashsl_scan->indexRelation->rd_id) 00143 { 00144 HashScanOpaque so = (HashScanOpaque) l->hashsl_scan->opaque; 00145 00146 if (so->hashso_bucket_valid && 00147 so->hashso_bucket == bucket) 00148 return true; 00149 } 00150 } 00151 00152 return false; 00153 }