OSDN Git Service

Change hashscan.c to keep its list of active hash index scans in
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 7 Mar 2008 15:59:03 +0000 (15:59 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 7 Mar 2008 15:59:03 +0000 (15:59 +0000)
TopMemoryContext, rather than scattered through executor per-query contexts.
This poses no danger of memory leak since the ResourceOwner mechanism
guarantees release of no-longer-needed items.  It is needed because the
per-query context might already be released by the time we try to clean up
the hash scan list.  Report by ykhuang, diagnosis by Heikki.

Back-patch to 8.0, where the ResourceOwner-based cleanup was introduced.
The given test case does not fail before 8.2, probably because we rearranged
transaction abort processing somehow; but this coding is undoubtedly risky
so I'll patch 8.0 and 8.1 anyway.

src/backend/access/hash/hashscan.c

index 2598c5f..1272ec9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.43 2008/01/01 19:45:46 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.44 2008/03/07 15:59:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "access/hash.h"
+#include "utils/memutils.h"
 #include "utils/resowner.h"
 
 
+/*
+ * We track all of a backend's active scans on hash indexes using a list
+ * of HashScanListData structs, which are allocated in TopMemoryContext.
+ * It's okay to use a long-lived context because we rely on the ResourceOwner
+ * mechanism to clean up unused entries after transaction or subtransaction
+ * abort.  We can't safely keep the entries in the executor's per-query
+ * context, because that might be already freed before we get a chance to
+ * clean up the list.  (XXX seems like there should be a better way to
+ * manage this...)
+ */
 typedef struct HashScanListData
 {
        IndexScanDesc hashsl_scan;
@@ -44,6 +55,11 @@ ReleaseResources_hash(void)
        HashScanList next;
 
        /*
+        * Release all HashScanList items belonging to the current ResourceOwner.
+        * Note that we do not release the underlying IndexScanDesc; that's in
+        * executor memory and will go away on its own (in fact quite possibly
+        * has gone away already, so we mustn't try to touch it here).
+        *
         * Note: this should be a no-op during normal query shutdown. However, in
         * an abort situation ExecutorEnd is not called and so there may be open
         * index scans to clean up.
@@ -69,14 +85,15 @@ ReleaseResources_hash(void)
 }
 
 /*
- *     _Hash_regscan() -- register a new scan.
+ *     _hash_regscan() -- register a new scan.
  */
 void
 _hash_regscan(IndexScanDesc scan)
 {
        HashScanList new_el;
 
-       new_el = (HashScanList) palloc(sizeof(HashScanListData));
+       new_el = (HashScanList) MemoryContextAlloc(TopMemoryContext,
+                                                                                          sizeof(HashScanListData));
        new_el->hashsl_scan = scan;
        new_el->hashsl_owner = CurrentResourceOwner;
        new_el->hashsl_next = HashScans;