]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
include the nodenames when calculating memory to purge
authorEvan Hunt <each@isc.org>
Thu, 14 Mar 2024 23:46:52 +0000 (16:46 -0700)
committerEvan Hunt <each@isc.org>
Tue, 30 Apr 2024 19:50:01 +0000 (12:50 -0700)
when the cache is over memory, we purge from the LRU list until
we've freed the approximate amount of memory to be added. this
approximation could fail because the memory allocated for nodenames
wasn't being counted.

add a dns_name_size() function so we can look up the size of nodenames,
then add that to the purgesize calculation.

lib/dns/include/dns/name.h
lib/dns/name.c
lib/dns/qpcache.c
tests/dns/qpdb_test.c

index a9a15ae5dea9c3eee13ddd5d1b71641800395a24..8180b1bb0385a30d856256c6f760c81681433970 100644 (file)
@@ -1339,4 +1339,14 @@ dns_name_isdnssvcb(const dns_name_t *name);
  * i.e. it starts with and optional _port label followed by a _dns label.
  */
 
+size_t
+dns_name_size(const dns_name_t *name);
+/*%<
+ * Return the amount of dynamically allocated memory associated with
+ * 'name' (which is 0 if 'name' is not dynamic).
+ *
+ * Requires:
+ * \li 'name' to be valid.
+ */
+
 ISC_LANG_ENDDECLS
index 9bca9ed7a0aad745a726c2fc54469dbbbf111e6c..03f12433c7bf8e86713d34525115b54cbaf8cbce 100644 (file)
@@ -1845,6 +1845,24 @@ dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
        dns_name_invalidate(name);
 }
 
+size_t
+dns_name_size(const dns_name_t *name) {
+       size_t size;
+
+       REQUIRE(DNS_NAME_VALID(name));
+
+       if (!name->attributes.dynamic) {
+               return (0);
+       }
+
+       size = name->length;
+       if (name->attributes.dynoffsets) {
+               size += name->labels;
+       }
+
+       return (size);
+}
+
 isc_result_t
 dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg) {
        dns_name_t downname;
index 529e637ddf804e9fc94f5156fc97fa6c7d82b086..647b54bdc42b5172766dac9ef15a29c850bfe670 100644 (file)
@@ -2403,12 +2403,21 @@ overmem(qpcache_t *qpdb, dns_slabheader_t *newheader,
        isc_rwlocktype_t *tlocktypep DNS__DB_FLARG) {
        uint32_t locknum_start = qpdb->lru_sweep++ % qpdb->node_lock_count;
        uint32_t locknum = locknum_start;
-       /* Size of added data, possible node and possible ENT node. */
-       size_t purgesize = rdataset_size(newheader) + 2 * sizeof(qpcnode_t);
-       size_t purged = 0;
+       size_t purgesize, purged = 0;
        isc_stdtime_t min_last_used = 0;
        size_t max_passes = 8;
 
+       /*
+        * Maximum estimated size of the data being added: The size
+        * of the rdataset, plus a new QP database node and nodename,
+        * and a possible additional NSEC node and nodename. Also add
+        * a 12k margin for a possible QP-trie chunk allocation.
+        * (It's okay to overestimate, we want to get cache memory
+        * down quickly.)
+        */
+       purgesize = 2 * (sizeof(qpcnode_t) +
+                        dns_name_size(&HEADERNODE(newheader)->name)) +
+                   rdataset_size(newheader) + 12288;
 again:
        do {
                isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
index d96a59080c0a3775484a1b4463df726f37cd3eb9..43ac35d1c5fa71c34f096230e31a9dc064aff129 100644 (file)
@@ -42,6 +42,9 @@
 #undef CHECK
 #include <tests/dns.h>
 
+/* Set to true (or use -v option) for verbose output */
+static bool verbose = false;
+
 /*
  * Add to a cache DB 'db' an rdataset of type 'rtype' at a name
  * <idx>.example.com. The rdataset would contain one data, and rdata_len is
@@ -140,12 +143,16 @@ ISC_RUN_TEST_IMPL(overmempurge_bigrdata) {
 
        /*
         * Then try to add the same number of entries, each has very large data.
-        * 'overmem purge' should keep the total cache size from not exceeding
+        * 'overmem purge' should keep the total cache size from exceeding
         * the 'hiwater' mark too much. So we should be able to assume the
         * cache size doesn't reach the "max".
         */
        while (i-- > 0) {
                overmempurge_addrdataset(db, now, i, 50054, 65535, false);
+               if (verbose) {
+                       print_message("# inuse: %zd max: %zd\n",
+                                     isc_mem_inuse(mctx2), maxcache);
+               }
                assert_true(isc_mem_inuse(mctx2) < maxcache);
        }
 
@@ -191,6 +198,10 @@ ISC_RUN_TEST_IMPL(overmempurge_longname) {
         */
        while (i-- > 0) {
                overmempurge_addrdataset(db, now, i, 50054, 0, true);
+               if (verbose) {
+                       print_message("# inuse: %zd max: %zd\n",
+                                     isc_mem_inuse(mctx2), maxcache);
+               }
                assert_true(isc_mem_inuse(mctx2) < maxcache);
        }