Take a bigger leap than the default when growing the cache hash tables beyond 18 bits
Related to #1775 (closed) and Support ticket #16212
Ideally, with the change in initial size of hash table based on max-cache-size ( #1775 (closed) ), we should never ever need to resize the hash table whilst named is running (unless we got our calculations wrong). So let's ignore the possibility that we started anyway with a big hash table, and consider the other scenario, that is we've started with an unlimited max-cache-size (configured the value 0) and that therefore named wasn't able to choose an appropriate initial hash table, and had to start at the smallest setting.
The amount of time spent in rehash is linear on count of nodes.
On modern Intel hardware the customer submitting this request measured about 400ns per node.
A rehash of tables < 2^18 bits uses max 50ms which probably nobody will notice. But any rehash of tables with 2^18 nodes or more will be noticeable and will cause named to stop serving clients for a few seconds. But a rehash a table of more than 2^25 nodes, this will take more than 13 seconds - you've rendered your resolver effectively offline - you really don't want to do that!
Therefore named might as well just jump ahead and allocate a really big enough table that will (probably) never ever be needed to increase further.
The original suggestion from the submitting customer is that the hash table resizing leaps from 2^18 directly to 2^24 or 2^25, based on their own server needs.
My alternative proposal (thinking about whopping big servers with oodles of memory) is that we (at this 'last big rehashing point' only) :
-
Establish what 90% of the memory capacity is of the server (similar to the default max-cache-size calculation)
-
Ascertain how big all the caches are on this server right now across all the views with caches (doing this now on the basis that once the server has been up and running for awhile, it is likely to be populating caches relative to one another in proportion to how cache server memory is going to be shared amongst them anyway).
-
Use that ratio to assign a theoretical biggest cache size for the cache whose hash table is about to be resized
-
From that theoretical maximum cache calculate the value in order to make that last big rehash leap from 2^18 to biggest possible all in one go.
This is the patch as originally submitted:
#define REHASH_LARGE_BITS 24
*** lib/dns/rbt.c-orig 2020-08-21 08:07:50.408349767 +0200
--- lib/dns/rbt.c 2020-08-21 08:07:55.161400495 +0200
***************
*** 2338,2343 ****
--- 2338,2353 ----
newbits += 1;
}
+ #ifdef REHASH_LARGE_BITS
+ /* Rehash of a large hash table will be very slow with a lot of memory access.
+ We've measured 400 nanoseconds per node on modern machine. A rehash of a million node
+ table will take 400ms and in practice stop named for this amount of time. So from 2^18
+ to 2^24 we skip intermediate steps and just allocate a big table so with a little luck
+ there will be no need rehash again. */
+ if (newbits > 18 && newbits < REHASH_LARGE_BITS)
+ newbits = REHASH_LARGE_BITS;
+ #endif
+
return (newbits);
}
I'm not offering a patch for my suggestion - (although I could, if I put my mind to it, but that's probably not the best use of my skillset!)