]> granicus.if.org Git - postgresql/commitdiff
Be smarter about age-counter overflow in formatting.c caches.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 16 Oct 2018 18:57:14 +0000 (14:57 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 16 Oct 2018 18:57:14 +0000 (14:57 -0400)
The previous code here simply threw away whatever it knew about cache
entry ages whenever a counter overflow occurred.  Since the counter
is int width and will be bumped once per format function execution,
overflows are not really so rare as to not be worth thinking about.
Instead, let's deal with the situation by halving all the age values,
essentially rescaling the age metric.  In that way, we retain a
pretty accurate (if not quite perfect) idea of which entries are oldest.

src/backend/utils/adt/formatting.c

index d158ef9adf931847e02d24e30139aa19c92ecda7..4118b78ae41702b9510af317f24e6915bfb1eca3 100644 (file)
@@ -3376,20 +3376,32 @@ DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
        }
 }
 
+/*
+ * The invariant for DCH cache entry management is that DCHCounter is equal
+ * to the maximum age value among the existing entries, and we increment it
+ * whenever an access occurs.  If we approach overflow, deal with that by
+ * halving all the age values, so that we retain a fairly accurate idea of
+ * which entries are oldest.
+ */
+static inline void
+DCH_prevent_counter_overflow(void)
+{
+       if (DCHCounter >= (INT_MAX - 1))
+       {
+               for (int i = 0; i < n_DCHCache; i++)
+                       DCHCache[i]->age >>= 1;
+               DCHCounter >>= 1;
+       }
+}
+
 /* select a DCHCacheEntry to hold the given format picture */
 static DCHCacheEntry *
 DCH_cache_getnew(const char *str)
 {
        DCHCacheEntry *ent;
 
-       /* handle counter overflow by resetting all ages */
-       if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES))
-       {
-               DCHCounter = 0;
-
-               for (int i = 0; i < n_DCHCache; i++)
-                       DCHCache[i]->age = (++DCHCounter);
-       }
+       /* Ensure we can advance DCHCounter below */
+       DCH_prevent_counter_overflow();
 
        /*
         * If cache is full, remove oldest entry (or recycle first not-valid one)
@@ -3445,14 +3457,8 @@ DCH_cache_getnew(const char *str)
 static DCHCacheEntry *
 DCH_cache_search(const char *str)
 {
-       /* handle counter overflow by resetting all ages */
-       if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES))
-       {
-               DCHCounter = 0;
-
-               for (int i = 0; i < n_DCHCache; i++)
-                       DCHCache[i]->age = (++DCHCounter);
-       }
+       /* Ensure we can advance DCHCounter below */
+       DCH_prevent_counter_overflow();
 
        for (int i = 0; i < n_DCHCache; i++)
        {
@@ -4057,20 +4063,26 @@ do { \
        (_n)->zero_end          = 0;    \
 } while(0)
 
+/* This works the same as DCH_prevent_counter_overflow */
+static inline void
+NUM_prevent_counter_overflow(void)
+{
+       if (NUMCounter >= (INT_MAX - 1))
+       {
+               for (int i = 0; i < n_NUMCache; i++)
+                       NUMCache[i]->age >>= 1;
+               NUMCounter >>= 1;
+       }
+}
+
 /* select a NUMCacheEntry to hold the given format picture */
 static NUMCacheEntry *
 NUM_cache_getnew(const char *str)
 {
        NUMCacheEntry *ent;
 
-       /* handle counter overflow by resetting all ages */
-       if (NUMCounter >= (INT_MAX - NUM_CACHE_ENTRIES))
-       {
-               NUMCounter = 0;
-
-               for (int i = 0; i < n_NUMCache; i++)
-                       NUMCache[i]->age = (++NUMCounter);
-       }
+       /* Ensure we can advance NUMCounter below */
+       NUM_prevent_counter_overflow();
 
        /*
         * If cache is full, remove oldest entry (or recycle first not-valid one)
@@ -4126,14 +4138,8 @@ NUM_cache_getnew(const char *str)
 static NUMCacheEntry *
 NUM_cache_search(const char *str)
 {
-       /* handle counter overflow by resetting all ages */
-       if (NUMCounter >= (INT_MAX - NUM_CACHE_ENTRIES))
-       {
-               NUMCounter = 0;
-
-               for (int i = 0; i < n_NUMCache; i++)
-                       NUMCache[i]->age = (++NUMCounter);
-       }
+       /* Ensure we can advance NUMCounter below */
+       NUM_prevent_counter_overflow();
 
        for (int i = 0; i < n_NUMCache; i++)
        {