Improve test coverage of CLOBBER_CACHE_ALWAYS by having it also force
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 28 Nov 2007 20:44:26 +0000 (20:44 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 28 Nov 2007 20:44:26 +0000 (20:44 +0000)
reloading of operator class information on each use of LookupOpclassInfo.
Had this been in place a year ago, it would have helped me find a bug
in the then-new 'operator family' code.  Now that we have a build farm
member testing CLOBBER_CACHE_ALWAYS on a regular basis, it seems worth
expending a little bit of effort here.

src/backend/utils/cache/relcache.c

index e28a79134e89f467e570f0d2e7a6b76eccbd6866..d0fe1e06ac8b97d8ed867da36eb304a07754b24b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.264 2007/11/15 21:14:40 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.265 2007/11/28 20:44:26 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1133,9 +1133,13 @@ IndexSupportInitialize(oidvector *indclass,
  * numbers is passed in, rather than being looked up, mainly because the
  * caller will have it already.
  *
- * XXX There isn't any provision for flushing the cache.  However, there
- * isn't any provision for flushing relcache entries when opclass info
- * changes, either :-(
+ * Note there is no provision for flushing the cache.  This is OK at the
+ * moment because there is no way to ALTER any interesting properties of an
+ * existing opclass --- all you can do is drop it, which will result in
+ * a useless but harmless dead entry in the cache.  To support altering
+ * opclass membership (not the same as opfamily membership!), we'd need to
+ * be able to flush this cache as well as the contents of relcache entries
+ * for indexes.
  */
 static OpClassCacheEnt *
 LookupOpclassInfo(Oid operatorClassOid,
@@ -1170,34 +1174,50 @@ LookupOpclassInfo(Oid operatorClassOid,
                                                                                           (void *) &operatorClassOid,
                                                                                           HASH_ENTER, &found);
 
-       if (found && opcentry->valid)
+       if (!found)
+       {
+               /* Need to allocate memory for new entry */
+               opcentry->valid = false;        /* until known OK */
+               opcentry->numStrats = numStrats;
+               opcentry->numSupport = numSupport;
+
+               if (numStrats > 0)
+                       opcentry->operatorOids = (Oid *)
+                               MemoryContextAllocZero(CacheMemoryContext,
+                                                                          numStrats * sizeof(Oid));
+               else
+                       opcentry->operatorOids = NULL;
+
+               if (numSupport > 0)
+                       opcentry->supportProcs = (RegProcedure *)
+                               MemoryContextAllocZero(CacheMemoryContext,
+                                                                          numSupport * sizeof(RegProcedure));
+               else
+                       opcentry->supportProcs = NULL;
+       }
+       else
        {
-               /* Already made an entry for it */
                Assert(numStrats == opcentry->numStrats);
                Assert(numSupport == opcentry->numSupport);
-               return opcentry;
        }
 
-       /* Need to fill in new entry */
-       opcentry->valid = false;        /* until known OK */
-       opcentry->numStrats = numStrats;
-       opcentry->numSupport = numSupport;
-
-       if (numStrats > 0)
-               opcentry->operatorOids = (Oid *)
-                       MemoryContextAllocZero(CacheMemoryContext,
-                                                                  numStrats * sizeof(Oid));
-       else
-               opcentry->operatorOids = NULL;
+       /*
+        * When testing for cache-flush hazards, we intentionally disable the
+        * operator class cache and force reloading of the info on each call.
+        * This is helpful because we want to test the case where a cache flush
+        * occurs while we are loading the info, and it's very hard to provoke
+        * that if this happens only once per opclass per backend.
+        */
+#if defined(CLOBBER_CACHE_ALWAYS)
+       opcentry->valid = false;
+#endif
 
-       if (numSupport > 0)
-               opcentry->supportProcs = (RegProcedure *)
-                       MemoryContextAllocZero(CacheMemoryContext,
-                                                                  numSupport * sizeof(RegProcedure));
-       else
-               opcentry->supportProcs = NULL;
+       if (opcentry->valid)
+               return opcentry;
 
        /*
+        * Need to fill in new entry.
+        *
         * To avoid infinite recursion during startup, force heap scans if we're
         * looking up info for the opclasses used by the indexes we would like to
         * reference here.