/*
- * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: acache.c,v 1.3.2.12 2006/04/27 09:36:45 marka Exp $ */
+/* $Id: acache.c,v 1.3.2.13 2006/05/02 12:55:31 shane Exp $ */
#include <config.h>
unsigned int cleaning_interval; /* The cleaning-interval
from named.conf,
in seconds. */
+
isc_stdtime_t last_cleanup_time; /* The time when the last
- cleanup task completed */
+ cleanup task completed */
isc_timer_t *cleaning_timer;
isc_event_t *resched_event; /* Sent by cleaner task to
state. */
};
+struct dns_acachestats {
+ unsigned int hits;
+ unsigned int queries;
+ unsigned int misses;
+ unsigned int adds;
+ unsigned int deleted;
+ unsigned int cleaned;
+ unsigned int cleaner_runs;
+ unsigned int overmem;
+ unsigned int overmem_nocreates;
+ unsigned int nomem;
+};
+
/*
* The actual acache object.
*/
isc_task_t *task;
isc_event_t cevent;
isc_boolean_t cevent_sent;
+
+ dns_acachestats_t stats;
};
struct dns_acacheentry {
static void acache_cleaner_shutdown_action(isc_task_t *task,
isc_event_t *event);
+/*
+ * acache should be locked. If it is not, the stats can get out of whack,
+ * which is not a big deal for us since this is for debugging / stats
+ */
+static void
+reset_stats(dns_acache_t *acache) {
+ acache->stats.hits = 0;
+ acache->stats.queries = 0;
+ acache->stats.misses = 0;
+ acache->stats.adds = 0;
+ acache->stats.deleted = 0;
+ acache->stats.cleaned = 0;
+ acache->stats.overmem = 0;
+ acache->stats.overmem_nocreates = 0;
+ acache->stats.nomem = 0;
+}
+
/*
* The acache must be locked before calling.
*/
}
dns_acache_detachentry(&cleaner->current_entry);
+ if (cleaner->overmem)
+ acache->stats.overmem++;
+ acache->stats.cleaned += cleaner->ncleaned;
+ acache->stats.cleaner_runs++;
+
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
+ ISC_LOG_NOTICE,
+ "acache %p stats: hits=%d misses=%d queries=%d "
+ "adds=%d deleted=%d "
+ "cleaned=%d cleaner_runs=%d overmem=%d "
+ "overmem_nocreates=%d nomem=%d",
+ acache,
+ acache->stats.hits, acache->stats.misses,
+ acache->stats.queries,
+ acache->stats.adds, acache->stats.deleted,
+ acache->stats.cleaned, acache->stats.cleaner_runs,
+ acache->stats.overmem, acache->stats.overmem_nocreates,
+ acache->stats.nomem);
+ reset_stats(acache);
+
isc_stdtime_get(&cleaner->last_cleanup_time);
UNLOCK(&acache->lock);
cleaner->ncleaned,
(unsigned long)isc_mem_inuse(cleaner->acache->mctx));
+ if (cleaner->overmem) {
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
+ "acache is still in overmem state "
+ "after cleaning");
+ }
+
cleaner->ncleaned = 0;
cleaner->state = cleaner_s_idle;
cleaner->resched_event = event;
while (n_entries-- > 0) {
isc_boolean_t is_stale = ISC_FALSE;
-
+
INSIST(entry != NULL);
next = ISC_LIST_NEXT(entry, link);
if (result != ISC_R_SUCCESS)
goto cleanup;
+ acache->stats.cleaner_runs = 0;
+ reset_stats(acache);
+
acache->magic = ACACHE_MAGIC;
*acachep = acache;
*targetp = source;
}
+void
+dns_acache_countquerymiss(dns_acache_t *acache) {
+ acache->stats.misses++; /* XXXSK danger: unlocked! */
+ acache->stats.queries++; /* XXXSK danger: unlocked! */
+}
+
void
dns_acache_detach(dns_acache_t **acachep) {
dns_acache_t *acache;
acache->dbentries--;
+ acache->stats.deleted++;
+
UNLOCK(&acache->lock);
return (ISC_R_SUCCESS);
* example, if the cleaner does not run aggressively enough),
* then we will not create additional entries.
*
- * XXX: It might be better to lock the acache->cleaner->lock,
+ * XXXSK: It might be better to lock the acache->cleaner->lock,
* but locking may be an expensive bottleneck. If we misread
* the value, we will occasionally refuse to create a few
* cache entries, or create a few that we should not. I do not
* expect this to happen often, and it will not have very bad
* effects when it does. So no lock for now.
*/
- if (acache->cleaner.overmem)
+ if (acache->cleaner.overmem) {
+ acache->stats.overmem_nocreates++; /* XXXSK danger: unlocked! */
return (ISC_R_NORESOURCES);
+ }
newentry = isc_mem_get(acache->mctx, sizeof(*newentry));
- if (newentry == NULL)
+ if (newentry == NULL) {
+ acache->stats.nomem++; /* XXXMLG danger: unlocked! */
return (ISC_R_NOMEMORY);
+ }
result = ACACHE_INITLOCK(&newentry->lock);
if (result != ISC_R_SUCCESS) {
}
}
+ entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */
+ entry->acache->stats.queries++;
+
ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_read);
return (result);
dns_acache_attachentry(entry, &dummy_entry);
ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+
+ acache->stats.adds++;
UNLOCK(&acache->lock);
return (ISC_R_SUCCESS);
*/
if (refs == 0) {
INSIST(!ISC_LINK_LINKED(entry, link));
+ (*entryp)->acache->stats.deleted++;
destroy_entry(entry);
}
DNS_LOGMODULE_ACACHE, ISC_LOG_WARNING,
"could not set acache cleaning interval: %s",
isc_result_totext(result));
+ else
+ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
+ DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
+ "acache %p cleaning interval set to %d.",
+ acache, t);
unlock:
UNLOCK(&acache->lock);