From: Evan Hunt Date: Thu, 14 Mar 2024 23:46:52 +0000 (-0700) Subject: include the nodenames when calculating memory to purge X-Git-Tag: v9.19.24~5^2~3 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=04d319afe47b6a38e22978d8618061c52532368d;p=thirdparty%2Fbind9.git include the nodenames when calculating memory to purge 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. --- diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index a9a15ae5dea..8180b1bb038 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -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 diff --git a/lib/dns/name.c b/lib/dns/name.c index 9bca9ed7a0a..03f12433c7b 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -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; diff --git a/lib/dns/qpcache.c b/lib/dns/qpcache.c index 529e637ddf8..647b54bdc42 100644 --- a/lib/dns/qpcache.c +++ b/lib/dns/qpcache.c @@ -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; diff --git a/tests/dns/qpdb_test.c b/tests/dns/qpdb_test.c index d96a59080c0..43ac35d1c5f 100644 --- a/tests/dns/qpdb_test.c +++ b/tests/dns/qpdb_test.c @@ -42,6 +42,9 @@ #undef CHECK #include +/* 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 * .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); }