diff --git a/CHANGES b/CHANGES index 947690651f..708c687561 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +2014. [func] Statistics about acache now recorded and sent + to log. [RT #15976] + 2013. [bug] Handle unexpected TSIGs on unsigned AXFR/IXFR responses more gracefully. [RT #15941] diff --git a/lib/dns/acache.c b/lib/dns/acache.c index 0e90f5f2f0..c87ab1817a 100644 --- a/lib/dns/acache.c +++ b/lib/dns/acache.c @@ -1,5 +1,5 @@ /* - * 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 @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acache.c,v 1.14 2006/04/27 09:36:46 marka Exp $ */ +/* $Id: acache.c,v 1.15 2006/05/02 13:04:54 shane Exp $ */ #include @@ -132,8 +132,9 @@ struct acache_cleaner { 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 @@ -153,6 +154,19 @@ struct acache_cleaner { 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. */ @@ -176,6 +190,8 @@ struct dns_acache { isc_task_t *task; isc_event_t cevent; isc_boolean_t cevent_sent; + + dns_acachestats_t stats; }; struct dns_acacheentry { @@ -240,6 +256,23 @@ static void acache_overmem_cleaning_action(isc_task_t *task, 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. */ @@ -639,6 +672,26 @@ end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) { } 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); @@ -652,6 +705,13 @@ end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) { 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; @@ -757,7 +817,7 @@ acache_incremental_cleaning_action(isc_task_t *task, isc_event_t *event) { while (n_entries-- > 0) { isc_boolean_t is_stale = ISC_FALSE; - + INSIST(entry != NULL); next = ISC_LIST_NEXT(entry, link); @@ -1010,6 +1070,9 @@ dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx, if (result != ISC_R_SUCCESS) goto cleanup; + acache->stats.cleaner_runs = 0; + reset_stats(acache); + acache->magic = ACACHE_MAGIC; *acachep = acache; @@ -1039,6 +1102,12 @@ dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp) { *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; @@ -1230,6 +1299,8 @@ dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) { acache->dbentries--; + acache->stats.deleted++; + UNLOCK(&acache->lock); return (ISC_R_SUCCESS); @@ -1252,19 +1323,23 @@ dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb, * 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) { @@ -1371,6 +1446,9 @@ dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep, } } + entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */ + entry->acache->stats.queries++; + ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_read); return (result); @@ -1501,6 +1579,8 @@ dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry, dns_acache_attachentry(entry, &dummy_entry); ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write); + + acache->stats.adds++; UNLOCK(&acache->lock); return (ISC_R_SUCCESS); @@ -1568,6 +1648,7 @@ dns_acache_detachentry(dns_acacheentry_t **entryp) { */ if (refs == 0) { INSIST(!ISC_LINK_LINKED(entry, link)); + (*entryp)->acache->stats.deleted++; destroy_entry(entry); } @@ -1610,6 +1691,11 @@ dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t) { 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); diff --git a/lib/dns/include/dns/acache.h b/lib/dns/include/dns/acache.h index 19def50b02..d2ef1f337e 100644 --- a/lib/dns/include/dns/acache.h +++ b/lib/dns/include/dns/acache.h @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: acache.h,v 1.4 2004/12/23 00:13:17 marka Exp $ */ +/* $Id: acache.h,v 1.5 2006/05/02 13:04:54 shane Exp $ */ #ifndef DNS_ACACHE_H #define DNS_ACACHE_H 1 @@ -434,6 +434,12 @@ dns_acache_detachentry(dns_acacheentry_t **entryp); * entry (including the entry object itself) will be freed. */ +void +dns_acache_countquerymiss(dns_acache_t *acache); +/* + * Count up a missed acache query. XXXMLG need more docs. + */ + ISC_LANG_ENDDECLS #endif /* DNS_ACACHE_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index c7ce50bc04..32c4a9ce4c 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.120 2006/02/28 02:39:51 marka Exp $ */ +/* $Id: types.h,v 1.121 2006/05/02 13:04:54 shane Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -33,6 +33,7 @@ typedef struct dns_acache dns_acache_t; typedef struct dns_acacheentry dns_acacheentry_t; +typedef struct dns_acachestats dns_acachestats_t; typedef struct dns_acl dns_acl_t; typedef struct dns_aclelement dns_aclelement_t; typedef struct dns_aclenv dns_aclenv_t; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index cea5516a8f..d8f3ac4be5 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.231 2006/03/07 04:58:51 marka Exp $ */ +/* $Id: rbtdb.c,v 1.232 2006/05/02 13:04:54 shane Exp $ */ /*! \file */ @@ -6411,11 +6411,14 @@ rdataset_getadditional(dns_rdataset_t *rdataset, dns_rdatasetadditional_t type, } if (acarray == NULL) { + if (type != dns_rdatasetadditional_fromcache) + dns_acache_countquerymiss(acache); NODE_UNLOCK(nodelock, isc_rwlocktype_read); return (ISC_R_NOTFOUND); } if (acarray[count].entry == NULL) { + dns_acache_countquerymiss(acache); NODE_UNLOCK(nodelock, isc_rwlocktype_read); return (ISC_R_NOTFOUND); } @@ -6695,7 +6698,7 @@ rdataset_putadditional(dns_acache_t *acache, dns_rdataset_t *rdataset, NODE_UNLOCK(nodelock, isc_rwlocktype_write); if (entry != NULL) { - if(cbarg != NULL) + if (cbarg != NULL) acache_cancelentry(rbtdb->common.mctx, entry, &cbarg); dns_acache_detachentry(&entry); }