Header And Logo

PostgreSQL
| The world's most advanced open source database.

hashscan.c

Go to the documentation of this file.
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 }