Fix spccache.c to not suppose that a cache entry will live across database
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 6 Jan 2010 23:00:02 +0000 (23:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 6 Jan 2010 23:00:02 +0000 (23:00 +0000)
access, per testing with CLOBBER_CACHE_ALWAYS.  Minor other editorialization.

src/backend/utils/cache/spccache.c

index 7de65b31b712d75d66cf8bd4ae1760d2e569c38b..16526159bc80113523414fdc69f52b708e114a1f 100644 (file)
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.2 2010/01/06 22:27:09 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/utils/cache/spccache.c,v 1.3 2010/01/06 23:00:02 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
-
 #include "postgres.h"
+
 #include "access/reloptions.h"
 #include "catalog/pg_tablespace.h"
 #include "commands/tablespace.h"
 #include "utils/spccache.h"
 #include "utils/syscache.h"
 
+
+/* Hash table for information about each tablespace */
 static HTAB *TableSpaceCacheHash = NULL;
 
-typedef struct {
-   Oid         oid;
-   TableSpaceOpts *opts;
-} TableSpace;
+typedef struct
+{
+   Oid         oid;            /* lookup key - must be first */
+   TableSpaceOpts *opts;       /* options, or NULL if none */
+} TableSpaceCacheEntry;
+
 
 /*
  * InvalidateTableSpaceCacheCallback
@@ -49,10 +53,10 @@ static void
 InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
 {
    HASH_SEQ_STATUS status;
-   TableSpace *spc;
+   TableSpaceCacheEntry *spc;
 
    hash_seq_init(&status, TableSpaceCacheHash);
-   while ((spc = (TableSpace *) hash_seq_search(&status)) != NULL)
+   while ((spc = (TableSpaceCacheEntry *) hash_seq_search(&status)) != NULL)
    {
        if (spc->opts)
            pfree(spc->opts);
@@ -66,7 +70,7 @@ InvalidateTableSpaceCacheCallback(Datum arg, int cacheid, ItemPointer tuplePtr)
 
 /*
  * InitializeTableSpaceCache
- *     Initiate the tablespace cache.
+ *     Initialize the tablespace cache.
  */
 static void
 InitializeTableSpaceCache(void)
@@ -76,8 +80,8 @@ InitializeTableSpaceCache(void)
    /* Initialize the hash table. */
    MemSet(&ctl, 0, sizeof(ctl));
    ctl.keysize = sizeof(Oid);
-   ctl.entrysize = sizeof(TableSpace);
-   ctl.hash = tag_hash;
+   ctl.entrysize = sizeof(TableSpaceCacheEntry);
+   ctl.hash = oid_hash;
    TableSpaceCacheHash =
        hash_create("TableSpace cache", 16, &ctl,
                    HASH_ELEM | HASH_FUNCTION);
@@ -94,17 +98,17 @@ InitializeTableSpaceCache(void)
 
 /*
  * get_tablespace
- *     Fetch TableSpace structure for a specified table OID.
+ *     Fetch TableSpaceCacheEntry structure for a specified table OID.
  *
  * Pointers returned by this function should not be stored, since a cache
  * flush will invalidate them.
  */
-static TableSpace *
+static TableSpaceCacheEntry *
 get_tablespace(Oid spcid)
 {
+   TableSpaceCacheEntry *spc;
    HeapTuple   tp;
-   TableSpace *spc;
-   bool        found;
+   TableSpaceOpts *opts;
 
    /*
     * Since spcid is always from a pg_class tuple, InvalidOid implies the
@@ -113,12 +117,14 @@ get_tablespace(Oid spcid)
    if (spcid == InvalidOid)
        spcid = MyDatabaseTableSpace;
 
-   /* Find existing cache entry, or create a new one. */
+   /* Find existing cache entry, if any. */
    if (!TableSpaceCacheHash)
        InitializeTableSpaceCache();
-   spc = (TableSpace *) hash_search(TableSpaceCacheHash, (void *) &spcid,
-                                    HASH_ENTER, &found);
-   if (found)
+   spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
+                                              (void *) &spcid,
+                                              HASH_FIND,
+                                              NULL);
+   if (spc)
        return spc;
 
    /*
@@ -127,9 +133,11 @@ get_tablespace(Oid spcid)
     * details for a non-existent tablespace.  We'll just treat that case as if
     * no options were specified.
     */
-   tp = SearchSysCache(TABLESPACEOID, ObjectIdGetDatum(spcid), 0, 0, 0);
+   tp = SearchSysCache(TABLESPACEOID,
+                       ObjectIdGetDatum(spcid),
+                       0, 0, 0);
    if (!HeapTupleIsValid(tp))
-       spc->opts = NULL;
+       opts = NULL;
    else
    {
        Datum   datum;
@@ -141,29 +149,40 @@ get_tablespace(Oid spcid)
                                Anum_pg_tablespace_spcoptions,
                                &isNull);
        if (isNull)
-           spc->opts = NULL;
+           opts = NULL;
        else
        {
+           /* XXX should NOT do the parsing work in CacheMemoryContext */
            octx = MemoryContextSwitchTo(CacheMemoryContext);
-           spc->opts = (TableSpaceOpts *) tablespace_reloptions(datum, false);
+           opts = (TableSpaceOpts *) tablespace_reloptions(datum, false);
            MemoryContextSwitchTo(octx);
        }
        ReleaseSysCache(tp);
    }
 
-   /* Update new TableSpace cache entry with results of option parsing. */
+   /*
+    * Now create the cache entry.  It's important to do this only after
+    * reading the pg_tablespace entry, since doing so could cause a cache
+    * flush.
+    */
+   spc = (TableSpaceCacheEntry *) hash_search(TableSpaceCacheHash,
+                                              (void *) &spcid,
+                                              HASH_ENTER,
+                                              NULL);
+   spc->opts = opts;
    return spc;
 }
 
 /*
  * get_tablespace_page_costs
- *     Return random and sequential page costs for a given tablespace.
+ *     Return random and/or sequential page costs for a given tablespace.
  */
 void
-get_tablespace_page_costs(Oid spcid, double *spc_random_page_cost,
-                              double *spc_seq_page_cost)
+get_tablespace_page_costs(Oid spcid,
+                         double *spc_random_page_cost,
+                         double *spc_seq_page_cost)
 {
-   TableSpace *spc = get_tablespace(spcid);
+   TableSpaceCacheEntry *spc = get_tablespace(spcid);
 
    Assert(spc != NULL);