2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00

cleanups for LRU-caching code [RT #18018]

This commit is contained in:
Tatuya JINMEI 神明達哉
2008-05-01 18:23:07 +00:00
parent 62fd1414b6
commit 5c024f7877
6 changed files with 381 additions and 846 deletions

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: config.c,v 1.86 2008/04/03 02:01:08 marka Exp $ */ /* $Id: config.c,v 1.87 2008/05/01 18:23:06 jinmei Exp $ */
/*! \file */ /*! \file */
@@ -124,7 +124,7 @@ options {\n\
query-source-v6 address *;\n\ query-source-v6 address *;\n\
notify-source *;\n\ notify-source *;\n\
notify-source-v6 *;\n\ notify-source-v6 *;\n\
cleaning-interval 60;\n\ cleaning-interval 0; /* now meaningless */\n\
min-roots 2;\n\ min-roots 2;\n\
lame-ttl 600;\n\ lame-ttl 600;\n\
max-ncache-ttl 10800; /* 3 hours */\n\ max-ncache-ttl 10800; /* 3 hours */\n\

View File

@@ -18,7 +18,7 @@
- PERFORMANCE OF THIS SOFTWARE. - PERFORMANCE OF THIS SOFTWARE.
--> -->
<!-- File: $Id: Bv9ARM-book.xml,v 1.350 2008/04/09 22:48:17 jinmei Exp $ --> <!-- File: $Id: Bv9ARM-book.xml,v 1.351 2008/05/01 18:23:06 jinmei Exp $ -->
<book xmlns:xi="http://www.w3.org/2001/XInclude"> <book xmlns:xi="http://www.w3.org/2001/XInclude">
<title>BIND 9 Administrator Reference Manual</title> <title>BIND 9 Administrator Reference Manual</title>
@@ -6870,11 +6870,14 @@ query-source-v6 address * port *;
<term><command>cleaning-interval</command></term> <term><command>cleaning-interval</command></term>
<listitem> <listitem>
<para> <para>
The server will remove expired resource records This interval is effectively obsolete. Previously,
the server would remove expired resource records
from the cache every <command>cleaning-interval</command> minutes. from the cache every <command>cleaning-interval</command> minutes.
The default is 60 minutes. The maximum value is 28 days <acronym>BIND</acronym> 9 now manages cache
(40320 minutes). memory in a more sophisticated manner and does not
If set to 0, no periodic cleaning will occur. rely on the periodic cleaning any more.
Specifying this option therefore has no effect on
the server's behavior.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: adb.c,v 1.238 2008/04/03 06:09:04 tbox Exp $ */ /* $Id: adb.c,v 1.239 2008/05/01 18:23:07 jinmei Exp $ */
/*! \file /*! \file
* *
@@ -26,13 +26,6 @@
* *
*/ */
/*%
* After we have cleaned all buckets, dump the database contents.
*/
#if 0
#define DUMP_ADB_AFTER_CLEANING
#endif
#include <config.h> #include <config.h>
#include <limits.h> #include <limits.h>
@@ -42,7 +35,6 @@
#include <isc/random.h> #include <isc/random.h>
#include <isc/string.h> /* Required for HP/UX (and others?) */ #include <isc/string.h> /* Required for HP/UX (and others?) */
#include <isc/task.h> #include <isc/task.h>
#include <isc/timer.h>
#include <isc/util.h> #include <isc/util.h>
#include <dns/adb.h> #include <dns/adb.h>
@@ -89,16 +81,6 @@
#define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */ #define ADB_CACHE_MAXIMUM 86400 /*%< seconds (86400 = 24 hours) */
#define ADB_ENTRY_WINDOW 1800 /*%< seconds */ #define ADB_ENTRY_WINDOW 1800 /*%< seconds */
/*%
* Wake up every CLEAN_SECONDS and clean CLEAN_BUCKETS buckets, so that all
* buckets are cleaned in CLEAN_PERIOD seconds.
*/
#define CLEAN_PERIOD 3600
/*% See #CLEAN_PERIOD */
#define CLEAN_SECONDS 30
/*% See #CLEAN_PERIOD */
#define CLEAN_BUCKETS ((NBUCKETS * CLEAN_SECONDS) / CLEAN_PERIOD)
/*% /*%
* The period in seconds after which an ADB name entry is regarded as stale * The period in seconds after which an ADB name entry is regarded as stale
* and forced to be cleaned up. * and forced to be cleaned up.
@@ -132,14 +114,6 @@ struct dns_adb {
isc_mutex_t overmemlock; /*%< Covers overmem */ isc_mutex_t overmemlock; /*%< Covers overmem */
isc_mem_t *mctx; isc_mem_t *mctx;
dns_view_t *view; dns_view_t *view;
isc_timermgr_t *timermgr;
isc_timer_t *timer;
#ifdef LRU_DEBUG
isc_timer_t *dump_timer; /* for test */
isc_time_t dump_time; /* for test */
#define DUMP_INTERVAL 30 /* seconds */
#endif
isc_taskmgr_t *taskmgr; isc_taskmgr_t *taskmgr;
isc_task_t *task; isc_task_t *task;
@@ -187,17 +161,6 @@ struct dns_adb {
isc_boolean_t cevent_sent; isc_boolean_t cevent_sent;
isc_boolean_t shutting_down; isc_boolean_t shutting_down;
isc_eventlist_t whenshutdown; isc_eventlist_t whenshutdown;
#ifdef LRU_DEBUG
unsigned int stale_purge;
unsigned int stale_scan;
unsigned int stale_expire;
unsigned int stale_lru;
unsigned int nname, nname_total;
unsigned int nentry, nentry_total;
unsigned int nameuses, entryuses;
#endif
}; };
/* /*
@@ -344,7 +307,6 @@ static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t,
static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t,
dns_rdatatype_t); dns_rdatatype_t);
static inline void check_exit(dns_adb_t *); static inline void check_exit(dns_adb_t *);
static void timer_cleanup(isc_task_t *, isc_event_t *);
static void destroy(dns_adb_t *); static void destroy(dns_adb_t *);
static isc_boolean_t shutdown_names(dns_adb_t *); static isc_boolean_t shutdown_names(dns_adb_t *);
static isc_boolean_t shutdown_entries(dns_adb_t *); static isc_boolean_t shutdown_entries(dns_adb_t *);
@@ -357,10 +319,6 @@ static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t,
static void water(void *, int); static void water(void *, int);
static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t);
#ifdef LRU_DEBUG
static void timer_dump(isc_task_t *, isc_event_t *);
#endif
/* /*
* MUST NOT overlap DNS_ADBFIND_* flags! * MUST NOT overlap DNS_ADBFIND_* flags!
*/ */
@@ -1332,11 +1290,6 @@ free_adbname(dns_adb_t *adb, dns_adbname_t **name) {
INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET); INSIST(n->lock_bucket == DNS_ADB_INVALIDBUCKET);
INSIST(n->adb == adb); INSIST(n->adb == adb);
#ifdef LRU_DEBUG
adb->nname--; /* XXX: omit ADB lock for brevity */
INSIST((int)adb->nname >= 0);
#endif
n->magic = 0; n->magic = 0;
dns_name_free(&n->name, adb->mctx); dns_name_free(&n->name, adb->mctx);
@@ -1430,11 +1383,6 @@ new_adbentry(dns_adb_t *adb) {
ISC_LIST_INIT(e->lameinfo); ISC_LIST_INIT(e->lameinfo);
ISC_LINK_INIT(e, plink); ISC_LINK_INIT(e, plink);
#ifdef LRU_DEBUG
adb->nentry++; /* XXX: omit ADB lock for brevity */
adb->nentry_total++;
#endif
return (e); return (e);
} }
@@ -1460,11 +1408,6 @@ free_adbentry(dns_adb_t *adb, dns_adbentry_t **entry) {
li = ISC_LIST_HEAD(e->lameinfo); li = ISC_LIST_HEAD(e->lameinfo);
} }
#ifdef LRU_DEBUG
adb->nentry--; /* XXX: omit ADB lock for brevity */
INSIST((int)adb->nentry >= 0);
#endif
isc_mempool_put(adb->emp, e); isc_mempool_put(adb->emp, e);
} }
@@ -1609,10 +1552,6 @@ new_adbaddrinfo(dns_adb_t *adb, dns_adbentry_t *entry, in_port_t port) {
ai->entry = entry; ai->entry = entry;
ISC_LINK_INIT(ai, publink); ISC_LINK_INIT(ai, publink);
#ifdef LRU_DEBUG
adb->entryuses++; /* for debug */
#endif
return (ai); return (ai);
} }
@@ -1832,18 +1771,6 @@ shutdown_task(isc_task_t *task, isc_event_t *ev) {
adb = ev->ev_arg; adb = ev->ev_arg;
INSIST(DNS_ADB_VALID(adb)); INSIST(DNS_ADB_VALID(adb));
/*
* Kill the timer, and then the ADB itself. Note that this implies
* that this task was the one scheduled to get timer events. If
* this is not true (and it is unfortunate there is no way to INSIST()
* this) badness will occur.
*/
LOCK(&adb->lock);
isc_timer_detach(&adb->timer);
#ifdef LRU_DEBUG
isc_timer_detach(&adb->dump_timer);
#endif
UNLOCK(&adb->lock);
isc_event_free(&ev); isc_event_free(&ev);
destroy(adb); destroy(adb);
} }
@@ -1928,9 +1855,6 @@ check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
result = check_expire_name(&victim, now); result = check_expire_name(&victim, now);
if (victim == NULL) { if (victim == NULL) {
#ifdef LRU_DEBUG
adb->stale_expire++;
#endif
victims++; victims++;
goto next; goto next;
} }
@@ -1941,9 +1865,6 @@ check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
DNS_EVENT_ADBCANCELED, DNS_EVENT_ADBCANCELED,
ISC_TRUE) == ISC_TRUE) ==
ISC_FALSE); ISC_FALSE);
#ifdef LRU_DEBUG
adb->stale_lru++;
#endif
victims++; victims++;
} }
@@ -1951,12 +1872,6 @@ check_stale_name(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
if (!overmem) if (!overmem)
break; break;
} }
#ifdef LRU_DEBUG
/* XXX: omit lock for brevity */
adb->stale_scan += scans;
adb->stale_purge += victims;
#endif
} }
/* /*
@@ -2042,96 +1957,10 @@ cleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) {
return (result); return (result);
} }
#if 1
static void
timer_cleanup(isc_task_t *task, isc_event_t *ev) {
UNUSED(task);
isc_event_free(&ev);
}
#else
static void
timer_cleanup(isc_task_t *task, isc_event_t *ev) {
dns_adb_t *adb;
isc_stdtime_t now;
unsigned int i;
isc_interval_t interval;
UNUSED(task);
adb = ev->ev_arg;
INSIST(DNS_ADB_VALID(adb));
LOCK(&adb->lock);
isc_stdtime_get(&now);
for (i = 0; i < CLEAN_BUCKETS; i++) {
/*
* Call our cleanup routines.
*/
RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) ==
ISC_FALSE);
RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now)
== ISC_FALSE);
/*
* Set the next bucket to be cleaned.
*/
adb->next_cleanbucket++;
if (adb->next_cleanbucket >= NBUCKETS) {
adb->next_cleanbucket = 0;
#ifdef DUMP_ADB_AFTER_CLEANING
dump_adb(adb, stdout, ISC_TRUE, now);
#endif
}
}
/*
* Reset the timer.
* XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or
* ISC_R_NOMEMORY, but it isn't clear what could be done here
* if either one of those things happened.
*/
interval = adb->tick_interval;
if (adb->overmem)
isc_interval_set(&interval, 0, 1);
(void)isc_timer_reset(adb->timer, isc_timertype_once, NULL,
&interval, ISC_FALSE);
UNLOCK(&adb->lock);
isc_event_free(&ev);
}
#endif
static void static void
destroy(dns_adb_t *adb) { destroy(dns_adb_t *adb) {
adb->magic = 0; adb->magic = 0;
#ifdef LRU_DEBUG
/* for debug: print statistics */
if (adb->nname_total > 0) {
INSIST(adb->nname == 0 && adb->nentry == 0);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_ADB, ISC_LOG_INFO,
"ADB %p name hit %.2f, entry hit %.2f", adb,
(double)adb->nameuses /
(adb->nname_total + adb->nameuses),
adb->entryuses > 0 ?
(double)adb->entryuses /
(adb->nentry_total + adb->entryuses) : 0);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_ADB, ISC_LOG_INFO,
"ADB %p stale name purges: %u(%u,%u)/%u",
adb, adb->stale_purge, adb->stale_expire,
adb->stale_lru, adb->stale_scan);
}
#endif
/*
* The timer is already dead, from the task's shutdown callback.
*/
isc_task_detach(&adb->task); isc_task_detach(&adb->task);
isc_mempool_destroy(&adb->nmp); isc_mempool_destroy(&adb->nmp);
@@ -2168,10 +1997,12 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
REQUIRE(mem != NULL); REQUIRE(mem != NULL);
REQUIRE(view != NULL); REQUIRE(view != NULL);
REQUIRE(timermgr != NULL); REQUIRE(timermgr != NULL); /* this is actually unused */
REQUIRE(taskmgr != NULL); REQUIRE(taskmgr != NULL);
REQUIRE(newadb != NULL && *newadb == NULL); REQUIRE(newadb != NULL && *newadb == NULL);
UNUSED(timermgr);
adb = isc_mem_get(mem, sizeof(dns_adb_t)); adb = isc_mem_get(mem, sizeof(dns_adb_t));
if (adb == NULL) if (adb == NULL)
return (ISC_R_NOMEMORY); return (ISC_R_NOMEMORY);
@@ -2191,13 +2022,8 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
adb->aimp = NULL; adb->aimp = NULL;
adb->afmp = NULL; adb->afmp = NULL;
adb->task = NULL; adb->task = NULL;
adb->timer = NULL;
#ifdef LRU_DEBUG
adb->dump_timer = NULL;
#endif
adb->mctx = NULL; adb->mctx = NULL;
adb->view = view; adb->view = view;
adb->timermgr = timermgr;
adb->taskmgr = taskmgr; adb->taskmgr = taskmgr;
adb->next_cleanbucket = 0; adb->next_cleanbucket = 0;
ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL,
@@ -2208,20 +2034,6 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
adb->overmem = ISC_FALSE; adb->overmem = ISC_FALSE;
ISC_LIST_INIT(adb->whenshutdown); ISC_LIST_INIT(adb->whenshutdown);
#ifdef LRU_DEBUG
/* for debug */
adb->nname = 0;
adb->nname_total = 0;
adb->nentry = 0;
adb->nentry_total = 0;
adb->stale_purge = 0;
adb->stale_scan = 0;
adb->stale_expire = 0;
adb->stale_lru = 0;
adb->nameuses = 0;
adb->entryuses = 0;
#endif
isc_mem_attach(mem, &adb->mctx); isc_mem_attach(mem, &adb->mctx);
result = isc_mutex_init(&adb->lock); result = isc_mutex_init(&adb->lock);
@@ -2287,41 +2099,12 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
#undef MPINIT #undef MPINIT
/* /*
* Allocate a timer and a task for our periodic cleanup. * Allocate an internal task.
*/ */
result = isc_task_create(adb->taskmgr, 0, &adb->task); result = isc_task_create(adb->taskmgr, 0, &adb->task);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto fail3; goto fail3;
isc_task_setname(adb->task, "ADB", adb); isc_task_setname(adb->task, "ADB", adb);
/*
* XXXMLG When this is changed to be a config file option,
*/
isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0);
result = isc_timer_create(adb->timermgr, isc_timertype_once,
NULL, &adb->tick_interval, adb->task,
timer_cleanup, adb, &adb->timer);
if (result != ISC_R_SUCCESS)
goto fail3;
#ifdef LRU_DEBUG
{
isc_interval_t interval;
interval.seconds = DUMP_INTERVAL;
interval.nanoseconds = 0;
RUNTIME_CHECK(isc_time_nowplusinterval(&adb->dump_time,
&interval) ==
ISC_R_SUCCESS);
result = isc_timer_create(adb->timermgr, isc_timertype_once,
&adb->dump_time, NULL, adb->task,
timer_dump, adb, &adb->dump_timer);
}
#endif
DP(ISC_LOG_DEBUG(5), "cleaning interval for adb: "
"%u buckets every %u seconds, %u buckets in system, %u cl.interval",
CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD);
/* /*
* Normal return. * Normal return.
@@ -2333,8 +2116,6 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr,
fail3: fail3:
if (adb->task != NULL) if (adb->task != NULL)
isc_task_detach(&adb->task); isc_task_detach(&adb->task);
if (adb->timer != NULL)
isc_timer_detach(&adb->timer);
/* clean up entrylocks */ /* clean up entrylocks */
DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS); DESTROYMUTEXBLOCK(adb->entrylocks, NBUCKETS);
@@ -2578,18 +2359,10 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action,
adbname->flags |= NAME_GLUE_OK; adbname->flags |= NAME_GLUE_OK;
if (FIND_STARTATZONE(find)) if (FIND_STARTATZONE(find))
adbname->flags |= NAME_STARTATZONE; adbname->flags |= NAME_STARTATZONE;
#ifdef LRU_DEBUG
adb->nname++; /* XXX: omit ADB lock for brevity */
adb->nname_total++;
#endif
} else { } else {
/* Move this name forward in the LRU list */ /* Move this name forward in the LRU list */
ISC_LIST_UNLINK(adb->names[bucket], adbname, plink); ISC_LIST_UNLINK(adb->names[bucket], adbname, plink);
ISC_LIST_PREPEND(adb->names[bucket], adbname, plink); ISC_LIST_PREPEND(adb->names[bucket], adbname, plink);
#ifdef LRU_DEBUG
adb->nameuses++;
#endif
} }
adbname->last_used = now; adbname->last_used = now;
@@ -3813,15 +3586,6 @@ water(void *arg, int mark) {
LOCK(&adb->overmemlock); LOCK(&adb->overmemlock);
if (adb->overmem != overmem) { if (adb->overmem != overmem) {
adb->overmem = overmem; adb->overmem = overmem;
#if 0 /* we don't need this timer for the new cleaning policy. */
if (overmem) {
isc_interval_t interval;
isc_interval_set(&interval, 0, 1);
(void)isc_timer_reset(adb->timer, isc_timertype_once,
NULL, &interval, ISC_TRUE);
}
#endif
isc_mem_waterack(adb->mctx, mark); isc_mem_waterack(adb->mctx, mark);
} }
UNLOCK(&adb->overmemlock); UNLOCK(&adb->overmemlock);
@@ -3845,47 +3609,3 @@ dns_adb_setadbsize(dns_adb_t *adb, isc_uint32_t size) {
else else
isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater); isc_mem_setwater(adb->mctx, water, adb, hiwater, lowater);
} }
#ifdef LRU_DEBUG
/*
* Periodic dumping of the internal state of the statistics.
* This will dump the cache contents, uses, record types, etc.
*/
static void
timer_dump(isc_task_t *task, isc_event_t *ev) {
dns_adb_t *adb;
isc_interval_t interval;
isc_time_t nexttime;
UNUSED(task);
adb = ev->ev_arg;
INSIST(DNS_ADB_VALID(adb));
LOCK(&adb->lock);
if (adb->nname > 0 || adb->nentry > 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_ADB, ISC_LOG_INFO,
"ADB memory usage %p: mem inuse %lu, "
"%u/%u names, %u/%u entries, "
"purge/scan=%u(%u,%u)/%u, overmem=%d",
adb, (unsigned long)isc_mem_inuse(adb->mctx),
adb->nname, adb->nname_total,
adb->nentry, adb->nentry_total,
adb->stale_purge, adb->stale_expire,
adb->stale_lru, adb->stale_scan, adb->overmem);
}
interval.seconds = DUMP_INTERVAL;
interval.nanoseconds = 0;
RUNTIME_CHECK(isc_time_add(&adb->dump_time, &interval, &nexttime) ==
ISC_R_SUCCESS); /* XXX: this is not always true */
adb->dump_time = nexttime;
(void)isc_timer_reset(adb->dump_timer, isc_timertype_once,
&adb->dump_time, NULL, ISC_FALSE);
UNLOCK(&adb->lock);
isc_event_free(&ev);
}
#endif

View File

@@ -15,13 +15,14 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: cache.c,v 1.78 2008/02/07 23:46:54 tbox Exp $ */ /* $Id: cache.c,v 1.79 2008/05/01 18:23:07 jinmei Exp $ */
/*! \file */ /*! \file */
#include <config.h> #include <config.h>
#include <isc/mem.h> #include <isc/mem.h>
#include <isc/string.h>
#include <isc/task.h> #include <isc/task.h>
#include <isc/time.h> #include <isc/time.h>
#include <isc/timer.h> #include <isc/timer.h>
@@ -39,24 +40,24 @@
#include <dns/rdatasetiter.h> #include <dns/rdatasetiter.h>
#include <dns/result.h> #include <dns/result.h>
#define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$') #define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$')
#define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC) #define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC)
/*! /*!
* Control incremental cleaning. * Control incremental cleaning.
* DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize(). * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
* See also DNS_CACHE_CLEANERINCREMENT * See also DNS_CACHE_CLEANERINCREMENT
*/ */
#define DNS_CACHE_MINSIZE 2097152 /*%< Bytes. 2097152 = 2 MB */ #define DNS_CACHE_MINSIZE 2097152 /*%< Bytes. 2097152 = 2 MB */
/*! /*!
* Control incremental cleaning. * Control incremental cleaning.
* CLEANERINCREMENT is how many nodes are examined in one pass. * CLEANERINCREMENT is how many nodes are examined in one pass.
* See also DNS_CACHE_MINSIZE * See also DNS_CACHE_MINSIZE
*/ */
#define DNS_CACHE_CLEANERINCREMENT 1000U /*%< Number of nodes. */ #define DNS_CACHE_CLEANERINCREMENT 1000U /*%< Number of nodes. */
/*** /***
*** Types *** Types
***/ ***/
/* /*
@@ -67,40 +68,48 @@
typedef struct cache_cleaner cache_cleaner_t; typedef struct cache_cleaner cache_cleaner_t;
typedef enum { typedef enum {
cleaner_s_idle, /*%< Waiting for cleaning-interval to expire. */ cleaner_s_idle, /*%< Waiting for cleaning-interval to expire. */
cleaner_s_busy, /*%< Currently cleaning. */ cleaner_s_busy, /*%< Currently cleaning. */
cleaner_s_done /*%< Freed enough memory after being overmem. */ cleaner_s_done /*%< Freed enough memory after being overmem. */
} cleaner_state_t; } cleaner_state_t;
/* /*
* Convenience macros for comprehensive assertion checking. * Convenience macros for comprehensive assertion checking.
*/ */
#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle) #define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy) (c)->resched_event != NULL)
#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
(c)->iterator != NULL && \
(c)->resched_event == NULL)
/*% /*%
* Accesses to a cache cleaner object are synchronized through * Accesses to a cache cleaner object are synchronized through
* task/event serialization, or locked from the cache object. * task/event serialization, or locked from the cache object.
*/ */
struct cache_cleaner { struct cache_cleaner {
isc_mutex_t lock; isc_mutex_t lock;
/*%< /*%<
* Locks overmem. Note: never allocate memory * Locks overmem_event, overmem. Note: never allocate memory
* while holding this lock - that could lead to deadlock since * while holding this lock - that could lead to deadlock since
* the lock is take by water() which is called from the memory * the lock is take by water() which is called from the memory
* allocator. * allocator.
*/ */
dns_cache_t *cache; dns_cache_t *cache;
isc_task_t *task; isc_task_t *task;
unsigned int cleaning_interval; /*% The cleaning-interval from unsigned int cleaning_interval; /*% The cleaning-interval from
named.conf, in seconds. */ named.conf, in seconds. */
isc_timer_t *cleaning_timer; isc_timer_t *cleaning_timer;
isc_event_t *resched_event; /*% Sent by cleaner task to
itself to reschedule */
isc_event_t *overmem_event;
unsigned int increment; /*% Number of names to dns_dbiterator_t *iterator;
unsigned int increment; /*% Number of names to
clean in one increment */ clean in one increment */
cleaner_state_t state; /*% Idle/Busy. */ cleaner_state_t state; /*% Idle/Busy. */
isc_boolean_t overmem; /*% The cache is in an overmem state. */ isc_boolean_t overmem; /*% The cache is in an overmem state. */
isc_boolean_t replaceiterator;
}; };
/*% /*%
@@ -109,34 +118,28 @@ struct cache_cleaner {
struct dns_cache { struct dns_cache {
/* Unlocked. */ /* Unlocked. */
unsigned int magic; unsigned int magic;
isc_mutex_t lock; isc_mutex_t lock;
isc_mutex_t filelock; isc_mutex_t filelock;
isc_mem_t *mctx; isc_mem_t *mctx;
/* Locked by 'lock'. */ /* Locked by 'lock'. */
int references; int references;
int live_tasks; int live_tasks;
dns_rdataclass_t rdclass; dns_rdataclass_t rdclass;
dns_db_t *db; dns_db_t *db;
cache_cleaner_t cleaner; cache_cleaner_t cleaner;
char *db_type; char *db_type;
int db_argc; int db_argc;
char **db_argv; char **db_argv;
/* Locked by 'filelock'. */ /* Locked by 'filelock'. */
char * filename; char *filename;
/* Access to the on-disk cache file is also locked by 'filelock'. */ /* Access to the on-disk cache file is also locked by 'filelock'. */
#ifdef LRU_DEBUG
#define DUMP_INTERVAL 30 /* seconds */
isc_timer_t *dump_timer; /* for test */
isc_time_t dump_time; /* for test */
#endif
}; };
/*** /***
*** Functions *** Functions
***/ ***/
static isc_result_t static isc_result_t
@@ -146,89 +149,14 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
static void static void
cleaning_timer_action(isc_task_t *task, isc_event_t *event); cleaning_timer_action(isc_task_t *task, isc_event_t *event);
static void
incremental_cleaning_action(isc_task_t *task, isc_event_t *event);
static void static void
cleaner_shutdown_action(isc_task_t *task, isc_event_t *event); cleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
#ifdef LRU_DEBUG
static void static void
timer_dump(isc_task_t *task, isc_event_t *event); overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
#endif
#if 0 /* This is no longer needed. When LRU_TEST is cleaned up,
* this should be as well. XXXMLG */
/*%
* Work out how many nodes can be cleaned in the time between two
* requests to the nameserver. Smooth the resulting number and use
* it as a estimate for the number of nodes to be cleaned in the next
* iteration.
*/
static void
adjust_increment(cache_cleaner_t *cleaner, unsigned int remaining,
isc_time_t *start)
{
isc_time_t end;
isc_uint64_t usecs;
isc_uint64_t new;
unsigned int pps = dns_pps;
unsigned int interval;
unsigned int names;
/*
* Tune for minumum of 100 packets per second (pps).
*/
if (pps < 100)
pps = 100;
isc_time_now(&end);
interval = 1000000 / pps; /* Interval between packets in usecs. */
if (interval == 0)
interval = 1;
INSIST(cleaner->increment >= remaining);
names = cleaner->increment - remaining;
usecs = isc_time_microdiff(&end, start);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1), "adjust_increment interval=%u "
"names=%u usec=%" ISC_PLATFORM_QUADFORMAT "u",
interval, names, usecs);
if (usecs == 0) {
/*
* If we cleaned all the nodes in unmeasurable time
* double the number of nodes to be cleaned next time.
*/
if (names == cleaner->increment) {
cleaner->increment *= 2;
if (cleaner->increment > DNS_CACHE_CLEANERINCREMENT)
cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
"%p:new cleaner->increment = %u\n",
cleaner, cleaner->increment);
}
return;
}
new = (names * interval);
new /= (usecs * 2);
if (new == 0)
new = 1;
/* Smooth */
new = (new + cleaner->increment * 7) / 8;
if (new > DNS_CACHE_CLEANERINCREMENT)
new = DNS_CACHE_CLEANERINCREMENT;
cleaner->increment = (unsigned int)new;
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1), "%p:new cleaner->increment = %u\n",
cleaner, cleaner->increment);
}
#endif
static inline isc_result_t static inline isc_result_t
cache_create_db(dns_cache_t *cache, dns_db_t **db) { cache_create_db(dns_cache_t *cache, dns_db_t **db) {
@@ -306,7 +234,16 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
cache->magic = CACHE_MAGIC; cache->magic = CACHE_MAGIC;
result = cache_cleaner_init(cache, taskmgr, timermgr, &cache->cleaner); /*
* RBT-type cache DB has its own mechanism of cache cleaning and doesn't
* need the control of the generic cleaner.
*/
if (strcmp(db_type, "rbt") == 0)
result = cache_cleaner_init(cache, NULL, NULL, &cache->cleaner);
else {
result = cache_cleaner_init(cache, taskmgr, timermgr,
&cache->cleaner);
}
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_db; goto cleanup_db;
@@ -347,6 +284,15 @@ cache_free(dns_cache_t *cache) {
if (cache->cleaner.task != NULL) if (cache->cleaner.task != NULL)
isc_task_detach(&cache->cleaner.task); isc_task_detach(&cache->cleaner.task);
if (cache->cleaner.overmem_event != NULL)
isc_event_free(&cache->cleaner.overmem_event);
if (cache->cleaner.resched_event != NULL)
isc_event_free(&cache->cleaner.resched_event);
if (cache->cleaner.iterator != NULL)
dns_dbiterator_destroy(&cache->cleaner.iterator);
DESTROYLOCK(&cache->cleaner.lock); DESTROYLOCK(&cache->cleaner.lock);
if (cache->filename) { if (cache->filename) {
@@ -548,9 +494,6 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, cache_cleaner_t *cleaner) isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
{ {
isc_result_t result; isc_result_t result;
#ifdef LRU_DEBUG
isc_interval_t interval;
#endif
result = isc_mutex_init(&cleaner->lock); result = isc_mutex_init(&cleaner->lock);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
@@ -559,10 +502,19 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
cleaner->increment = DNS_CACHE_CLEANERINCREMENT; cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
cleaner->state = cleaner_s_idle; cleaner->state = cleaner_s_idle;
cleaner->cache = cache; cleaner->cache = cache;
cleaner->iterator = NULL;
cleaner->overmem = ISC_FALSE; cleaner->overmem = ISC_FALSE;
cleaner->replaceiterator = ISC_FALSE;
cleaner->task = NULL; cleaner->task = NULL;
cleaner->cleaning_timer = NULL; cleaner->cleaning_timer = NULL;
cleaner->resched_event = NULL;
cleaner->overmem_event = NULL;
result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
&cleaner->iterator);
if (result != ISC_R_SUCCESS)
goto cleanup;
if (taskmgr != NULL && timermgr != NULL) { if (taskmgr != NULL && timermgr != NULL) {
result = isc_task_create(taskmgr, 1, &cleaner->task); result = isc_task_create(taskmgr, 1, &cleaner->task);
@@ -588,8 +540,7 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
cleaner->cleaning_interval = 0; /* Initially turned off. */ cleaner->cleaning_interval = 0; /* Initially turned off. */
result = isc_timer_create(timermgr, isc_timertype_inactive, result = isc_timer_create(timermgr, isc_timertype_inactive,
NULL, NULL, NULL, NULL, cleaner->task,
cleaner->task,
cleaning_timer_action, cleaner, cleaning_timer_action, cleaner,
&cleaner->cleaning_timer); &cleaner->cleaning_timer);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
@@ -600,33 +551,122 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
goto cleanup; goto cleanup;
} }
#ifdef LRU_DEBUG cleaner->resched_event =
interval.seconds = DUMP_INTERVAL; isc_event_allocate(cache->mctx, cleaner,
interval.nanoseconds = 0; DNS_EVENT_CACHECLEAN,
RUNTIME_CHECK(isc_time_nowplusinterval(&cache->dump_time, incremental_cleaning_action,
&interval) == cleaner, sizeof(isc_event_t));
ISC_R_SUCCESS); if (cleaner->resched_event == NULL) {
cache->dump_timer = NULL; result = ISC_R_NOMEMORY;
result = isc_timer_create(timermgr, isc_timertype_once, goto cleanup;
&cache->dump_time, NULL, }
cleaner->task, timer_dump,
cache, &cache->dump_timer); cleaner->overmem_event =
RUNTIME_CHECK(result == ISC_R_SUCCESS); /* for brevity */ isc_event_allocate(cache->mctx, cleaner,
#endif DNS_EVENT_CACHEOVERMEM,
overmem_cleaning_action,
cleaner, sizeof(isc_event_t));
if (cleaner->overmem_event == NULL) {
result = ISC_R_NOMEMORY;
goto cleanup;
}
} }
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
cleanup: cleanup:
if (cleaner->overmem_event != NULL)
isc_event_free(&cleaner->overmem_event);
if (cleaner->resched_event != NULL)
isc_event_free(&cleaner->resched_event);
if (cleaner->cleaning_timer != NULL) if (cleaner->cleaning_timer != NULL)
isc_timer_detach(&cleaner->cleaning_timer); isc_timer_detach(&cleaner->cleaning_timer);
if (cleaner->task != NULL) if (cleaner->task != NULL)
isc_task_detach(&cleaner->task); isc_task_detach(&cleaner->task);
if (cleaner->iterator != NULL)
dns_dbiterator_destroy(&cleaner->iterator);
DESTROYLOCK(&cleaner->lock); DESTROYLOCK(&cleaner->lock);
fail: fail:
return (result); return (result);
} }
static void
begin_cleaning(cache_cleaner_t *cleaner) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(CLEANER_IDLE(cleaner));
/*
* Create an iterator, if it does not already exist, and
* position it at the beginning of the cache.
*/
if (cleaner->iterator == NULL)
result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
&cleaner->iterator);
if (result != ISC_R_SUCCESS)
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
"cache cleaner could not create "
"iterator: %s", isc_result_totext(result));
else {
dns_dbiterator_setcleanmode(cleaner->iterator, ISC_TRUE);
result = dns_dbiterator_first(cleaner->iterator);
}
if (result != ISC_R_SUCCESS) {
/*
* If the result is ISC_R_NOMORE, the database is empty,
* so there is nothing to be cleaned.
*/
if (result != ISC_R_NOMORE && cleaner->iterator != NULL) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"cache cleaner: "
"dns_dbiterator_first() failed: %s",
dns_result_totext(result));
dns_dbiterator_destroy(&cleaner->iterator);
} else if (cleaner->iterator != NULL) {
result = dns_dbiterator_pause(cleaner->iterator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
}
} else {
/*
* Pause the iterator to free its lock.
*/
result = dns_dbiterator_pause(cleaner->iterator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
"begin cache cleaning, mem inuse %lu",
(unsigned long)isc_mem_inuse(cleaner->cache->mctx));
cleaner->state = cleaner_s_busy;
isc_task_send(cleaner->task, &cleaner->resched_event);
}
return;
}
static void
end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
isc_result_t result;
REQUIRE(CLEANER_BUSY(cleaner));
REQUIRE(event != NULL);
result = dns_dbiterator_pause(cleaner->iterator);
if (result != ISC_R_SUCCESS)
dns_dbiterator_destroy(&cleaner->iterator);
dns_cache_setcleaninginterval(cleaner->cache,
cleaner->cleaning_interval);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
(unsigned long)isc_mem_inuse(cleaner->cache->mctx));
cleaner->state = cleaner_s_idle;
cleaner->resched_event = event;
}
/* /*
* This is run once for every cache-cleaning-interval as defined in named.conf. * This is run once for every cache-cleaning-interval as defined in named.conf.
*/ */
@@ -643,9 +683,174 @@ cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
ISC_LOG_DEBUG(1), "cache cleaning timer fired, " ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
"cleaner state = %d", cleaner->state); "cleaner state = %d", cleaner->state);
if (cleaner->state == cleaner_s_idle)
begin_cleaning(cleaner);
isc_event_free(&event); isc_event_free(&event);
} }
/*
* This is called when the cache either surpasses its upper limit
* or shrinks beyond its lower limit.
*/
static void
overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
cache_cleaner_t *cleaner = event->ev_arg;
isc_boolean_t want_cleaning = ISC_FALSE;
UNUSED(task);
INSIST(task == cleaner->task);
INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
INSIST(cleaner->overmem_event == NULL);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
"overmem = %d, state = %d", cleaner->overmem,
cleaner->state);
LOCK(&cleaner->lock);
if (cleaner->overmem) {
if (cleaner->state == cleaner_s_idle)
want_cleaning = ISC_TRUE;
} else {
if (cleaner->state == cleaner_s_busy)
/*
* end_cleaning() can't be called here because
* then both cleaner->overmem_event and
* cleaner->resched_event will point to this
* event. Set the state to done, and then
* when the incremental_cleaning_action() event
* is posted, it will handle the end_cleaning.
*/
cleaner->state = cleaner_s_done;
}
cleaner->overmem_event = event;
UNLOCK(&cleaner->lock);
if (want_cleaning)
begin_cleaning(cleaner);
}
/*
* Do incremental cleaning.
*/
static void
incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
cache_cleaner_t *cleaner = event->ev_arg;
isc_result_t result;
unsigned int n_names;
isc_time_t start;
UNUSED(task);
INSIST(task == cleaner->task);
INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
if (cleaner->state == cleaner_s_done) {
cleaner->state = cleaner_s_busy;
end_cleaning(cleaner, event);
LOCK(&cleaner->cache->lock);
LOCK(&cleaner->lock);
if (cleaner->replaceiterator) {
dns_dbiterator_destroy(&cleaner->iterator);
(void) dns_db_createiterator(cleaner->cache->db,
ISC_FALSE,
&cleaner->iterator);
cleaner->replaceiterator = ISC_FALSE;
}
UNLOCK(&cleaner->lock);
UNLOCK(&cleaner->cache->lock);
return;
}
INSIST(CLEANER_BUSY(cleaner));
n_names = cleaner->increment;
REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
isc_time_now(&start);
while (n_names-- > 0) {
dns_dbnode_t *node = NULL;
result = dns_dbiterator_current(cleaner->iterator, &node,
NULL);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"cache cleaner: dns_dbiterator_current() "
"failed: %s", dns_result_totext(result));
end_cleaning(cleaner, event);
return;
}
/*
* The node was not needed, but was required by
* dns_dbiterator_current(). Give up its reference.
*/
dns_db_detachnode(cleaner->cache->db, &node);
/*
* Step to the next node.
*/
result = dns_dbiterator_next(cleaner->iterator);
if (result != ISC_R_SUCCESS) {
/*
* Either the end was reached (ISC_R_NOMORE) or
* some error was signaled. If the cache is still
* overmem and no error was encountered,
* keep trying to clean it, otherwise stop cleaning.
*/
if (result != ISC_R_NOMORE)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"cache cleaner: "
"dns_dbiterator_next() "
"failed: %s",
dns_result_totext(result));
else if (cleaner->overmem) {
result = dns_dbiterator_first(cleaner->
iterator);
if (result == ISC_R_SUCCESS) {
isc_log_write(dns_lctx,
DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1),
"cache cleaner: "
"still overmem, "
"reset and try again");
continue;
}
}
end_cleaning(cleaner, event);
return;
}
}
/*
* We have successfully performed a cleaning increment but have
* not gone through the entire cache. Free the iterator locks
* and reschedule another batch. If it fails, just try to continue
* anyway.
*/
result = dns_dbiterator_pause(cleaner->iterator);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
"mem inuse %lu, sleeping", cleaner->increment,
(unsigned long)isc_mem_inuse(cleaner->cache->mctx));
isc_task_send(task, &event);
INSIST(CLEANER_BUSY(cleaner));
return;
}
/* /*
* Do immediate cleaning. * Do immediate cleaning.
*/ */
@@ -714,6 +919,10 @@ water(void *arg, int mark) {
isc_mem_waterack(cache->mctx, mark); isc_mem_waterack(cache->mctx, mark);
} }
if (cache->cleaner.overmem_event != NULL)
isc_task_send(cache->cleaner.task,
&cache->cleaner.overmem_event);
UNLOCK(&cache->cleaner.lock); UNLOCK(&cache->cleaner.lock);
} }
@@ -731,8 +940,8 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
if (size != 0 && size < DNS_CACHE_MINSIZE) if (size != 0 && size < DNS_CACHE_MINSIZE)
size = DNS_CACHE_MINSIZE; size = DNS_CACHE_MINSIZE;
hiwater = size - (size >> 3); /* Approximately 7/8ths. */ hiwater = size - (size >> 3); /* Approximately 7/8ths. */
lowater = size - (size >> 2); /* Approximately 3/4ths. */ lowater = size - (size >> 2); /* Approximately 3/4ths. */
/* /*
* If the cache was overmem and cleaning, but now with the new limits * If the cache was overmem and cleaning, but now with the new limits
@@ -767,6 +976,11 @@ cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
INSIST(task == cache->cleaner.task); INSIST(task == cache->cleaner.task);
INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN); INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
if (CLEANER_BUSY(&cache->cleaner))
end_cleaning(&cache->cleaner, event);
else
isc_event_free(&event);
LOCK(&cache->lock); LOCK(&cache->lock);
cache->live_tasks--; cache->live_tasks--;
@@ -783,10 +997,6 @@ cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
if (cache->cleaner.cleaning_timer != NULL) if (cache->cleaner.cleaning_timer != NULL)
isc_timer_detach(&cache->cleaner.cleaning_timer); isc_timer_detach(&cache->cleaner.cleaning_timer);
#ifdef LRU_DEBUG
isc_timer_detach(&cache->dump_timer);
#endif
/* Make sure we don't reschedule anymore. */ /* Make sure we don't reschedule anymore. */
(void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL); (void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
@@ -794,8 +1004,6 @@ cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
if (should_free) if (should_free)
cache_free(cache); cache_free(cache);
isc_event_free(&event);
} }
isc_result_t isc_result_t
@@ -810,9 +1018,14 @@ dns_cache_flush(dns_cache_t *cache) {
LOCK(&cache->lock); LOCK(&cache->lock);
LOCK(&cache->cleaner.lock); LOCK(&cache->cleaner.lock);
if (cache->cleaner.state == cleaner_s_idle) { if (cache->cleaner.state == cleaner_s_idle) {
/* XXXMLG do something */ if (cache->cleaner.iterator != NULL)
} else if (cache->cleaner.state == cleaner_s_busy) { dns_dbiterator_destroy(&cache->cleaner.iterator);
/* XXXMLG do something else */ (void) dns_db_createiterator(db, ISC_FALSE,
&cache->cleaner.iterator);
} else {
if (cache->cleaner.state == cleaner_s_busy)
cache->cleaner.state = cleaner_s_done;
cache->cleaner.replaceiterator = ISC_TRUE;
} }
dns_db_detach(&cache->db); dns_db_detach(&cache->db);
cache->db = db; cache->db = db;
@@ -874,33 +1087,3 @@ dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
dns_db_detach(&db); dns_db_detach(&db);
return (result); return (result);
} }
#ifdef LRU_DEBUG
static void
timer_dump(isc_task_t *task, isc_event_t *event) {
dns_cache_t *cache;
isc_interval_t interval;
isc_time_t nexttime;
UNUSED(task);
cache = event->ev_arg;
INSIST(VALID_CACHE(cache));
#ifdef LRU_DEBUG
/* XXX: abuse existing overmem method */
dns_db_overmem(cache->db, (isc_boolean_t)-1);
#endif
interval.seconds = DUMP_INTERVAL;
interval.nanoseconds = 0;
RUNTIME_CHECK(isc_time_add(&cache->dump_time, &interval, &nexttime) ==
ISC_R_SUCCESS); /* XXX: this is not always true */
cache->dump_time = nexttime;
(void)isc_timer_reset(cache->dump_timer, isc_timertype_once,
&cache->dump_time, NULL, ISC_FALSE);
isc_event_free(&event);
}
#endif

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: rbtdb.c,v 1.259 2008/04/23 21:32:01 each Exp $ */ /* $Id: rbtdb.c,v 1.260 2008/05/01 18:23:07 jinmei Exp $ */
/*! \file */ /*! \file */
@@ -275,8 +275,6 @@ typedef ISC_LIST(dns_rbtnode_t) rbtnodelist_t;
#define RDATASET_ATTR_NXDOMAIN 0x0010 #define RDATASET_ATTR_NXDOMAIN 0x0010
#define RDATASET_ATTR_RESIGN 0x0020 #define RDATASET_ATTR_RESIGN 0x0020
#define RDATASET_ATTR_STATCOUNT 0x0040 #define RDATASET_ATTR_STATCOUNT 0x0040
#define RDATASET_ATTR_CACHE 0x1000 /* for debug */
#define RDATASET_ATTR_CANCELED 0x2000 /* for debug */
typedef struct acache_cbarg { typedef struct acache_cbarg {
dns_rdatasetadditional_t type; dns_rdatasetadditional_t type;
@@ -352,33 +350,6 @@ typedef struct rbtdb_version {
typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t; typedef ISC_LIST(rbtdb_version_t) rbtdb_versionlist_t;
#ifdef LRU_DEBUG
/* statistics info for testing */
struct cachestat {
unsigned int cache_total;
int cache_current;
unsigned int ncache_total;
int ncache_current;
unsigned int a_total;
int a_current;
unsigned int aaaa_total;
int aaaa_current;
unsigned int ns_total;
int ns_current;
unsigned int ptr_total;
int ptr_current;
unsigned int glue_total;
int glue_current;
unsigned int additional_total;
int additional_current;
unsigned int stale_purge;
unsigned int stale_scan;
unsigned int stale_expire;
unsigned int stale_lru;
};
#endif
typedef enum { typedef enum {
dns_db_insecure, dns_db_insecure,
dns_db_partial, dns_db_partial,
@@ -437,9 +408,6 @@ typedef struct {
/* Unlocked */ /* Unlocked */
unsigned int quantum; unsigned int quantum;
#ifdef LRU_DEBUG
struct cachestat cachestat;
#endif
} dns_rbtdb_t; } dns_rbtdb_t;
#define RBTDB_ATTR_LOADED 0x01 #define RBTDB_ATTR_LOADED 0x01
@@ -922,41 +890,6 @@ free_rbtdb(dns_rbtdb_t *rbtdb, isc_boolean_t log, isc_event_t *event) {
if (rbtdb->task != NULL) if (rbtdb->task != NULL)
isc_task_detach(&rbtdb->task); isc_task_detach(&rbtdb->task);
#ifdef LRU_DEBUG
/* Experimental logging about memory usage */
if (IS_CACHE(rbtdb) && rbtdb->common.rdclass == dns_rdataclass_in) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_INFO,
"cache DB %p: mem inuse %lu, XXX node, "
"%d/%u current/total cache, %d/%u neg, %d/%u A, %d/%u AAAA, "
"%d/%u NS, %d/%u PTR, %d/%u glue, "
"%d/%u additional, purge/scan=%u(%u expiry, %u lru)/%u, "
"overmem=%d",
rbtdb,
(unsigned long)isc_mem_inuse(rbtdb->common.mctx),
rbtdb->cachestat.cache_current, rbtdb->cachestat.cache_total,
rbtdb->cachestat.ncache_current, rbtdb->cachestat.ncache_total,
rbtdb->cachestat.a_current, rbtdb->cachestat.a_total,
rbtdb->cachestat.aaaa_current, rbtdb->cachestat.aaaa_total,
rbtdb->cachestat.ns_current, rbtdb->cachestat.ns_total,
rbtdb->cachestat.ptr_current, rbtdb->cachestat.ptr_total,
rbtdb->cachestat.glue_current, rbtdb->cachestat.glue_total,
rbtdb->cachestat.additional_current,
rbtdb->cachestat.additional_total,
rbtdb->cachestat.stale_purge, rbtdb->cachestat.stale_expire,
rbtdb->cachestat.stale_lru, rbtdb->cachestat.stale_scan,
rbtdb->overmem);
INSIST(rbtdb->cachestat.cache_current == 0);
INSIST(rbtdb->cachestat.ncache_current == 0);
INSIST(rbtdb->cachestat.a_current == 0);
INSIST(rbtdb->cachestat.aaaa_current == 0);
INSIST(rbtdb->cachestat.ns_current == 0);
INSIST(rbtdb->cachestat.ptr_current == 0);
INSIST(rbtdb->cachestat.glue_current == 0);
INSIST(rbtdb->cachestat.additional_current == 0);
}
#endif
RBTDB_DESTROYLOCK(&rbtdb->lock); RBTDB_DESTROYLOCK(&rbtdb->lock);
rbtdb->common.magic = 0; rbtdb->common.magic = 0;
rbtdb->common.impmagic = 0; rbtdb->common.impmagic = 0;
@@ -1231,69 +1164,6 @@ free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset)
update_rrsetstats(rbtdb, rdataset, ISC_FALSE); update_rrsetstats(rbtdb, rdataset, ISC_FALSE);
} }
#ifdef LRU_DEBUG
/*
* for debug: statistics update.
* Nothing in this block should have any side-effects.
*/
if (EXISTS(rdataset) &&
(rdataset->attributes & RDATASET_ATTR_CACHE) != 0) {
rbtdb->cachestat.cache_current--;
if ((rdataset->attributes & RDATASET_ATTR_CANCELED) != 0)
rbtdb->cachestat.cache_total--;
if (RBTDB_RDATATYPE_BASE(rdataset->type) == 0) {
rbtdb->cachestat.ncache_current--;
INSIST(rbtdb->cachestat.ncache_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.ncache_total--;
}
if (rdataset->type == dns_rdatatype_a) {
rbtdb->cachestat.a_current--;
INSIST(rbtdb->cachestat.a_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.a_total--;
} else if (rdataset->type == dns_rdatatype_aaaa) {
rbtdb->cachestat.aaaa_current--;
INSIST(rbtdb->cachestat.aaaa_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.aaaa_total--;
} else if (rdataset->type == dns_rdatatype_ptr) {
rbtdb->cachestat.ptr_current--;
INSIST(rbtdb->cachestat.ptr_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.ptr_total--;
} else if (rdataset->type == dns_rdatatype_ns) {
rbtdb->cachestat.ns_current--;
INSIST(rbtdb->cachestat.ns_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.ns_total--;
}
if (rdataset->trust == dns_trust_glue &&
(rdataset->type == dns_rdatatype_a ||
rdataset->type == dns_rdatatype_aaaa)) {
rbtdb->cachestat.glue_current--;
INSIST(rbtdb->cachestat.glue_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.glue_total--;
}
if (rdataset->trust == dns_trust_additional &&
(rdataset->type == dns_rdatatype_a ||
rdataset->type == dns_rdatatype_aaaa)) {
rbtdb->cachestat.additional_current--;
INSIST(rbtdb->cachestat.additional_current >= 0);
if ((rdataset->attributes & RDATASET_ATTR_CANCELED)
!= 0)
rbtdb->cachestat.additional_total--;
}
}
#endif
idx = rdataset->node->locknum; idx = rdataset->node->locknum;
if (ISC_LINK_LINKED(rdataset, lru_link)) if (ISC_LINK_LINKED(rdataset, lru_link))
ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link); ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link);
@@ -4589,40 +4459,8 @@ static void
overmem(dns_db_t *db, isc_boolean_t overmem) { overmem(dns_db_t *db, isc_boolean_t overmem) {
dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
#ifdef LRU_DEBUG if (IS_CACHE(rbtdb))
/* XXX: see cache.c:timer_dump() */
if ((int)overmem == -1) {
if (!IS_CACHE(rbtdb) || db->rdclass != dns_rdataclass_in)
return; /* for brevity */
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_CACHE, ISC_LOG_INFO,
"cache DB %p: mem inuse %lu, %u node, "
"%d/%u current/total cache, %d/%u neg, %d/%u A, %d/%u AAAA, "
"%d/%u NS, %d/%u PTR, %d/%u glue, "
"%d/%u additional, purge/scan=%u(%u expiry, %u lru)/%u, "
"overmem=%d",
rbtdb,
(unsigned long)isc_mem_inuse(rbtdb->common.mctx),
dns_rbt_nodecount(rbtdb->tree),
rbtdb->cachestat.cache_current, rbtdb->cachestat.cache_total,
rbtdb->cachestat.ncache_current, rbtdb->cachestat.ncache_total,
rbtdb->cachestat.a_current, rbtdb->cachestat.a_total,
rbtdb->cachestat.aaaa_current, rbtdb->cachestat.aaaa_total,
rbtdb->cachestat.ns_current, rbtdb->cachestat.ns_total,
rbtdb->cachestat.ptr_current, rbtdb->cachestat.ptr_total,
rbtdb->cachestat.glue_current, rbtdb->cachestat.glue_total,
rbtdb->cachestat.additional_current,
rbtdb->cachestat.additional_total,
rbtdb->cachestat.stale_purge, rbtdb->cachestat.stale_expire,
rbtdb->cachestat.stale_lru, rbtdb->cachestat.stale_scan,
rbtdb->overmem);
return;
}
#endif
if (IS_CACHE(rbtdb)) {
rbtdb->overmem = overmem; rbtdb->overmem = overmem;
}
} }
static void static void
@@ -5019,38 +4857,6 @@ cname_and_other_data(dns_rbtnode_t *node, rbtdb_serial_t serial) {
return (ISC_FALSE); return (ISC_FALSE);
} }
#ifdef LRU_DEBUG
static void
cachestat_update(dns_rbtdb_t *rbtdb, rdatasetheader_t *header) {
if ((header->attributes & RDATASET_ATTR_CACHE) == 0)
return;
/* XXX: don't use lock for brevity */
rbtdb->cachestat.cache_total++;
if (RBTDB_RDATATYPE_BASE(header->type) == 0)
rbtdb->cachestat.ncache_total++;
if (header->type == dns_rdatatype_a)
rbtdb->cachestat.a_total++;
else if (header->type == dns_rdatatype_aaaa)
rbtdb->cachestat.aaaa_total++;
else if (header->type == dns_rdatatype_ns)
rbtdb->cachestat.ns_total++;
else if (header->type == dns_rdatatype_ptr)
rbtdb->cachestat.ptr_total++;
if (header->trust == dns_trust_glue &&
(header->type == dns_rdatatype_a ||
header->type == dns_rdatatype_aaaa)) {
rbtdb->cachestat.glue_total++;
}
if (header->trust == dns_trust_additional &&
(header->type == dns_rdatatype_a ||
header->type == dns_rdatatype_aaaa)) {
rbtdb->cachestat.additional_total++;
}
}
#endif
static isc_result_t static isc_result_t
resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) { resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) {
isc_result_t result; isc_result_t result;
@@ -5166,9 +4972,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* The NXDOMAIN/NODATA(QTYPE=ANY) * The NXDOMAIN/NODATA(QTYPE=ANY)
* is more trusted. * is more trusted.
*/ */
/* set the flag for debug */
newheader->attributes |=
RDATASET_ATTR_CANCELED;
free_rdataset(rbtdb, free_rdataset(rbtdb,
rbtdb->common.mctx, rbtdb->common.mctx,
newheader); newheader);
@@ -5227,7 +5030,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
*/ */
if (rbtversion == NULL && trust < header->trust && if (rbtversion == NULL && trust < header->trust &&
(header->rdh_ttl > now || header_nx)) { (header->rdh_ttl > now || header_nx)) {
newheader->attributes |= RDATASET_ATTR_CANCELED;
free_rdataset(rbtdb, rbtdb->common.mctx, newheader); free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL) if (addedrdataset != NULL)
bind_rdataset(rbtdb, rbtnode, header, now, bind_rdataset(rbtdb, rbtnode, header, now,
@@ -5316,7 +5118,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
header->noqname = newheader->noqname; header->noqname = newheader->noqname;
newheader->noqname = NULL; newheader->noqname = NULL;
} }
newheader->attributes |= RDATASET_ATTR_CANCELED;
free_rdataset(rbtdb, rbtdb->common.mctx, newheader); free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL) if (addedrdataset != NULL)
bind_rdataset(rbtdb, rbtnode, header, now, bind_rdataset(rbtdb, rbtnode, header, now,
@@ -5342,7 +5143,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
header->noqname = newheader->noqname; header->noqname = newheader->noqname;
newheader->noqname = NULL; newheader->noqname = NULL;
} }
newheader->attributes |= RDATASET_ATTR_CANCELED;
free_rdataset(rbtdb, rbtdb->common.mctx, newheader); free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
if (addedrdataset != NULL) if (addedrdataset != NULL)
bind_rdataset(rbtdb, rbtnode, header, now, bind_rdataset(rbtdb, rbtnode, header, now,
@@ -5387,9 +5187,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
* will not leak... for long. * will not leak... for long.
*/ */
isc_heap_insert(rbtdb->heaps[idx], newheader); isc_heap_insert(rbtdb->heaps[idx], newheader);
#ifdef LRU_DEBUG
cachestat_update(rbtdb, newheader);
#endif
} else if (RESIGN(newheader)) } else if (RESIGN(newheader))
resign_insert(rbtdb, idx, newheader); resign_insert(rbtdb, idx, newheader);
} }
@@ -5442,9 +5239,6 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
ISC_LIST_PREPEND(rbtdb->rdatasets[idx], ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
newheader, lru_link); newheader, lru_link);
isc_heap_insert(rbtdb->heaps[idx], newheader); isc_heap_insert(rbtdb->heaps[idx], newheader);
#ifdef LRU_DEBUG
cachestat_update(rbtdb, newheader);
#endif
} else if (RESIGN(newheader)) { } else if (RESIGN(newheader)) {
resign_insert(rbtdb, idx, newheader); resign_insert(rbtdb, idx, newheader);
} }
@@ -5621,45 +5415,6 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
update_rrsetstats(rbtdb, newheader, ISC_TRUE); update_rrsetstats(rbtdb, newheader, ISC_TRUE);
} }
#ifdef LRU_DEBUG
/* for debug: statistics update */
if (IS_CACHE(rbtdb) && rdataset->rdclass == dns_rdataclass_in) {
/* XXX: don't use lock for brevity */
newheader->attributes |= RDATASET_ATTR_CACHE;
rbtdb->cachestat.cache_total++;
rbtdb->cachestat.cache_current++;
if (rdataset->type == 0) {
rbtdb->cachestat.ncache_total++;
rbtdb->cachestat.ncache_current++;
}
if (rdataset->type == dns_rdatatype_a) {
rbtdb->cachestat.a_total++;
rbtdb->cachestat.a_current++;
} else if (rdataset->type == dns_rdatatype_aaaa) {
rbtdb->cachestat.aaaa_total++;
rbtdb->cachestat.aaaa_current++;
} else if (rdataset->type == dns_rdatatype_ns) {
rbtdb->cachestat.ns_total++;
rbtdb->cachestat.ns_current++;
} else if (rdataset->type == dns_rdatatype_ptr) {
rbtdb->cachestat.ptr_total++;
rbtdb->cachestat.ptr_current++;
}
if (rdataset->trust == dns_trust_glue &&
(rdataset->type == dns_rdatatype_a ||
rdataset->type == dns_rdatatype_aaaa)) {
rbtdb->cachestat.glue_total++;
rbtdb->cachestat.glue_current++;
}
if (rdataset->trust == dns_trust_additional &&
(rdataset->type == dns_rdatatype_a ||
rdataset->type == dns_rdatatype_aaaa)) {
rbtdb->cachestat.additional_total++;
rbtdb->cachestat.additional_current++;
}
}
#endif
if (IS_CACHE(rbtdb)) { if (IS_CACHE(rbtdb)) {
if (tree_locked) if (tree_locked)
cleanup_dead_nodes(rbtdb, rbtnode->locknum); cleanup_dead_nodes(rbtdb, rbtnode->locknum);
@@ -7893,7 +7648,6 @@ check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
{ {
rdatasetheader_t *victim; rdatasetheader_t *victim;
isc_boolean_t overmem = rbtdb->overmem; isc_boolean_t overmem = rbtdb->overmem;
int scans = 0; /* for debug */
int victims = 0; int victims = 0;
/* /*
@@ -7902,11 +7656,6 @@ check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
victim = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1); victim = isc_heap_element(rbtdb->heaps[rbtnode->locknum], 1);
if (victim != NULL && victim->rdh_ttl <= now - RBTDB_VIRTUAL) { if (victim != NULL && victim->rdh_ttl <= now - RBTDB_VIRTUAL) {
INSIST(victim->node->locknum == rbtnode->locknum); INSIST(victim->node->locknum == rbtnode->locknum);
#ifdef LRU_DEBUG
/* for debug */
rbtdb->cachestat.stale_expire++;
#endif
victims++; victims++;
set_ttl(rbtdb, victim, 0); set_ttl(rbtdb, victim, 0);
@@ -7935,13 +7684,7 @@ check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
victim = ISC_LIST_TAIL(rbtdb->rdatasets[rbtnode->locknum]); victim = ISC_LIST_TAIL(rbtdb->rdatasets[rbtnode->locknum]);
if (victim != NULL && overmem) { if (victim != NULL && overmem) {
INSIST(victim->node->locknum == rbtnode->locknum); INSIST(victim->node->locknum == rbtnode->locknum);
#ifdef LRU_DEBUG
/* for debug */
rbtdb->cachestat.stale_lru++;
#endif
victims++; victims++;
scans++;
set_ttl(rbtdb, victim, 0); set_ttl(rbtdb, victim, 0);
victim->attributes |= RDATASET_ATTR_STALE; victim->attributes |= RDATASET_ATTR_STALE;
@@ -7962,10 +7705,4 @@ check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
isc_rwlocktype_none); isc_rwlocktype_none);
} }
} }
#ifdef LRU_DEBUG
/* update statistics for debug (no lock for brevity) */
rbtdb->cachestat.stale_scan += scans;
rbtdb->cachestat.stale_purge += victims;
#endif
} }

View File

@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE. * PERFORMANCE OF THIS SOFTWARE.
*/ */
/* $Id: resolver.c,v 1.368 2008/04/10 07:20:11 marka Exp $ */ /* $Id: resolver.c,v 1.369 2008/05/01 18:23:07 jinmei Exp $ */
/*! \file */ /*! \file */
@@ -353,11 +353,7 @@ struct dns_resolver {
isc_timer_t * spillattimer; isc_timer_t * spillattimer;
isc_boolean_t zero_no_soa_ttl; isc_boolean_t zero_no_soa_ttl;
isc_timer_t * disppooltimer; isc_timer_t * disppooltimer;
#ifdef LRU_DEBUG
#define DUMP_INTERVAL 30 /* seconds */
isc_timer_t * dumptimer;
isc_time_t dump_time;
#endif
/* Locked by lock. */ /* Locked by lock. */
unsigned int references; unsigned int references;
isc_boolean_t exiting; isc_boolean_t exiting;
@@ -373,15 +369,6 @@ struct dns_resolver {
/* Locked by poollock. */ /* Locked by poollock. */
dns_dispatch_t ** dispatchv4pool; dns_dispatch_t ** dispatchv4pool;
dns_dispatch_t ** dispatchv6pool; dns_dispatch_t ** dispatchv6pool;
#ifdef LRU_DEBUG
/* Unlocked: just for debug */
unsigned int extqueries;
unsigned int extqueries_ns;
unsigned int extqueries_soa;
unsigned int extqueries_a;
unsigned int extqueries_aaaa;
#endif
}; };
#define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!') #define RES_MAGIC ISC_MAGIC('R', 'e', 's', '!')
@@ -416,10 +403,6 @@ static isc_result_t ncache_adderesult(dns_message_t *message,
static void validated(isc_task_t *task, isc_event_t *event); static void validated(isc_task_t *task, isc_event_t *event);
static void maybe_destroy(fetchctx_t *fctx); static void maybe_destroy(fetchctx_t *fctx);
#ifdef LRU_DEBUG
static void timer_dump(isc_task_t *task, isc_event_t *ev);
#endif
/*% /*%
* Increment resolver-related statistics counters. * Increment resolver-related statistics counters.
*/ */
@@ -1706,23 +1689,6 @@ resquery_send(resquery_t *query) {
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_message; goto cleanup_message;
#ifdef LRU_DEBUG
res->extqueries++;
switch (fctx->type) {
case dns_rdatatype_ns:
res->extqueries_ns++;
break;
case dns_rdatatype_soa:
res->extqueries_soa++;
break;
case dns_rdatatype_a:
res->extqueries_a++;
break;
case dns_rdatatype_aaaa:
res->extqueries_aaaa++;
break;
}
#endif
query->sends++; query->sends++;
QTRACE("sent"); QTRACE("sent");
@@ -6291,16 +6257,6 @@ destroy(dns_resolver_t *res) {
INSIST(res->nfctx == 0); INSIST(res->nfctx == 0);
#ifdef LRU_DEBUG
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
"destroying resolver %p: external queries "
"total/NS/SOA/A/AAAA=%u/%u/%u/%u/%u",
res, res->extqueries, res->extqueries_ns,
res->extqueries_soa, res->extqueries_a,
res->extqueries_aaaa);
#endif
RES_DESTROYLOCK(&res->poollock); RES_DESTROYLOCK(&res->poollock);
DESTROYLOCK(&res->primelock); DESTROYLOCK(&res->primelock);
DESTROYLOCK(&res->nlock); DESTROYLOCK(&res->nlock);
@@ -6338,10 +6294,6 @@ destroy(dns_resolver_t *res) {
} }
if (res->disppooltimer != NULL) if (res->disppooltimer != NULL)
isc_timer_detach(&res->disppooltimer); isc_timer_detach(&res->disppooltimer);
#ifdef LRU_DEBUG
if (res->dumptimer != NULL)
isc_timer_detach(&res->dumptimer);
#endif
dns_resolver_reset_algorithms(res); dns_resolver_reset_algorithms(res);
dns_resolver_resetmustbesecure(res); dns_resolver_resetmustbesecure(res);
#if USE_ALGLOCK #if USE_ALGLOCK
@@ -6475,15 +6427,6 @@ dns_resolver_create(dns_view_t *view,
res->dispatchv4pool = NULL; res->dispatchv4pool = NULL;
res->dispatchv6pool = NULL; res->dispatchv6pool = NULL;
res->disppooltimer = NULL; res->disppooltimer = NULL;
#ifdef LRU_DEBUG
res->dumptimer = NULL;
res->extqueries = 0;
res->extqueries_ns = 0;
res->extqueries_soa = 0;
res->extqueries_a = 0;
res->extqueries_aaaa = 0;
#endif
res->nbuckets = ntasks; res->nbuckets = ntasks;
res->activebuckets = ntasks; res->activebuckets = ntasks;
res->buckets = isc_mem_get(view->mctx, res->buckets = isc_mem_get(view->mctx,
@@ -6566,22 +6509,6 @@ dns_resolver_create(dns_view_t *view,
result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL, result = isc_timer_create(timermgr, isc_timertype_inactive, NULL, NULL,
task, spillattimer_countdown, res, task, spillattimer_countdown, res,
&res->spillattimer); &res->spillattimer);
#ifdef LRU_DEBUG
{
isc_interval_t interval;
interval.seconds = DUMP_INTERVAL;
interval.nanoseconds = 0;
RUNTIME_CHECK(isc_time_nowplusinterval(&res->dump_time,
&interval) ==
ISC_R_SUCCESS);
result = isc_timer_create(timermgr, isc_timertype_once,
&res->dump_time, NULL, task,
timer_dump, res, &res->dumptimer);
}
#endif
isc_task_detach(&task); isc_task_detach(&task);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_poollock; goto cleanup_poollock;
@@ -7769,38 +7696,3 @@ dns_resolver_createdispatchpool(dns_resolver_t *res, unsigned int ndisps,
return (result); return (result);
} }
#ifdef LRU_DEBUG
static void
timer_dump(isc_task_t *task, isc_event_t *ev) {
dns_resolver_t *res;
isc_interval_t interval;
isc_time_t nexttime;
UNUSED(task);
res = ev->ev_arg;
INSIST(VALID_RESOLVER(res));
if (res->extqueries > 0) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER,
DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO,
"resolver dump %p: external queries "
"total/NS/SOA/A/AAAA=%u/%u/%u/%u/%u",
res, res->extqueries, res->extqueries_ns,
res->extqueries_soa, res->extqueries_a,
res->extqueries_aaaa);
}
interval.seconds = DUMP_INTERVAL;
interval.nanoseconds = 0;
RUNTIME_CHECK(isc_time_add(&res->dump_time, &interval, &nexttime) ==
ISC_R_SUCCESS); /* XXX: this is not always true */
res->dump_time = nexttime;
(void)isc_timer_reset(res->dumptimer, isc_timertype_once,
&res->dump_time, NULL, ISC_FALSE);
isc_event_free(&ev);
}
#endif