From: Tom Lane Date: Tue, 16 Oct 2018 18:57:14 +0000 (-0400) Subject: Be smarter about age-counter overflow in formatting.c caches. X-Git-Tag: REL_12_BETA1~1381 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2c300c680767a45450bf7afa4075095f40502dc4;p=postgresql Be smarter about age-counter overflow in formatting.c caches. 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. --- diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index d158ef9adf..4118b78ae4 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -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++) {