mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 14:35:26 +00:00
Use a new memory context when flushing the cache
When the cache's memory context was in over memory state when the cache was flushed it resulted in LRU cleaning removing newly entered data in the new cache straight away until the old cache had been destroyed enough to take it out of over memory state. When flushing the cache create a new memory context for the new db to prevent this.
This commit is contained in:
167
lib/dns/cache.c
167
lib/dns/cache.c
@@ -68,6 +68,7 @@ struct dns_cache {
|
||||
isc_mutex_t lock;
|
||||
isc_mem_t *mctx; /* Main cache memory */
|
||||
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,74 @@ 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, dns_cache_t **cachep) {
|
||||
isc_result_t result;
|
||||
dns_cache_t *cache = NULL;
|
||||
isc_mem_t *mctx = NULL;
|
||||
|
||||
REQUIRE(loopmgr != NULL);
|
||||
REQUIRE(cachename != NULL);
|
||||
REQUIRE(cachep != NULL && *cachep == NULL);
|
||||
|
||||
/*
|
||||
* Self.
|
||||
*/
|
||||
isc_mem_create(&mctx);
|
||||
isc_mem_setname(mctx, "cache-self");
|
||||
|
||||
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)),
|
||||
@@ -170,7 +192,8 @@ dns_cache_create(isc_loopmgr_t *loopmgr, dns_rdataclass_t rdclass,
|
||||
/*
|
||||
* 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 +213,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 +243,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 +268,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 +336,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 +620,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 +680,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 +752,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);
|
||||
|
||||
|
Reference in New Issue
Block a user