1 /* $NetBSD: cache.c,v 1.8 2014/12/10 04:37:58 christos Exp $ */
4 * Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: cache.c,v 1.91 2011/08/26 05:12:56 marka Exp */
28 #include <isc/print.h>
29 #include <isc/string.h>
30 #include <isc/stats.h>
33 #include <isc/timer.h>
37 #include <dns/cache.h>
39 #include <dns/dbiterator.h>
40 #include <dns/events.h>
43 #include <dns/masterdump.h>
44 #include <dns/rdata.h>
45 #include <dns/rdataset.h>
46 #include <dns/rdatasetiter.h>
47 #include <dns/result.h>
48 #include <dns/stats.h>
52 #define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$')
53 #define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC)
56 * Control incremental cleaning.
57 * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
58 * See also DNS_CACHE_CLEANERINCREMENT
60 #define DNS_CACHE_MINSIZE 2097152U /*%< Bytes. 2097152 = 2 MB */
62 * Control incremental cleaning.
63 * CLEANERINCREMENT is how many nodes are examined in one pass.
64 * See also DNS_CACHE_MINSIZE
66 #define DNS_CACHE_CLEANERINCREMENT 1000U /*%< Number of nodes. */
73 * A cache_cleaner_t encapsulates the state of the periodic
77 typedef struct cache_cleaner cache_cleaner_t
;
80 cleaner_s_idle
, /*%< Waiting for cleaning-interval to expire. */
81 cleaner_s_busy
, /*%< Currently cleaning. */
82 cleaner_s_done
/*%< Freed enough memory after being overmem. */
86 * Convenience macros for comprehensive assertion checking.
88 #define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
89 (c)->resched_event != NULL)
90 #define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
91 (c)->iterator != NULL && \
92 (c)->resched_event == NULL)
95 * Accesses to a cache cleaner object are synchronized through
96 * task/event serialization, or locked from the cache object.
98 struct cache_cleaner
{
101 * Locks overmem_event, overmem. Note: never allocate memory
102 * while holding this lock - that could lead to deadlock since
103 * the lock is take by water() which is called from the memory
109 unsigned int cleaning_interval
; /*% The cleaning-interval from
110 named.conf, in seconds. */
111 isc_timer_t
*cleaning_timer
;
112 isc_event_t
*resched_event
; /*% Sent by cleaner task to
113 itself to reschedule */
114 isc_event_t
*overmem_event
;
116 dns_dbiterator_t
*iterator
;
117 unsigned int increment
; /*% Number of names to
118 clean in one increment */
119 cleaner_state_t state
; /*% Idle/Busy. */
120 isc_boolean_t overmem
; /*% The cache is in an overmem state. */
121 isc_boolean_t replaceiterator
;
125 * The actual cache object.
132 isc_mutex_t filelock
;
133 isc_mem_t
*mctx
; /* Main cache memory */
134 isc_mem_t
*hmctx
; /* Heap memory */
137 /* Locked by 'lock'. */
140 dns_rdataclass_t rdclass
;
142 cache_cleaner_t cleaner
;
149 /* Locked by 'filelock'. */
151 /* Access to the on-disk cache file is also locked by 'filelock'. */
159 cache_cleaner_init(dns_cache_t
*cache
, isc_taskmgr_t
*taskmgr
,
160 isc_timermgr_t
*timermgr
, cache_cleaner_t
*cleaner
);
163 cleaning_timer_action(isc_task_t
*task
, isc_event_t
*event
);
166 incremental_cleaning_action(isc_task_t
*task
, isc_event_t
*event
);
169 cleaner_shutdown_action(isc_task_t
*task
, isc_event_t
*event
);
172 overmem_cleaning_action(isc_task_t
*task
, isc_event_t
*event
);
174 static inline isc_result_t
175 cache_create_db(dns_cache_t
*cache
, dns_db_t
**db
) {
176 return (dns_db_create(cache
->mctx
, cache
->db_type
, dns_rootname
,
177 dns_dbtype_cache
, cache
->rdclass
,
178 cache
->db_argc
, cache
->db_argv
, db
));
182 dns_cache_create(isc_mem_t
*cmctx
, isc_taskmgr_t
*taskmgr
,
183 isc_timermgr_t
*timermgr
, dns_rdataclass_t rdclass
,
184 const char *db_type
, unsigned int db_argc
, char **db_argv
,
185 dns_cache_t
**cachep
)
187 return (dns_cache_create3(cmctx
, cmctx
, taskmgr
, timermgr
, rdclass
, "",
188 db_type
, db_argc
, db_argv
, cachep
));
192 dns_cache_create2(isc_mem_t
*cmctx
, isc_taskmgr_t
*taskmgr
,
193 isc_timermgr_t
*timermgr
, dns_rdataclass_t rdclass
,
194 const char *cachename
, const char *db_type
,
195 unsigned int db_argc
, char **db_argv
, dns_cache_t
**cachep
)
197 return (dns_cache_create3(cmctx
, cmctx
, taskmgr
, timermgr
, rdclass
,
198 cachename
, db_type
, db_argc
, db_argv
,
203 dns_cache_create3(isc_mem_t
*cmctx
, isc_mem_t
*hmctx
, isc_taskmgr_t
*taskmgr
,
204 isc_timermgr_t
*timermgr
, dns_rdataclass_t rdclass
,
205 const char *cachename
, const char *db_type
,
206 unsigned int db_argc
, char **db_argv
, dns_cache_t
**cachep
)
213 REQUIRE(cachep
!= NULL
);
214 REQUIRE(*cachep
== NULL
);
215 REQUIRE(cmctx
!= NULL
);
216 REQUIRE(hmctx
!= NULL
);
217 REQUIRE(cachename
!= NULL
);
219 cache
= isc_mem_get(cmctx
, sizeof(*cache
));
221 return (ISC_R_NOMEMORY
);
223 cache
->mctx
= cache
->hmctx
= NULL
;
224 isc_mem_attach(cmctx
, &cache
->mctx
);
225 isc_mem_attach(hmctx
, &cache
->hmctx
);
228 if (cachename
!= NULL
) {
229 cache
->name
= isc_mem_strdup(cmctx
, cachename
);
230 if (cache
->name
== NULL
) {
231 result
= ISC_R_NOMEMORY
;
236 result
= isc_mutex_init(&cache
->lock
);
237 if (result
!= ISC_R_SUCCESS
)
240 result
= isc_mutex_init(&cache
->filelock
);
241 if (result
!= ISC_R_SUCCESS
)
244 cache
->references
= 1;
245 cache
->live_tasks
= 0;
246 cache
->rdclass
= rdclass
;
249 result
= isc_stats_create(cmctx
, &cache
->stats
,
250 dns_cachestatscounter_max
);
251 if (result
!= ISC_R_SUCCESS
)
252 goto cleanup_filelock
;
254 cache
->db_type
= isc_mem_strdup(cmctx
, db_type
);
255 if (cache
->db_type
== NULL
) {
256 result
= ISC_R_NOMEMORY
;
261 * For databases of type "rbt" we pass hmctx to dns_db_create()
262 * via cache->db_argv, followed by the rest of the arguments in
263 * db_argv (of which there really shouldn't be any).
265 if (strcmp(cache
->db_type
, "rbt") == 0)
268 cache
->db_argc
= db_argc
+ extra
;
269 cache
->db_argv
= NULL
;
271 if (cache
->db_argc
!= 0) {
272 cache
->db_argv
= isc_mem_get(cmctx
,
273 cache
->db_argc
* sizeof(char *));
274 if (cache
->db_argv
== NULL
) {
275 result
= ISC_R_NOMEMORY
;
279 for (i
= 0; i
< cache
->db_argc
; i
++)
280 cache
->db_argv
[i
] = NULL
;
282 cache
->db_argv
[0] = (char *) hmctx
;
283 for (i
= extra
; i
< cache
->db_argc
; i
++) {
284 cache
->db_argv
[i
] = isc_mem_strdup(cmctx
,
286 if (cache
->db_argv
[i
] == NULL
) {
287 result
= ISC_R_NOMEMORY
;
294 * Create the database
297 result
= cache_create_db(cache
, &cache
->db
);
298 if (result
!= ISC_R_SUCCESS
)
300 if (taskmgr
!= NULL
) {
302 result
= isc_task_create(taskmgr
, 1, &dbtask
);
303 if (result
!= ISC_R_SUCCESS
)
305 dns_db_settask(cache
->db
, dbtask
);
306 isc_task_detach(&dbtask
);
309 cache
->filename
= NULL
;
311 cache
->magic
= CACHE_MAGIC
;
314 * RBT-type cache DB has its own mechanism of cache cleaning and doesn't
315 * need the control of the generic cleaner.
317 if (strcmp(db_type
, "rbt") == 0)
318 result
= cache_cleaner_init(cache
, NULL
, NULL
, &cache
->cleaner
);
320 result
= cache_cleaner_init(cache
, taskmgr
, timermgr
,
323 if (result
!= ISC_R_SUCCESS
)
326 result
= dns_db_setcachestats(cache
->db
, cache
->stats
);
327 if (result
!= ISC_R_SUCCESS
)
332 return (ISC_R_SUCCESS
);
335 dns_db_detach(&cache
->db
);
337 for (i
= extra
; i
< cache
->db_argc
; i
++)
338 if (cache
->db_argv
[i
] != NULL
)
339 isc_mem_free(cmctx
, cache
->db_argv
[i
]);
340 if (cache
->db_argv
!= NULL
)
341 isc_mem_put(cmctx
, cache
->db_argv
,
342 cache
->db_argc
* sizeof(char *));
344 isc_mem_free(cmctx
, cache
->db_type
);
346 DESTROYLOCK(&cache
->filelock
);
348 isc_stats_detach(&cache
->stats
);
350 DESTROYLOCK(&cache
->lock
);
352 if (cache
->name
!= NULL
)
353 isc_mem_free(cmctx
, cache
->name
);
354 isc_mem_detach(&cache
->hmctx
);
355 isc_mem_putanddetach(&cache
->mctx
, cache
, sizeof(*cache
));
360 cache_free(dns_cache_t
*cache
) {
363 REQUIRE(VALID_CACHE(cache
));
364 REQUIRE(cache
->references
== 0);
366 isc_mem_setwater(cache
->mctx
, NULL
, NULL
, 0, 0);
368 if (cache
->cleaner
.task
!= NULL
)
369 isc_task_detach(&cache
->cleaner
.task
);
371 if (cache
->cleaner
.overmem_event
!= NULL
)
372 isc_event_free(&cache
->cleaner
.overmem_event
);
374 if (cache
->cleaner
.resched_event
!= NULL
)
375 isc_event_free(&cache
->cleaner
.resched_event
);
377 if (cache
->cleaner
.iterator
!= NULL
)
378 dns_dbiterator_destroy(&cache
->cleaner
.iterator
);
380 DESTROYLOCK(&cache
->cleaner
.lock
);
382 if (cache
->filename
) {
383 isc_mem_free(cache
->mctx
, cache
->filename
);
384 cache
->filename
= NULL
;
387 if (cache
->db
!= NULL
)
388 dns_db_detach(&cache
->db
);
390 if (cache
->db_argv
!= NULL
) {
392 * We don't free db_argv[0] in "rbt" cache databases
393 * as it's a pointer to hmctx
396 if (strcmp(cache
->db_type
, "rbt") == 0)
398 for (i
= extra
; i
< cache
->db_argc
; i
++)
399 if (cache
->db_argv
[i
] != NULL
)
400 isc_mem_free(cache
->mctx
, cache
->db_argv
[i
]);
401 isc_mem_put(cache
->mctx
, cache
->db_argv
,
402 cache
->db_argc
* sizeof(char *));
405 if (cache
->db_type
!= NULL
)
406 isc_mem_free(cache
->mctx
, cache
->db_type
);
408 if (cache
->name
!= NULL
)
409 isc_mem_free(cache
->mctx
, cache
->name
);
411 if (cache
->stats
!= NULL
)
412 isc_stats_detach(&cache
->stats
);
414 DESTROYLOCK(&cache
->lock
);
415 DESTROYLOCK(&cache
->filelock
);
418 isc_mem_detach(&cache
->hmctx
);
419 isc_mem_putanddetach(&cache
->mctx
, cache
, sizeof(*cache
));
424 dns_cache_attach(dns_cache_t
*cache
, dns_cache_t
**targetp
) {
426 REQUIRE(VALID_CACHE(cache
));
427 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
431 UNLOCK(&cache
->lock
);
437 dns_cache_detach(dns_cache_t
**cachep
) {
439 isc_boolean_t free_cache
= ISC_FALSE
;
441 REQUIRE(cachep
!= NULL
);
443 REQUIRE(VALID_CACHE(cache
));
446 REQUIRE(cache
->references
> 0);
448 if (cache
->references
== 0) {
449 cache
->cleaner
.overmem
= ISC_FALSE
;
450 free_cache
= ISC_TRUE
;
457 * When the cache is shut down, dump it to a file if one is
460 isc_result_t result
= dns_cache_dump(cache
);
461 if (result
!= ISC_R_SUCCESS
)
462 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
463 DNS_LOGMODULE_CACHE
, ISC_LOG_WARNING
,
464 "error dumping cache: %s ",
465 isc_result_totext(result
));
468 * If the cleaner task exists, let it free the cache.
470 if (cache
->live_tasks
> 0) {
471 isc_task_shutdown(cache
->cleaner
.task
);
472 free_cache
= ISC_FALSE
;
476 UNLOCK(&cache
->lock
);
483 dns_cache_attachdb(dns_cache_t
*cache
, dns_db_t
**dbp
) {
484 REQUIRE(VALID_CACHE(cache
));
485 REQUIRE(dbp
!= NULL
&& *dbp
== NULL
);
486 REQUIRE(cache
->db
!= NULL
);
489 dns_db_attach(cache
->db
, dbp
);
490 UNLOCK(&cache
->lock
);
495 dns_cache_setfilename(dns_cache_t
*cache
, const char *filename
) {
498 REQUIRE(VALID_CACHE(cache
));
499 REQUIRE(filename
!= NULL
);
501 newname
= isc_mem_strdup(cache
->mctx
, filename
);
503 return (ISC_R_NOMEMORY
);
505 LOCK(&cache
->filelock
);
507 isc_mem_free(cache
->mctx
, cache
->filename
);
508 cache
->filename
= newname
;
509 UNLOCK(&cache
->filelock
);
511 return (ISC_R_SUCCESS
);
515 dns_cache_load(dns_cache_t
*cache
) {
518 REQUIRE(VALID_CACHE(cache
));
520 if (cache
->filename
== NULL
)
521 return (ISC_R_SUCCESS
);
523 LOCK(&cache
->filelock
);
524 result
= dns_db_load(cache
->db
, cache
->filename
);
525 UNLOCK(&cache
->filelock
);
531 dns_cache_dump(dns_cache_t
*cache
) {
534 REQUIRE(VALID_CACHE(cache
));
536 if (cache
->filename
== NULL
)
537 return (ISC_R_SUCCESS
);
539 LOCK(&cache
->filelock
);
540 result
= dns_master_dump(cache
->mctx
, cache
->db
, NULL
,
541 &dns_master_style_cache
, cache
->filename
);
542 UNLOCK(&cache
->filelock
);
548 dns_cache_setcleaninginterval(dns_cache_t
*cache
, unsigned int t
) {
549 isc_interval_t interval
;
555 * It may be the case that the cache has already shut down.
556 * If so, it has no timer.
558 if (cache
->cleaner
.cleaning_timer
== NULL
)
561 cache
->cleaner
.cleaning_interval
= t
;
564 result
= isc_timer_reset(cache
->cleaner
.cleaning_timer
,
565 isc_timertype_inactive
,
566 NULL
, NULL
, ISC_TRUE
);
568 isc_interval_set(&interval
, cache
->cleaner
.cleaning_interval
,
570 result
= isc_timer_reset(cache
->cleaner
.cleaning_timer
,
571 isc_timertype_ticker
,
572 NULL
, &interval
, ISC_FALSE
);
574 if (result
!= ISC_R_SUCCESS
)
575 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
576 DNS_LOGMODULE_CACHE
, ISC_LOG_WARNING
,
577 "could not set cache cleaning interval: %s",
578 isc_result_totext(result
));
581 UNLOCK(&cache
->lock
);
585 dns_cache_getcleaninginterval(dns_cache_t
*cache
) {
588 REQUIRE(VALID_CACHE(cache
));
591 t
= cache
->cleaner
.cleaning_interval
;
592 UNLOCK(&cache
->lock
);
598 dns_cache_getname(dns_cache_t
*cache
) {
599 REQUIRE(VALID_CACHE(cache
));
601 return (cache
->name
);
605 * Initialize the cache cleaner object at *cleaner.
606 * Space for the object must be allocated by the caller.
610 cache_cleaner_init(dns_cache_t
*cache
, isc_taskmgr_t
*taskmgr
,
611 isc_timermgr_t
*timermgr
, cache_cleaner_t
*cleaner
)
615 result
= isc_mutex_init(&cleaner
->lock
);
616 if (result
!= ISC_R_SUCCESS
)
619 cleaner
->increment
= DNS_CACHE_CLEANERINCREMENT
;
620 cleaner
->state
= cleaner_s_idle
;
621 cleaner
->cache
= cache
;
622 cleaner
->iterator
= NULL
;
623 cleaner
->overmem
= ISC_FALSE
;
624 cleaner
->replaceiterator
= ISC_FALSE
;
626 cleaner
->task
= NULL
;
627 cleaner
->cleaning_timer
= NULL
;
628 cleaner
->resched_event
= NULL
;
629 cleaner
->overmem_event
= NULL
;
630 cleaner
->cleaning_interval
= 0; /* Initially turned off. */
632 result
= dns_db_createiterator(cleaner
->cache
->db
, ISC_FALSE
,
634 if (result
!= ISC_R_SUCCESS
)
637 if (taskmgr
!= NULL
&& timermgr
!= NULL
) {
638 result
= isc_task_create(taskmgr
, 1, &cleaner
->task
);
639 if (result
!= ISC_R_SUCCESS
) {
640 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
641 "isc_task_create() failed: %s",
642 dns_result_totext(result
));
643 result
= ISC_R_UNEXPECTED
;
646 cleaner
->cache
->live_tasks
++;
647 isc_task_setname(cleaner
->task
, "cachecleaner", cleaner
);
649 result
= isc_task_onshutdown(cleaner
->task
,
650 cleaner_shutdown_action
, cache
);
651 if (result
!= ISC_R_SUCCESS
) {
652 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
654 "isc_task_onshutdown() failed: %s",
655 dns_result_totext(result
));
659 result
= isc_timer_create(timermgr
, isc_timertype_inactive
,
660 NULL
, NULL
, cleaner
->task
,
661 cleaning_timer_action
, cleaner
,
662 &cleaner
->cleaning_timer
);
663 if (result
!= ISC_R_SUCCESS
) {
664 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
665 "isc_timer_create() failed: %s",
666 dns_result_totext(result
));
667 result
= ISC_R_UNEXPECTED
;
671 cleaner
->resched_event
=
672 isc_event_allocate(cache
->mctx
, cleaner
,
673 DNS_EVENT_CACHECLEAN
,
674 incremental_cleaning_action
,
675 cleaner
, sizeof(isc_event_t
));
676 if (cleaner
->resched_event
== NULL
) {
677 result
= ISC_R_NOMEMORY
;
681 cleaner
->overmem_event
=
682 isc_event_allocate(cache
->mctx
, cleaner
,
683 DNS_EVENT_CACHEOVERMEM
,
684 overmem_cleaning_action
,
685 cleaner
, sizeof(isc_event_t
));
686 if (cleaner
->overmem_event
== NULL
) {
687 result
= ISC_R_NOMEMORY
;
692 return (ISC_R_SUCCESS
);
695 if (cleaner
->overmem_event
!= NULL
)
696 isc_event_free(&cleaner
->overmem_event
);
697 if (cleaner
->resched_event
!= NULL
)
698 isc_event_free(&cleaner
->resched_event
);
699 if (cleaner
->cleaning_timer
!= NULL
)
700 isc_timer_detach(&cleaner
->cleaning_timer
);
701 if (cleaner
->task
!= NULL
)
702 isc_task_detach(&cleaner
->task
);
703 if (cleaner
->iterator
!= NULL
)
704 dns_dbiterator_destroy(&cleaner
->iterator
);
705 DESTROYLOCK(&cleaner
->lock
);
711 begin_cleaning(cache_cleaner_t
*cleaner
) {
712 isc_result_t result
= ISC_R_SUCCESS
;
714 REQUIRE(CLEANER_IDLE(cleaner
));
717 * Create an iterator, if it does not already exist, and
718 * position it at the beginning of the cache.
720 if (cleaner
->iterator
== NULL
)
721 result
= dns_db_createiterator(cleaner
->cache
->db
, ISC_FALSE
,
723 if (result
!= ISC_R_SUCCESS
)
724 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
725 DNS_LOGMODULE_CACHE
, ISC_LOG_WARNING
,
726 "cache cleaner could not create "
727 "iterator: %s", isc_result_totext(result
));
729 dns_dbiterator_setcleanmode(cleaner
->iterator
, ISC_TRUE
);
730 result
= dns_dbiterator_first(cleaner
->iterator
);
732 if (result
!= ISC_R_SUCCESS
) {
734 * If the result is ISC_R_NOMORE, the database is empty,
735 * so there is nothing to be cleaned.
737 if (result
!= ISC_R_NOMORE
&& cleaner
->iterator
!= NULL
) {
738 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
740 "dns_dbiterator_first() failed: %s",
741 dns_result_totext(result
));
742 dns_dbiterator_destroy(&cleaner
->iterator
);
743 } else if (cleaner
->iterator
!= NULL
) {
744 result
= dns_dbiterator_pause(cleaner
->iterator
);
745 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
749 * Pause the iterator to free its lock.
751 result
= dns_dbiterator_pause(cleaner
->iterator
);
752 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
754 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
,
755 DNS_LOGMODULE_CACHE
, ISC_LOG_DEBUG(1),
756 "begin cache cleaning, mem inuse %lu",
757 (unsigned long)isc_mem_inuse(cleaner
->cache
->mctx
));
758 cleaner
->state
= cleaner_s_busy
;
759 isc_task_send(cleaner
->task
, &cleaner
->resched_event
);
766 end_cleaning(cache_cleaner_t
*cleaner
, isc_event_t
*event
) {
769 REQUIRE(CLEANER_BUSY(cleaner
));
770 REQUIRE(event
!= NULL
);
772 result
= dns_dbiterator_pause(cleaner
->iterator
);
773 if (result
!= ISC_R_SUCCESS
)
774 dns_dbiterator_destroy(&cleaner
->iterator
);
776 dns_cache_setcleaninginterval(cleaner
->cache
,
777 cleaner
->cleaning_interval
);
779 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
, DNS_LOGMODULE_CACHE
,
780 ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
781 (unsigned long)isc_mem_inuse(cleaner
->cache
->mctx
));
783 cleaner
->state
= cleaner_s_idle
;
784 cleaner
->resched_event
= event
;
788 * This is run once for every cache-cleaning-interval as defined in named.conf.
791 cleaning_timer_action(isc_task_t
*task
, isc_event_t
*event
) {
792 cache_cleaner_t
*cleaner
= event
->ev_arg
;
796 INSIST(task
== cleaner
->task
);
797 INSIST(event
->ev_type
== ISC_TIMEREVENT_TICK
);
799 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
, DNS_LOGMODULE_CACHE
,
800 ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
801 "cleaner state = %d", cleaner
->state
);
803 if (cleaner
->state
== cleaner_s_idle
)
804 begin_cleaning(cleaner
);
806 isc_event_free(&event
);
810 * This is called when the cache either surpasses its upper limit
811 * or shrinks beyond its lower limit.
814 overmem_cleaning_action(isc_task_t
*task
, isc_event_t
*event
) {
815 cache_cleaner_t
*cleaner
= event
->ev_arg
;
816 isc_boolean_t want_cleaning
= ISC_FALSE
;
820 INSIST(task
== cleaner
->task
);
821 INSIST(event
->ev_type
== DNS_EVENT_CACHEOVERMEM
);
822 INSIST(cleaner
->overmem_event
== NULL
);
824 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
, DNS_LOGMODULE_CACHE
,
825 ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
826 "overmem = %d, state = %d", cleaner
->overmem
,
829 LOCK(&cleaner
->lock
);
831 if (cleaner
->overmem
) {
832 if (cleaner
->state
== cleaner_s_idle
)
833 want_cleaning
= ISC_TRUE
;
835 if (cleaner
->state
== cleaner_s_busy
)
837 * end_cleaning() can't be called here because
838 * then both cleaner->overmem_event and
839 * cleaner->resched_event will point to this
840 * event. Set the state to done, and then
841 * when the incremental_cleaning_action() event
842 * is posted, it will handle the end_cleaning.
844 cleaner
->state
= cleaner_s_done
;
847 cleaner
->overmem_event
= event
;
849 UNLOCK(&cleaner
->lock
);
852 begin_cleaning(cleaner
);
856 * Do incremental cleaning.
859 incremental_cleaning_action(isc_task_t
*task
, isc_event_t
*event
) {
860 cache_cleaner_t
*cleaner
= event
->ev_arg
;
862 unsigned int n_names
;
867 INSIST(task
== cleaner
->task
);
868 INSIST(event
->ev_type
== DNS_EVENT_CACHECLEAN
);
870 if (cleaner
->state
== cleaner_s_done
) {
871 cleaner
->state
= cleaner_s_busy
;
872 end_cleaning(cleaner
, event
);
873 LOCK(&cleaner
->cache
->lock
);
874 LOCK(&cleaner
->lock
);
875 if (cleaner
->replaceiterator
) {
876 dns_dbiterator_destroy(&cleaner
->iterator
);
877 (void) dns_db_createiterator(cleaner
->cache
->db
,
880 cleaner
->replaceiterator
= ISC_FALSE
;
882 UNLOCK(&cleaner
->lock
);
883 UNLOCK(&cleaner
->cache
->lock
);
887 INSIST(CLEANER_BUSY(cleaner
));
889 n_names
= cleaner
->increment
;
891 REQUIRE(DNS_DBITERATOR_VALID(cleaner
->iterator
));
893 isc_time_now(&start
);
894 while (n_names
-- > 0) {
895 dns_dbnode_t
*node
= NULL
;
897 result
= dns_dbiterator_current(cleaner
->iterator
, &node
,
899 if (result
!= ISC_R_SUCCESS
) {
900 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
901 "cache cleaner: dns_dbiterator_current() "
902 "failed: %s", dns_result_totext(result
));
904 end_cleaning(cleaner
, event
);
909 * The node was not needed, but was required by
910 * dns_dbiterator_current(). Give up its reference.
912 dns_db_detachnode(cleaner
->cache
->db
, &node
);
915 * Step to the next node.
917 result
= dns_dbiterator_next(cleaner
->iterator
);
919 if (result
!= ISC_R_SUCCESS
) {
921 * Either the end was reached (ISC_R_NOMORE) or
922 * some error was signaled. If the cache is still
923 * overmem and no error was encountered,
924 * keep trying to clean it, otherwise stop cleaning.
926 if (result
!= ISC_R_NOMORE
)
927 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
929 "dns_dbiterator_next() "
931 dns_result_totext(result
));
932 else if (cleaner
->overmem
) {
933 result
= dns_dbiterator_first(cleaner
->
935 if (result
== ISC_R_SUCCESS
) {
936 isc_log_write(dns_lctx
,
937 DNS_LOGCATEGORY_DATABASE
,
942 "reset and try again");
947 end_cleaning(cleaner
, event
);
953 * We have successfully performed a cleaning increment but have
954 * not gone through the entire cache. Free the iterator locks
955 * and reschedule another batch. If it fails, just try to continue
958 result
= dns_dbiterator_pause(cleaner
->iterator
);
959 RUNTIME_CHECK(result
== ISC_R_SUCCESS
);
961 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DATABASE
, DNS_LOGMODULE_CACHE
,
962 ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
963 "mem inuse %lu, sleeping", cleaner
->increment
,
964 (unsigned long)isc_mem_inuse(cleaner
->cache
->mctx
));
966 isc_task_send(task
, &event
);
967 INSIST(CLEANER_BUSY(cleaner
));
972 * Do immediate cleaning.
975 dns_cache_clean(dns_cache_t
*cache
, isc_stdtime_t now
) {
977 dns_dbiterator_t
*iterator
= NULL
;
979 REQUIRE(VALID_CACHE(cache
));
981 result
= dns_db_createiterator(cache
->db
, 0, &iterator
);
982 if (result
!= ISC_R_SUCCESS
)
985 result
= dns_dbiterator_first(iterator
);
987 while (result
== ISC_R_SUCCESS
) {
988 dns_dbnode_t
*node
= NULL
;
989 result
= dns_dbiterator_current(iterator
, &node
,
991 if (result
!= ISC_R_SUCCESS
)
995 * Check TTLs, mark expired rdatasets stale.
997 result
= dns_db_expirenode(cache
->db
, node
, now
);
998 if (result
!= ISC_R_SUCCESS
) {
999 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1000 "cache cleaner: dns_db_expirenode() "
1002 dns_result_totext(result
));
1009 * This is where the actual freeing takes place.
1011 dns_db_detachnode(cache
->db
, &node
);
1013 result
= dns_dbiterator_next(iterator
);
1016 dns_dbiterator_destroy(&iterator
);
1018 if (result
== ISC_R_NOMORE
)
1019 result
= ISC_R_SUCCESS
;
1025 water(void *arg
, int mark
) {
1026 dns_cache_t
*cache
= arg
;
1027 isc_boolean_t overmem
= ISC_TF(mark
== ISC_MEM_HIWATER
);
1029 REQUIRE(VALID_CACHE(cache
));
1031 LOCK(&cache
->cleaner
.lock
);
1033 if (overmem
!= cache
->cleaner
.overmem
) {
1034 dns_db_overmem(cache
->db
, overmem
);
1035 cache
->cleaner
.overmem
= overmem
;
1036 isc_mem_waterack(cache
->mctx
, mark
);
1039 if (cache
->cleaner
.overmem_event
!= NULL
)
1040 isc_task_send(cache
->cleaner
.task
,
1041 &cache
->cleaner
.overmem_event
);
1043 UNLOCK(&cache
->cleaner
.lock
);
1047 dns_cache_setcachesize(dns_cache_t
*cache
, size_t size
) {
1048 size_t hiwater
, lowater
;
1050 REQUIRE(VALID_CACHE(cache
));
1053 * Impose a minimum cache size; pathological things happen if there
1054 * is too little room.
1056 if (size
!= 0U && size
< DNS_CACHE_MINSIZE
)
1057 size
= DNS_CACHE_MINSIZE
;
1061 UNLOCK(&cache
->lock
);
1063 hiwater
= size
- (size
>> 3); /* Approximately 7/8ths. */
1064 lowater
= size
- (size
>> 2); /* Approximately 3/4ths. */
1067 * If the cache was overmem and cleaning, but now with the new limits
1068 * it is no longer in an overmem condition, then the next
1069 * isc_mem_put for cache memory will do the right thing and trigger
1073 if (size
== 0U || hiwater
== 0U || lowater
== 0U)
1075 * Disable cache memory limiting.
1077 isc_mem_setwater(cache
->mctx
, water
, cache
, 0, 0);
1080 * Establish new cache memory limits (either for the first
1081 * time, or replacing other limits).
1083 isc_mem_setwater(cache
->mctx
, water
, cache
, hiwater
, lowater
);
1087 dns_cache_getcachesize(dns_cache_t
*cache
) {
1090 REQUIRE(VALID_CACHE(cache
));
1094 UNLOCK(&cache
->lock
);
1100 * The cleaner task is shutting down; do the necessary cleanup.
1103 cleaner_shutdown_action(isc_task_t
*task
, isc_event_t
*event
) {
1104 dns_cache_t
*cache
= event
->ev_arg
;
1105 isc_boolean_t should_free
= ISC_FALSE
;
1109 INSIST(task
== cache
->cleaner
.task
);
1110 INSIST(event
->ev_type
== ISC_TASKEVENT_SHUTDOWN
);
1112 if (CLEANER_BUSY(&cache
->cleaner
))
1113 end_cleaning(&cache
->cleaner
, event
);
1115 isc_event_free(&event
);
1119 cache
->live_tasks
--;
1120 INSIST(cache
->live_tasks
== 0);
1122 if (cache
->references
== 0)
1123 should_free
= ISC_TRUE
;
1126 * By detaching the timer in the context of its task,
1127 * we are guaranteed that there will be no further timer
1130 if (cache
->cleaner
.cleaning_timer
!= NULL
)
1131 isc_timer_detach(&cache
->cleaner
.cleaning_timer
);
1133 /* Make sure we don't reschedule anymore. */
1134 (void)isc_task_purge(task
, NULL
, DNS_EVENT_CACHECLEAN
, NULL
);
1136 UNLOCK(&cache
->lock
);
1143 dns_cache_flush(dns_cache_t
*cache
) {
1144 dns_db_t
*db
= NULL
;
1145 isc_result_t result
;
1147 result
= cache_create_db(cache
, &db
);
1148 if (result
!= ISC_R_SUCCESS
)
1152 LOCK(&cache
->cleaner
.lock
);
1153 if (cache
->cleaner
.state
== cleaner_s_idle
) {
1154 if (cache
->cleaner
.iterator
!= NULL
)
1155 dns_dbiterator_destroy(&cache
->cleaner
.iterator
);
1156 (void) dns_db_createiterator(db
, ISC_FALSE
,
1157 &cache
->cleaner
.iterator
);
1159 if (cache
->cleaner
.state
== cleaner_s_busy
)
1160 cache
->cleaner
.state
= cleaner_s_done
;
1161 cache
->cleaner
.replaceiterator
= ISC_TRUE
;
1163 dns_db_detach(&cache
->db
);
1165 dns_db_setcachestats(cache
->db
, cache
->stats
);
1166 UNLOCK(&cache
->cleaner
.lock
);
1167 UNLOCK(&cache
->lock
);
1169 return (ISC_R_SUCCESS
);
1173 clearnode(dns_db_t
*db
, dns_dbnode_t
*node
) {
1174 isc_result_t result
;
1175 dns_rdatasetiter_t
*iter
= NULL
;
1177 result
= dns_db_allrdatasets(db
, node
, NULL
, (isc_stdtime_t
)0, &iter
);
1178 if (result
!= ISC_R_SUCCESS
)
1181 for (result
= dns_rdatasetiter_first(iter
);
1182 result
== ISC_R_SUCCESS
;
1183 result
= dns_rdatasetiter_next(iter
))
1185 dns_rdataset_t rdataset
;
1186 dns_rdataset_init(&rdataset
);
1188 dns_rdatasetiter_current(iter
, &rdataset
);
1189 result
= dns_db_deleterdataset(db
, node
, NULL
,
1190 rdataset
.type
, rdataset
.covers
);
1191 dns_rdataset_disassociate(&rdataset
);
1192 if (result
!= ISC_R_SUCCESS
&& result
!= DNS_R_UNCHANGED
)
1196 if (result
== ISC_R_NOMORE
)
1197 result
= ISC_R_SUCCESS
;
1199 dns_rdatasetiter_destroy(&iter
);
1204 cleartree(dns_db_t
*db
, dns_name_t
*name
) {
1205 isc_result_t result
, answer
= ISC_R_SUCCESS
;
1206 dns_dbiterator_t
*iter
= NULL
;
1207 dns_dbnode_t
*node
= NULL
;
1208 dns_fixedname_t fnodename
;
1209 dns_name_t
*nodename
;
1211 dns_fixedname_init(&fnodename
);
1212 nodename
= dns_fixedname_name(&fnodename
);
1214 result
= dns_db_createiterator(db
, 0, &iter
);
1215 if (result
!= ISC_R_SUCCESS
)
1218 result
= dns_dbiterator_seek(iter
, name
);
1219 if (result
!= ISC_R_SUCCESS
)
1222 while (result
== ISC_R_SUCCESS
) {
1223 result
= dns_dbiterator_current(iter
, &node
, nodename
);
1224 if (result
== DNS_R_NEWORIGIN
)
1225 result
= ISC_R_SUCCESS
;
1226 if (result
!= ISC_R_SUCCESS
)
1231 if (! dns_name_issubdomain(nodename
, name
))
1235 * If clearnode fails record and move onto the next node.
1237 result
= clearnode(db
, node
);
1238 if (result
!= ISC_R_SUCCESS
&& answer
== ISC_R_SUCCESS
)
1240 dns_db_detachnode(db
, &node
);
1241 result
= dns_dbiterator_next(iter
);
1245 if (result
== ISC_R_NOMORE
|| result
== ISC_R_NOTFOUND
)
1246 result
= ISC_R_SUCCESS
;
1247 if (result
!= ISC_R_SUCCESS
&& answer
== ISC_R_SUCCESS
)
1250 dns_db_detachnode(db
, &node
);
1252 dns_dbiterator_destroy(&iter
);
1258 dns_cache_flushname(dns_cache_t
*cache
, dns_name_t
*name
) {
1259 return (dns_cache_flushnode(cache
, name
, ISC_FALSE
));
1263 dns_cache_flushnode(dns_cache_t
*cache
, dns_name_t
*name
,
1266 isc_result_t result
;
1267 dns_dbnode_t
*node
= NULL
;
1268 dns_db_t
*db
= NULL
;
1270 if (dns_name_equal(name
, dns_rootname
))
1271 return (dns_cache_flush(cache
));
1274 if (cache
->db
!= NULL
)
1275 dns_db_attach(cache
->db
, &db
);
1276 UNLOCK(&cache
->lock
);
1278 return (ISC_R_SUCCESS
);
1281 result
= cleartree(cache
->db
, name
);
1283 result
= dns_db_findnode(cache
->db
, name
, ISC_FALSE
, &node
);
1284 if (result
== ISC_R_NOTFOUND
) {
1285 result
= ISC_R_SUCCESS
;
1288 if (result
!= ISC_R_SUCCESS
)
1290 result
= clearnode(cache
->db
, node
);
1291 dns_db_detachnode(cache
->db
, &node
);
1300 dns_cache_getstats(dns_cache_t
*cache
) {
1301 REQUIRE(VALID_CACHE(cache
));
1302 return (cache
->stats
);
1306 dns_cache_updatestats(dns_cache_t
*cache
, isc_result_t result
) {
1307 REQUIRE(VALID_CACHE(cache
));
1308 if (cache
->stats
== NULL
)
1313 case DNS_R_NCACHENXDOMAIN
:
1314 case DNS_R_NCACHENXRRSET
:
1319 isc_stats_increment(cache
->stats
,
1320 dns_cachestatscounter_queryhits
);
1323 isc_stats_increment(cache
->stats
,
1324 dns_cachestatscounter_querymisses
);
1329 * XXX: Much of the following code has been copied in from statschannel.c.
1330 * We should refactor this into a generic function in stats.c that can be
1331 * called from both places.
1335 isc_statsformat_t type
;
1336 void *arg
; /* type dependent argument */
1337 int ncounters
; /* for general statistics */
1338 int *counterindices
; /* for general statistics */
1339 isc_uint64_t
*countervalues
; /* for general statistics */
1340 isc_result_t result
;
1344 getcounter(isc_statscounter_t counter
, isc_uint64_t val
, void *arg
) {
1345 cache_dumparg_t
*dumparg
= arg
;
1347 REQUIRE(counter
< dumparg
->ncounters
);
1348 dumparg
->countervalues
[counter
] = val
;
1352 getcounters(isc_stats_t
*stats
, isc_statsformat_t type
, int ncounters
,
1353 int *indices
, isc_uint64_t
*values
)
1355 cache_dumparg_t dumparg
;
1357 memset(values
, 0, sizeof(values
[0]) * ncounters
);
1359 dumparg
.type
= type
;
1360 dumparg
.ncounters
= ncounters
;
1361 dumparg
.counterindices
= indices
;
1362 dumparg
.countervalues
= values
;
1364 isc_stats_dump(stats
, getcounter
, &dumparg
, ISC_STATSDUMP_VERBOSE
);
1368 dns_cache_dumpstats(dns_cache_t
*cache
, FILE *fp
) {
1369 int indices
[dns_cachestatscounter_max
];
1370 isc_uint64_t values
[dns_cachestatscounter_max
];
1372 REQUIRE(VALID_CACHE(cache
));
1374 getcounters(cache
->stats
, isc_statsformat_file
,
1375 dns_cachestatscounter_max
, indices
, values
);
1377 fprintf(fp
, "%20" ISC_PRINT_QUADFORMAT
"u %s\n",
1378 values
[dns_cachestatscounter_hits
],
1380 fprintf(fp
, "%20" ISC_PRINT_QUADFORMAT
"u %s\n",
1381 values
[dns_cachestatscounter_misses
],
1383 fprintf(fp
, "%20" ISC_PRINT_QUADFORMAT
"u %s\n",
1384 values
[dns_cachestatscounter_queryhits
],
1385 "cache hits (from query)");
1386 fprintf(fp
, "%20" ISC_PRINT_QUADFORMAT
"u %s\n",
1387 values
[dns_cachestatscounter_querymisses
],
1388 "cache misses (from query)");
1389 fprintf(fp
, "%20" ISC_PRINT_QUADFORMAT
"u %s\n",
1390 values
[dns_cachestatscounter_deletelru
],
1391 "cache records deleted due to memory exhaustion");
1392 fprintf(fp
, "%20" ISC_PRINT_QUADFORMAT
"u %s\n",
1393 values
[dns_cachestatscounter_deletettl
],
1394 "cache records deleted due to TTL expiration");
1395 fprintf(fp
, "%20u %s\n", dns_db_nodecount(cache
->db
),
1396 "cache database nodes");
1397 fprintf(fp
, "%20u %s\n", dns_db_hashsize(cache
->db
),
1398 "cache database hash buckets");
1400 fprintf(fp
, "%20u %s\n", (unsigned int) isc_mem_total(cache
->mctx
),
1401 "cache tree memory total");
1402 fprintf(fp
, "%20u %s\n", (unsigned int) isc_mem_inuse(cache
->mctx
),
1403 "cache tree memory in use");
1404 fprintf(fp
, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache
->mctx
),
1405 "cache tree highest memory in use");
1407 fprintf(fp
, "%20u %s\n", (unsigned int) isc_mem_total(cache
->hmctx
),
1408 "cache heap memory total");
1409 fprintf(fp
, "%20u %s\n", (unsigned int) isc_mem_inuse(cache
->hmctx
),
1410 "cache heap memory in use");
1411 fprintf(fp
, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache
->hmctx
),
1412 "cache heap highest memory in use");
1416 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
1418 renderstat(const char *name
, isc_uint64_t value
, xmlTextWriterPtr writer
) {
1421 TRY0(xmlTextWriterStartElement(writer
, ISC_XMLCHAR
"counter"));
1422 TRY0(xmlTextWriterWriteAttribute(writer
,
1423 ISC_XMLCHAR
"name", ISC_XMLCHAR name
));
1424 TRY0(xmlTextWriterWriteFormatString(writer
,
1425 "%" ISC_PRINT_QUADFORMAT
"u",
1427 TRY0(xmlTextWriterEndElement(writer
)); /* counter */
1434 dns_cache_renderxml(dns_cache_t
*cache
, xmlTextWriterPtr writer
) {
1435 int indices
[dns_cachestatscounter_max
];
1436 isc_uint64_t values
[dns_cachestatscounter_max
];
1439 REQUIRE(VALID_CACHE(cache
));
1441 getcounters(cache
->stats
, isc_statsformat_file
,
1442 dns_cachestatscounter_max
, indices
, values
);
1443 TRY0(renderstat("CacheHits",
1444 values
[dns_cachestatscounter_hits
], writer
));
1445 TRY0(renderstat("CacheMisses",
1446 values
[dns_cachestatscounter_misses
], writer
));
1447 TRY0(renderstat("QueryHits",
1448 values
[dns_cachestatscounter_queryhits
], writer
));
1449 TRY0(renderstat("QueryMisses",
1450 values
[dns_cachestatscounter_querymisses
], writer
));
1451 TRY0(renderstat("DeleteLRU",
1452 values
[dns_cachestatscounter_deletelru
], writer
));
1453 TRY0(renderstat("DeleteTTL",
1454 values
[dns_cachestatscounter_deletettl
], writer
));
1456 TRY0(renderstat("CacheNodes", dns_db_nodecount(cache
->db
), writer
));
1457 TRY0(renderstat("CacheBuckets", dns_db_hashsize(cache
->db
), writer
));
1459 TRY0(renderstat("TreeMemTotal", isc_mem_total(cache
->mctx
), writer
));
1460 TRY0(renderstat("TreeMemInUse", isc_mem_inuse(cache
->mctx
), writer
));
1461 TRY0(renderstat("TreeMemMax", isc_mem_maxinuse(cache
->mctx
), writer
));
1463 TRY0(renderstat("HeapMemTotal", isc_mem_total(cache
->hmctx
), writer
));
1464 TRY0(renderstat("HeapMemInUse", isc_mem_inuse(cache
->hmctx
), writer
));
1465 TRY0(renderstat("HeapMemMax", isc_mem_maxinuse(cache
->hmctx
), writer
));
1472 #define CHECKMEM(m) do { \
1474 result = ISC_R_NOMEMORY;\
1477 } while(/*CONSTCOND*/0)
1480 dns_cache_renderjson(dns_cache_t
*cache
, json_object
*cstats
) {
1481 isc_result_t result
= ISC_R_SUCCESS
;
1482 int indices
[dns_cachestatscounter_max
];
1483 isc_uint64_t values
[dns_cachestatscounter_max
];
1486 REQUIRE(VALID_CACHE(cache
));
1488 getcounters(cache
->stats
, isc_statsformat_file
,
1489 dns_cachestatscounter_max
, indices
, values
);
1491 obj
= json_object_new_int64(values
[dns_cachestatscounter_hits
]);
1493 json_object_object_add(cstats
, "CacheHits", obj
);
1495 obj
= json_object_new_int64(values
[dns_cachestatscounter_misses
]);
1497 json_object_object_add(cstats
, "CacheMisses", obj
);
1499 obj
= json_object_new_int64(values
[dns_cachestatscounter_queryhits
]);
1501 json_object_object_add(cstats
, "QueryHits", obj
);
1503 obj
= json_object_new_int64(values
[dns_cachestatscounter_querymisses
]);
1505 json_object_object_add(cstats
, "QueryMisses", obj
);
1507 obj
= json_object_new_int64(values
[dns_cachestatscounter_deletelru
]);
1509 json_object_object_add(cstats
, "DeleteLRU", obj
);
1511 obj
= json_object_new_int64(values
[dns_cachestatscounter_deletettl
]);
1513 json_object_object_add(cstats
, "DeleteTTL", obj
);
1515 obj
= json_object_new_int64(dns_db_nodecount(cache
->db
));
1517 json_object_object_add(cstats
, "CacheNodes", obj
);
1519 obj
= json_object_new_int64(dns_db_hashsize(cache
->db
));
1521 json_object_object_add(cstats
, "CacheBuckets", obj
);
1523 obj
= json_object_new_int64(isc_mem_total(cache
->mctx
));
1525 json_object_object_add(cstats
, "TreeMemTotal", obj
);
1527 obj
= json_object_new_int64(isc_mem_inuse(cache
->mctx
));
1529 json_object_object_add(cstats
, "TreeMemInUse", obj
);
1531 obj
= json_object_new_int64(isc_mem_maxinuse(cache
->mctx
));
1533 json_object_object_add(cstats
, "HeapMemMax", obj
);
1535 obj
= json_object_new_int64(isc_mem_total(cache
->hmctx
));
1537 json_object_object_add(cstats
, "HeapMemTotal", obj
);
1539 obj
= json_object_new_int64(isc_mem_inuse(cache
->hmctx
));
1541 json_object_object_add(cstats
, "HeapMemInUse", obj
);
1543 obj
= json_object_new_int64(isc_mem_maxinuse(cache
->hmctx
));
1545 json_object_object_add(cstats
, "HeapMemMax", obj
);
1547 result
= ISC_R_SUCCESS
;