diff --git a/CHANGES b/CHANGES index 4f3a04cd07..6b6f217041 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +6391. [bug] Use a completely new memory context when flushing the + cache. [GL #2744] + 6390. [placeholder] 6389. [bug] dnssec-verify and dnssec-signzone could fail if there diff --git a/bin/delv/delv.c b/bin/delv/delv.c index a767c0cffa..e06322de11 100644 --- a/bin/delv/delv.c +++ b/bin/delv/delv.c @@ -2151,7 +2151,7 @@ run_server(void *arg) { CHECK(dns_view_create(mctx, dispatchmgr, dns_rdataclass_in, "_default", &view)); - CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", &cache)); + CHECK(dns_cache_create(loopmgr, dns_rdataclass_in, "", mctx, &cache)); dns_view_setcache(view, cache, false); dns_cache_detach(&cache); dns_view_setdstport(view, destport); diff --git a/bin/named/server.c b/bin/named/server.c index f972dce906..a17375dbaa 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -4671,7 +4671,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, * is simply a named cache that is not shared. */ CHECK(dns_cache_create(named_g_loopmgr, view->rdclass, - cachename, &cache)); + cachename, mctx, &cache)); } nsc = isc_mem_get(mctx, sizeof(*nsc)); nsc->cache = NULL; diff --git a/lib/dns/cache.c b/lib/dns/cache.c index acff97edae..e9e677c40b 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -66,8 +66,9 @@ struct dns_cache { /* Unlocked. */ unsigned int magic; isc_mutex_t lock; - isc_mem_t *mctx; /* Main cache memory */ + isc_mem_t *mctx; /* Memory context for the dns_cache object */ isc_mem_t *hmctx; /* Heap memory */ + isc_mem_t *tmctx; /* Tree memory */ isc_loop_t *loop; char *name; isc_refcount_t references; @@ -86,62 +87,19 @@ struct dns_cache { ***/ static isc_result_t -cache_create_db(dns_cache_t *cache, dns_db_t **db) { +cache_create_db(dns_cache_t *cache, dns_db_t **dbp, isc_mem_t **tmctxp, + isc_mem_t **hmctxp) { isc_result_t result; char *argv[1] = { 0 }; + dns_db_t *db = NULL; + isc_mem_t *tmctx = NULL, *hmctx = NULL; /* - * For databases of type "qpcache" or "rbt" (which are the - * only cache implementations currently in existence) we pass - * hmctx to dns_db_create() via argv[0]. - */ - argv[0] = (char *)cache->hmctx; - result = dns_db_create(cache->mctx, CACHEDB_DEFAULT, dns_rootname, - dns_dbtype_cache, cache->rdclass, 1, argv, db); - if (result != ISC_R_SUCCESS) { - return (result); - } - - dns_db_setservestalettl(*db, cache->serve_stale_ttl); - dns_db_setservestalerefresh(*db, cache->serve_stale_refresh); - dns_db_setloop(*db, cache->loop); - - result = dns_db_setcachestats(*db, cache->stats); - if (result != ISC_R_SUCCESS) { - dns_db_detach(db); - return (result); - } - - return (ISC_R_SUCCESS); -} - -static void -cache_destroy(dns_cache_t *cache) { - isc_stats_detach(&cache->stats); - isc_mutex_destroy(&cache->lock); - isc_mem_free(cache->mctx, cache->name); - isc_loop_detach(&cache->loop); - isc_mem_detach(&cache->hmctx); - isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache)); -} - -isc_result_t -dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass, - const char *cachename, dns_cache_t **cachep) { - isc_result_t result; - dns_cache_t *cache = NULL; - isc_mem_t *mctx = NULL, *hmctx = NULL; - - REQUIRE(loopmgr != NULL); - REQUIRE(cachename != NULL); - REQUIRE(cachep != NULL && *cachep == NULL); - - /* - * This will be the main cache memory context, which is subject + * This will be the cache memory context, which is subject * to cleaning when the configured memory limits are exceeded. */ - isc_mem_create(&mctx); - isc_mem_setname(mctx, "cache"); + isc_mem_create(&tmctx); + isc_mem_setname(tmctx, "cache"); /* * This will be passed to RBTDB to use for heaps. This is separate @@ -152,10 +110,66 @@ dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass, isc_mem_create(&hmctx); isc_mem_setname(hmctx, "cache_heap"); + /* + * For databases of type "qpcache" or "rbt" (which are the + * only cache implementations currently in existence) we pass + * hmctx to dns_db_create() via argv[0]. + */ + argv[0] = (char *)hmctx; + result = dns_db_create(tmctx, CACHEDB_DEFAULT, dns_rootname, + dns_dbtype_cache, cache->rdclass, 1, argv, &db); + if (result != ISC_R_SUCCESS) { + goto cleanup_mctx; + } + result = dns_db_setcachestats(db, cache->stats); + if (result != ISC_R_SUCCESS) { + goto cleanup_db; + } + dns_db_setservestalettl(db, cache->serve_stale_ttl); + dns_db_setservestalerefresh(db, cache->serve_stale_refresh); + dns_db_setloop(db, cache->loop); + *dbp = db; + *hmctxp = hmctx; + *tmctxp = tmctx; + + return (ISC_R_SUCCESS); + +cleanup_db: + dns_db_detach(&db); +cleanup_mctx: + isc_mem_detach(&hmctx); + isc_mem_detach(&tmctx); + + return (result); +} + +static void +cache_destroy(dns_cache_t *cache) { + isc_stats_detach(&cache->stats); + isc_mutex_destroy(&cache->lock); + isc_mem_free(cache->mctx, cache->name); + isc_loop_detach(&cache->loop); + if (cache->hmctx != NULL) { + isc_mem_detach(&cache->hmctx); + } + if (cache->tmctx != NULL) { + isc_mem_detach(&cache->tmctx); + } + isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache)); +} + +isc_result_t +dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass, + const char *cachename, isc_mem_t *mctx, dns_cache_t **cachep) { + isc_result_t result; + dns_cache_t *cache = NULL; + + REQUIRE(loopmgr != NULL); + REQUIRE(cachename != NULL); + REQUIRE(cachep != NULL && *cachep == NULL); + cache = isc_mem_get(mctx, sizeof(*cache)); *cache = (dns_cache_t){ - .mctx = mctx, - .hmctx = hmctx, .rdclass = rdclass, .name = isc_mem_strdup(mctx, cachename), .loop = isc_loop_ref(isc_loop_main(loopmgr)), @@ -164,13 +178,15 @@ dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass, }; isc_mutex_init(&cache->lock); + isc_mem_attach(mctx, &cache->mctx); isc_stats_create(mctx, &cache->stats, dns_cachestatscounter_max); /* * Create the database */ - result = cache_create_db(cache, &cache->db); + result = cache_create_db(cache, &cache->db, &cache->tmctx, + &cache->hmctx); if (result != ISC_R_SUCCESS) { goto cleanup; } @@ -190,7 +206,7 @@ cache_cleanup(dns_cache_t *cache) { isc_refcount_destroy(&cache->references); cache->magic = 0; - isc_mem_clearwater(cache->mctx); + isc_mem_clearwater(cache->tmctx); dns_db_detach(&cache->db); cache_destroy(cache); @@ -220,6 +236,17 @@ dns_cache_getname(dns_cache_t *cache) { return (cache->name); } +static void +updatewater(dns_cache_t *cache) { + size_t hi = cache->size - (cache->size >> 3); /* ~ 7/8ths. */ + size_t lo = cache->size - (cache->size >> 2); /* ~ 3/4ths. */ + if (cache->size == 0U || hi == 0U || lo == 0U) { + isc_mem_clearwater(cache->tmctx); + } else { + isc_mem_setwater(cache->tmctx, hi, lo); + } +} + void dns_cache_setcachesize(dns_cache_t *cache, size_t size) { REQUIRE(VALID_CACHE(cache)); @@ -234,15 +261,8 @@ dns_cache_setcachesize(dns_cache_t *cache, size_t size) { LOCK(&cache->lock); cache->size = size; + updatewater(cache); UNLOCK(&cache->lock); - - size_t hi = size - (size >> 3); /* Approximately 7/8ths. */ - size_t lo = size - (size >> 2); /* Approximately 3/4ths. */ - if (size == 0U || hi == 0U || lo == 0U) { - isc_mem_clearwater(cache->mctx); - } else { - isc_mem_setwater(cache->mctx, hi, lo); - } } size_t @@ -309,19 +329,29 @@ dns_cache_getservestalerefresh(dns_cache_t *cache) { isc_result_t dns_cache_flush(dns_cache_t *cache) { dns_db_t *db = NULL, *olddb; + isc_mem_t *tmctx = NULL, *oldtmctx; + isc_mem_t *hmctx = NULL, *oldhmctx; isc_result_t result; - result = cache_create_db(cache, &db); + result = cache_create_db(cache, &db, &tmctx, &hmctx); if (result != ISC_R_SUCCESS) { return (result); } LOCK(&cache->lock); + isc_mem_clearwater(cache->tmctx); + oldhmctx = cache->hmctx; + cache->hmctx = hmctx; + oldtmctx = cache->tmctx; + cache->tmctx = tmctx; + updatewater(cache); olddb = cache->db; cache->db = db; UNLOCK(&cache->lock); dns_db_detach(&olddb); + isc_mem_detach(&oldhmctx); + isc_mem_detach(&oldtmctx); return (ISC_R_SUCCESS); } @@ -583,7 +613,7 @@ dns_cache_dumpstats(dns_cache_t *cache, FILE *fp) { fprintf(fp, "%20" PRIu64 " %s\n", (uint64_t)dns_db_hashsize(cache->db), "cache database hash buckets"); - fprintf(fp, "%20" PRIu64 " %s\n", (uint64_t)isc_mem_inuse(cache->mctx), + fprintf(fp, "%20" PRIu64 " %s\n", (uint64_t)isc_mem_inuse(cache->tmctx), "cache tree memory in use"); fprintf(fp, "%20" PRIu64 " %s\n", (uint64_t)isc_mem_inuse(cache->hmctx), @@ -643,7 +673,7 @@ dns_cache_renderxml(dns_cache_t *cache, void *writer0) { dns_db_nodecount(cache->db, dns_dbtree_nsec), writer)); TRY0(renderstat("CacheBuckets", dns_db_hashsize(cache->db), writer)); - TRY0(renderstat("TreeMemInUse", isc_mem_inuse(cache->mctx), writer)); + TRY0(renderstat("TreeMemInUse", isc_mem_inuse(cache->tmctx), writer)); TRY0(renderstat("HeapMemInUse", isc_mem_inuse(cache->hmctx), writer)); error: @@ -715,7 +745,7 @@ dns_cache_renderjson(dns_cache_t *cache, void *cstats0) { CHECKMEM(obj); json_object_object_add(cstats, "CacheBuckets", obj); - obj = json_object_new_int64(isc_mem_inuse(cache->mctx)); + obj = json_object_new_int64(isc_mem_inuse(cache->tmctx)); CHECKMEM(obj); json_object_object_add(cstats, "TreeMemInUse", obj); diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h index 103e5cbf7e..72cf80c3f4 100644 --- a/lib/dns/include/dns/cache.h +++ b/lib/dns/include/dns/cache.h @@ -73,7 +73,7 @@ ISC_REFCOUNT_DECL(dns_cache); isc_result_t dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass, - const char *cachename, dns_cache_t **cachep); + const char *cachename, isc_mem_t *mctx, dns_cache_t **cachep); /*%< * Create a new DNS cache. * @@ -84,6 +84,8 @@ dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass, *\li 'loopmgr' is a valid loop manager. * *\li 'cachename' is a valid string. This must not be NULL. + + *\li 'mctx' is a valid memory context. * *\li 'cachep' is a valid pointer, and *cachep == NULL * diff --git a/tests/libtest/dns.c b/tests/libtest/dns.c index e57a6820e8..8dd1bbc5e5 100644 --- a/tests/libtest/dns.c +++ b/tests/libtest/dns.c @@ -84,7 +84,7 @@ dns_test_makeview(const char *name, bool with_dispatchmgr, bool with_cache, } if (with_cache) { - result = dns_cache_create(loopmgr, dns_rdataclass_in, "", + result = dns_cache_create(loopmgr, dns_rdataclass_in, "", mctx, &cache); if (result != ISC_R_SUCCESS) { dns_view_detach(&view);