xref: /minix3/external/bsd/bind/dist/lib/dns/cache.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
1*00b67f09SDavid van Moolenbroek /*	$NetBSD: cache.c,v 1.8 2014/12/10 04:37:58 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2009, 2011-2013  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 1999-2003  Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek  *
7*00b67f09SDavid van Moolenbroek  * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek  *
11*00b67f09SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek  * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek  */
19*00b67f09SDavid van Moolenbroek 
20*00b67f09SDavid van Moolenbroek /* Id: cache.c,v 1.91 2011/08/26 05:12:56 marka Exp  */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek 
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek 
26*00b67f09SDavid van Moolenbroek #include <isc/json.h>
27*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
28*00b67f09SDavid van Moolenbroek #include <isc/print.h>
29*00b67f09SDavid van Moolenbroek #include <isc/string.h>
30*00b67f09SDavid van Moolenbroek #include <isc/stats.h>
31*00b67f09SDavid van Moolenbroek #include <isc/task.h>
32*00b67f09SDavid van Moolenbroek #include <isc/time.h>
33*00b67f09SDavid van Moolenbroek #include <isc/timer.h>
34*00b67f09SDavid van Moolenbroek #include <isc/util.h>
35*00b67f09SDavid van Moolenbroek #include <isc/xml.h>
36*00b67f09SDavid van Moolenbroek 
37*00b67f09SDavid van Moolenbroek #include <dns/cache.h>
38*00b67f09SDavid van Moolenbroek #include <dns/db.h>
39*00b67f09SDavid van Moolenbroek #include <dns/dbiterator.h>
40*00b67f09SDavid van Moolenbroek #include <dns/events.h>
41*00b67f09SDavid van Moolenbroek #include <dns/lib.h>
42*00b67f09SDavid van Moolenbroek #include <dns/log.h>
43*00b67f09SDavid van Moolenbroek #include <dns/masterdump.h>
44*00b67f09SDavid van Moolenbroek #include <dns/rdata.h>
45*00b67f09SDavid van Moolenbroek #include <dns/rdataset.h>
46*00b67f09SDavid van Moolenbroek #include <dns/rdatasetiter.h>
47*00b67f09SDavid van Moolenbroek #include <dns/result.h>
48*00b67f09SDavid van Moolenbroek #include <dns/stats.h>
49*00b67f09SDavid van Moolenbroek 
50*00b67f09SDavid van Moolenbroek #include "rbtdb.h"
51*00b67f09SDavid van Moolenbroek 
52*00b67f09SDavid van Moolenbroek #define CACHE_MAGIC		ISC_MAGIC('$', '$', '$', '$')
53*00b67f09SDavid van Moolenbroek #define VALID_CACHE(cache)	ISC_MAGIC_VALID(cache, CACHE_MAGIC)
54*00b67f09SDavid van Moolenbroek 
55*00b67f09SDavid van Moolenbroek /*!
56*00b67f09SDavid van Moolenbroek  * Control incremental cleaning.
57*00b67f09SDavid van Moolenbroek  * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
58*00b67f09SDavid van Moolenbroek  * See also DNS_CACHE_CLEANERINCREMENT
59*00b67f09SDavid van Moolenbroek  */
60*00b67f09SDavid van Moolenbroek #define DNS_CACHE_MINSIZE	2097152U /*%< Bytes.  2097152 = 2 MB */
61*00b67f09SDavid van Moolenbroek /*!
62*00b67f09SDavid van Moolenbroek  * Control incremental cleaning.
63*00b67f09SDavid van Moolenbroek  * CLEANERINCREMENT is how many nodes are examined in one pass.
64*00b67f09SDavid van Moolenbroek  * See also DNS_CACHE_MINSIZE
65*00b67f09SDavid van Moolenbroek  */
66*00b67f09SDavid van Moolenbroek #define DNS_CACHE_CLEANERINCREMENT	1000U	/*%< Number of nodes. */
67*00b67f09SDavid van Moolenbroek 
68*00b67f09SDavid van Moolenbroek /***
69*00b67f09SDavid van Moolenbroek  ***	Types
70*00b67f09SDavid van Moolenbroek  ***/
71*00b67f09SDavid van Moolenbroek 
72*00b67f09SDavid van Moolenbroek /*
73*00b67f09SDavid van Moolenbroek  * A cache_cleaner_t encapsulates the state of the periodic
74*00b67f09SDavid van Moolenbroek  * cache cleaning.
75*00b67f09SDavid van Moolenbroek  */
76*00b67f09SDavid van Moolenbroek 
77*00b67f09SDavid van Moolenbroek typedef struct cache_cleaner cache_cleaner_t;
78*00b67f09SDavid van Moolenbroek 
79*00b67f09SDavid van Moolenbroek typedef enum {
80*00b67f09SDavid van Moolenbroek 	cleaner_s_idle,	/*%< Waiting for cleaning-interval to expire. */
81*00b67f09SDavid van Moolenbroek 	cleaner_s_busy,	/*%< Currently cleaning. */
82*00b67f09SDavid van Moolenbroek 	cleaner_s_done	/*%< Freed enough memory after being overmem. */
83*00b67f09SDavid van Moolenbroek } cleaner_state_t;
84*00b67f09SDavid van Moolenbroek 
85*00b67f09SDavid van Moolenbroek /*
86*00b67f09SDavid van Moolenbroek  * Convenience macros for comprehensive assertion checking.
87*00b67f09SDavid van Moolenbroek  */
88*00b67f09SDavid van Moolenbroek #define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
89*00b67f09SDavid van Moolenbroek 			 (c)->resched_event != NULL)
90*00b67f09SDavid van Moolenbroek #define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
91*00b67f09SDavid van Moolenbroek 			 (c)->iterator != NULL && \
92*00b67f09SDavid van Moolenbroek 			 (c)->resched_event == NULL)
93*00b67f09SDavid van Moolenbroek 
94*00b67f09SDavid van Moolenbroek /*%
95*00b67f09SDavid van Moolenbroek  * Accesses to a cache cleaner object are synchronized through
96*00b67f09SDavid van Moolenbroek  * task/event serialization, or locked from the cache object.
97*00b67f09SDavid van Moolenbroek  */
98*00b67f09SDavid van Moolenbroek struct cache_cleaner {
99*00b67f09SDavid van Moolenbroek 	isc_mutex_t	lock;
100*00b67f09SDavid van Moolenbroek 	/*%<
101*00b67f09SDavid van Moolenbroek 	 * Locks overmem_event, overmem.  Note: never allocate memory
102*00b67f09SDavid van Moolenbroek 	 * while holding this lock - that could lead to deadlock since
103*00b67f09SDavid van Moolenbroek 	 * the lock is take by water() which is called from the memory
104*00b67f09SDavid van Moolenbroek 	 * allocator.
105*00b67f09SDavid van Moolenbroek 	 */
106*00b67f09SDavid van Moolenbroek 
107*00b67f09SDavid van Moolenbroek 	dns_cache_t	*cache;
108*00b67f09SDavid van Moolenbroek 	isc_task_t	*task;
109*00b67f09SDavid van Moolenbroek 	unsigned int	cleaning_interval; /*% The cleaning-interval from
110*00b67f09SDavid van Moolenbroek 					      named.conf, in seconds. */
111*00b67f09SDavid van Moolenbroek 	isc_timer_t	*cleaning_timer;
112*00b67f09SDavid van Moolenbroek 	isc_event_t	*resched_event;	/*% Sent by cleaner task to
113*00b67f09SDavid van Moolenbroek 					   itself to reschedule */
114*00b67f09SDavid van Moolenbroek 	isc_event_t	*overmem_event;
115*00b67f09SDavid van Moolenbroek 
116*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *iterator;
117*00b67f09SDavid van Moolenbroek 	unsigned int	increment;	/*% Number of names to
118*00b67f09SDavid van Moolenbroek 					   clean in one increment */
119*00b67f09SDavid van Moolenbroek 	cleaner_state_t	state;		/*% Idle/Busy. */
120*00b67f09SDavid van Moolenbroek 	isc_boolean_t	overmem;	/*% The cache is in an overmem state. */
121*00b67f09SDavid van Moolenbroek 	isc_boolean_t	 replaceiterator;
122*00b67f09SDavid van Moolenbroek };
123*00b67f09SDavid van Moolenbroek 
124*00b67f09SDavid van Moolenbroek /*%
125*00b67f09SDavid van Moolenbroek  * The actual cache object.
126*00b67f09SDavid van Moolenbroek  */
127*00b67f09SDavid van Moolenbroek 
128*00b67f09SDavid van Moolenbroek struct dns_cache {
129*00b67f09SDavid van Moolenbroek 	/* Unlocked. */
130*00b67f09SDavid van Moolenbroek 	unsigned int		magic;
131*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
132*00b67f09SDavid van Moolenbroek 	isc_mutex_t		filelock;
133*00b67f09SDavid van Moolenbroek 	isc_mem_t		*mctx;		/* Main cache memory */
134*00b67f09SDavid van Moolenbroek 	isc_mem_t		*hmctx;		/* Heap memory */
135*00b67f09SDavid van Moolenbroek 	char			*name;
136*00b67f09SDavid van Moolenbroek 
137*00b67f09SDavid van Moolenbroek 	/* Locked by 'lock'. */
138*00b67f09SDavid van Moolenbroek 	int			references;
139*00b67f09SDavid van Moolenbroek 	int			live_tasks;
140*00b67f09SDavid van Moolenbroek 	dns_rdataclass_t	rdclass;
141*00b67f09SDavid van Moolenbroek 	dns_db_t		*db;
142*00b67f09SDavid van Moolenbroek 	cache_cleaner_t		cleaner;
143*00b67f09SDavid van Moolenbroek 	char			*db_type;
144*00b67f09SDavid van Moolenbroek 	int			db_argc;
145*00b67f09SDavid van Moolenbroek 	char			**db_argv;
146*00b67f09SDavid van Moolenbroek 	size_t			size;
147*00b67f09SDavid van Moolenbroek 	isc_stats_t		*stats;
148*00b67f09SDavid van Moolenbroek 
149*00b67f09SDavid van Moolenbroek 	/* Locked by 'filelock'. */
150*00b67f09SDavid van Moolenbroek 	char			*filename;
151*00b67f09SDavid van Moolenbroek 	/* Access to the on-disk cache file is also locked by 'filelock'. */
152*00b67f09SDavid van Moolenbroek };
153*00b67f09SDavid van Moolenbroek 
154*00b67f09SDavid van Moolenbroek /***
155*00b67f09SDavid van Moolenbroek  ***	Functions
156*00b67f09SDavid van Moolenbroek  ***/
157*00b67f09SDavid van Moolenbroek 
158*00b67f09SDavid van Moolenbroek static isc_result_t
159*00b67f09SDavid van Moolenbroek cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
160*00b67f09SDavid van Moolenbroek 		   isc_timermgr_t *timermgr, cache_cleaner_t *cleaner);
161*00b67f09SDavid van Moolenbroek 
162*00b67f09SDavid van Moolenbroek static void
163*00b67f09SDavid van Moolenbroek cleaning_timer_action(isc_task_t *task, isc_event_t *event);
164*00b67f09SDavid van Moolenbroek 
165*00b67f09SDavid van Moolenbroek static void
166*00b67f09SDavid van Moolenbroek incremental_cleaning_action(isc_task_t *task, isc_event_t *event);
167*00b67f09SDavid van Moolenbroek 
168*00b67f09SDavid van Moolenbroek static void
169*00b67f09SDavid van Moolenbroek cleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
170*00b67f09SDavid van Moolenbroek 
171*00b67f09SDavid van Moolenbroek static void
172*00b67f09SDavid van Moolenbroek overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
173*00b67f09SDavid van Moolenbroek 
174*00b67f09SDavid van Moolenbroek static inline isc_result_t
cache_create_db(dns_cache_t * cache,dns_db_t ** db)175*00b67f09SDavid van Moolenbroek cache_create_db(dns_cache_t *cache, dns_db_t **db) {
176*00b67f09SDavid van Moolenbroek 	return (dns_db_create(cache->mctx, cache->db_type, dns_rootname,
177*00b67f09SDavid van Moolenbroek 			      dns_dbtype_cache, cache->rdclass,
178*00b67f09SDavid van Moolenbroek 			      cache->db_argc, cache->db_argv, db));
179*00b67f09SDavid van Moolenbroek }
180*00b67f09SDavid van Moolenbroek 
181*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_create(isc_mem_t * cmctx,isc_taskmgr_t * taskmgr,isc_timermgr_t * timermgr,dns_rdataclass_t rdclass,const char * db_type,unsigned int db_argc,char ** db_argv,dns_cache_t ** cachep)182*00b67f09SDavid van Moolenbroek dns_cache_create(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
183*00b67f09SDavid van Moolenbroek 		 isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
184*00b67f09SDavid van Moolenbroek 		 const char *db_type, unsigned int db_argc, char **db_argv,
185*00b67f09SDavid van Moolenbroek 		 dns_cache_t **cachep)
186*00b67f09SDavid van Moolenbroek {
187*00b67f09SDavid van Moolenbroek 	return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass, "",
188*00b67f09SDavid van Moolenbroek 				  db_type, db_argc, db_argv, cachep));
189*00b67f09SDavid van Moolenbroek }
190*00b67f09SDavid van Moolenbroek 
191*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_create2(isc_mem_t * cmctx,isc_taskmgr_t * taskmgr,isc_timermgr_t * timermgr,dns_rdataclass_t rdclass,const char * cachename,const char * db_type,unsigned int db_argc,char ** db_argv,dns_cache_t ** cachep)192*00b67f09SDavid van Moolenbroek dns_cache_create2(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
193*00b67f09SDavid van Moolenbroek 		  isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
194*00b67f09SDavid van Moolenbroek 		  const char *cachename, const char *db_type,
195*00b67f09SDavid van Moolenbroek 		  unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
196*00b67f09SDavid van Moolenbroek {
197*00b67f09SDavid van Moolenbroek 	return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass,
198*00b67f09SDavid van Moolenbroek 				  cachename, db_type, db_argc, db_argv,
199*00b67f09SDavid van Moolenbroek 				  cachep));
200*00b67f09SDavid van Moolenbroek }
201*00b67f09SDavid van Moolenbroek 
202*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_create3(isc_mem_t * cmctx,isc_mem_t * hmctx,isc_taskmgr_t * taskmgr,isc_timermgr_t * timermgr,dns_rdataclass_t rdclass,const char * cachename,const char * db_type,unsigned int db_argc,char ** db_argv,dns_cache_t ** cachep)203*00b67f09SDavid van Moolenbroek dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr,
204*00b67f09SDavid van Moolenbroek 		  isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
205*00b67f09SDavid van Moolenbroek 		  const char *cachename, const char *db_type,
206*00b67f09SDavid van Moolenbroek 		  unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
207*00b67f09SDavid van Moolenbroek {
208*00b67f09SDavid van Moolenbroek 	isc_result_t result;
209*00b67f09SDavid van Moolenbroek 	dns_cache_t *cache;
210*00b67f09SDavid van Moolenbroek 	int i, extra = 0;
211*00b67f09SDavid van Moolenbroek 	isc_task_t *dbtask;
212*00b67f09SDavid van Moolenbroek 
213*00b67f09SDavid van Moolenbroek 	REQUIRE(cachep != NULL);
214*00b67f09SDavid van Moolenbroek 	REQUIRE(*cachep == NULL);
215*00b67f09SDavid van Moolenbroek 	REQUIRE(cmctx != NULL);
216*00b67f09SDavid van Moolenbroek 	REQUIRE(hmctx != NULL);
217*00b67f09SDavid van Moolenbroek 	REQUIRE(cachename != NULL);
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek 	cache = isc_mem_get(cmctx, sizeof(*cache));
220*00b67f09SDavid van Moolenbroek 	if (cache == NULL)
221*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
222*00b67f09SDavid van Moolenbroek 
223*00b67f09SDavid van Moolenbroek 	cache->mctx = cache->hmctx = NULL;
224*00b67f09SDavid van Moolenbroek 	isc_mem_attach(cmctx, &cache->mctx);
225*00b67f09SDavid van Moolenbroek 	isc_mem_attach(hmctx, &cache->hmctx);
226*00b67f09SDavid van Moolenbroek 
227*00b67f09SDavid van Moolenbroek 	cache->name = NULL;
228*00b67f09SDavid van Moolenbroek 	if (cachename != NULL) {
229*00b67f09SDavid van Moolenbroek 		cache->name = isc_mem_strdup(cmctx, cachename);
230*00b67f09SDavid van Moolenbroek 		if (cache->name == NULL) {
231*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
232*00b67f09SDavid van Moolenbroek 			goto cleanup_mem;
233*00b67f09SDavid van Moolenbroek 		}
234*00b67f09SDavid van Moolenbroek 	}
235*00b67f09SDavid van Moolenbroek 
236*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&cache->lock);
237*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
238*00b67f09SDavid van Moolenbroek 		goto cleanup_mem;
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&cache->filelock);
241*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
242*00b67f09SDavid van Moolenbroek 		goto cleanup_lock;
243*00b67f09SDavid van Moolenbroek 
244*00b67f09SDavid van Moolenbroek 	cache->references = 1;
245*00b67f09SDavid van Moolenbroek 	cache->live_tasks = 0;
246*00b67f09SDavid van Moolenbroek 	cache->rdclass = rdclass;
247*00b67f09SDavid van Moolenbroek 
248*00b67f09SDavid van Moolenbroek 	cache->stats = NULL;
249*00b67f09SDavid van Moolenbroek 	result = isc_stats_create(cmctx, &cache->stats,
250*00b67f09SDavid van Moolenbroek 				  dns_cachestatscounter_max);
251*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
252*00b67f09SDavid van Moolenbroek 		goto cleanup_filelock;
253*00b67f09SDavid van Moolenbroek 
254*00b67f09SDavid van Moolenbroek 	cache->db_type = isc_mem_strdup(cmctx, db_type);
255*00b67f09SDavid van Moolenbroek 	if (cache->db_type == NULL) {
256*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;
257*00b67f09SDavid van Moolenbroek 		goto cleanup_stats;
258*00b67f09SDavid van Moolenbroek 	}
259*00b67f09SDavid van Moolenbroek 
260*00b67f09SDavid van Moolenbroek 	/*
261*00b67f09SDavid van Moolenbroek 	 * For databases of type "rbt" we pass hmctx to dns_db_create()
262*00b67f09SDavid van Moolenbroek 	 * via cache->db_argv, followed by the rest of the arguments in
263*00b67f09SDavid van Moolenbroek 	 * db_argv (of which there really shouldn't be any).
264*00b67f09SDavid van Moolenbroek 	 */
265*00b67f09SDavid van Moolenbroek 	if (strcmp(cache->db_type, "rbt") == 0)
266*00b67f09SDavid van Moolenbroek 		extra = 1;
267*00b67f09SDavid van Moolenbroek 
268*00b67f09SDavid van Moolenbroek 	cache->db_argc = db_argc + extra;
269*00b67f09SDavid van Moolenbroek 	cache->db_argv = NULL;
270*00b67f09SDavid van Moolenbroek 
271*00b67f09SDavid van Moolenbroek 	if (cache->db_argc != 0) {
272*00b67f09SDavid van Moolenbroek 		cache->db_argv = isc_mem_get(cmctx,
273*00b67f09SDavid van Moolenbroek 					     cache->db_argc * sizeof(char *));
274*00b67f09SDavid van Moolenbroek 		if (cache->db_argv == NULL) {
275*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
276*00b67f09SDavid van Moolenbroek 			goto cleanup_dbtype;
277*00b67f09SDavid van Moolenbroek 		}
278*00b67f09SDavid van Moolenbroek 
279*00b67f09SDavid van Moolenbroek 		for (i = 0; i < cache->db_argc; i++)
280*00b67f09SDavid van Moolenbroek 			cache->db_argv[i] = NULL;
281*00b67f09SDavid van Moolenbroek 
282*00b67f09SDavid van Moolenbroek 		cache->db_argv[0] = (char *) hmctx;
283*00b67f09SDavid van Moolenbroek 		for (i = extra; i < cache->db_argc; i++) {
284*00b67f09SDavid van Moolenbroek 			cache->db_argv[i] = isc_mem_strdup(cmctx,
285*00b67f09SDavid van Moolenbroek 							   db_argv[i - extra]);
286*00b67f09SDavid van Moolenbroek 			if (cache->db_argv[i] == NULL) {
287*00b67f09SDavid van Moolenbroek 				result = ISC_R_NOMEMORY;
288*00b67f09SDavid van Moolenbroek 				goto cleanup_dbargv;
289*00b67f09SDavid van Moolenbroek 			}
290*00b67f09SDavid van Moolenbroek 		}
291*00b67f09SDavid van Moolenbroek 	}
292*00b67f09SDavid van Moolenbroek 
293*00b67f09SDavid van Moolenbroek 	/*
294*00b67f09SDavid van Moolenbroek 	 * Create the database
295*00b67f09SDavid van Moolenbroek 	 */
296*00b67f09SDavid van Moolenbroek 	cache->db = NULL;
297*00b67f09SDavid van Moolenbroek 	result = cache_create_db(cache, &cache->db);
298*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
299*00b67f09SDavid van Moolenbroek 		goto cleanup_dbargv;
300*00b67f09SDavid van Moolenbroek 	if (taskmgr != NULL) {
301*00b67f09SDavid van Moolenbroek 		dbtask = NULL;
302*00b67f09SDavid van Moolenbroek 		result = isc_task_create(taskmgr, 1, &dbtask);
303*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
304*00b67f09SDavid van Moolenbroek 			goto cleanup_db;
305*00b67f09SDavid van Moolenbroek 		dns_db_settask(cache->db, dbtask);
306*00b67f09SDavid van Moolenbroek 		isc_task_detach(&dbtask);
307*00b67f09SDavid van Moolenbroek 	}
308*00b67f09SDavid van Moolenbroek 
309*00b67f09SDavid van Moolenbroek 	cache->filename = NULL;
310*00b67f09SDavid van Moolenbroek 
311*00b67f09SDavid van Moolenbroek 	cache->magic = CACHE_MAGIC;
312*00b67f09SDavid van Moolenbroek 
313*00b67f09SDavid van Moolenbroek 	/*
314*00b67f09SDavid van Moolenbroek 	 * RBT-type cache DB has its own mechanism of cache cleaning and doesn't
315*00b67f09SDavid van Moolenbroek 	 * need the control of the generic cleaner.
316*00b67f09SDavid van Moolenbroek 	 */
317*00b67f09SDavid van Moolenbroek 	if (strcmp(db_type, "rbt") == 0)
318*00b67f09SDavid van Moolenbroek 		result = cache_cleaner_init(cache, NULL, NULL, &cache->cleaner);
319*00b67f09SDavid van Moolenbroek 	else {
320*00b67f09SDavid van Moolenbroek 		result = cache_cleaner_init(cache, taskmgr, timermgr,
321*00b67f09SDavid van Moolenbroek 					    &cache->cleaner);
322*00b67f09SDavid van Moolenbroek 	}
323*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
324*00b67f09SDavid van Moolenbroek 		goto cleanup_db;
325*00b67f09SDavid van Moolenbroek 
326*00b67f09SDavid van Moolenbroek 	result = dns_db_setcachestats(cache->db, cache->stats);
327*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
328*00b67f09SDavid van Moolenbroek 		goto cleanup_db;
329*00b67f09SDavid van Moolenbroek 
330*00b67f09SDavid van Moolenbroek 
331*00b67f09SDavid van Moolenbroek 	*cachep = cache;
332*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
333*00b67f09SDavid van Moolenbroek 
334*00b67f09SDavid van Moolenbroek  cleanup_db:
335*00b67f09SDavid van Moolenbroek 	dns_db_detach(&cache->db);
336*00b67f09SDavid van Moolenbroek  cleanup_dbargv:
337*00b67f09SDavid van Moolenbroek 	for (i = extra; i < cache->db_argc; i++)
338*00b67f09SDavid van Moolenbroek 		if (cache->db_argv[i] != NULL)
339*00b67f09SDavid van Moolenbroek 			isc_mem_free(cmctx, cache->db_argv[i]);
340*00b67f09SDavid van Moolenbroek 	if (cache->db_argv != NULL)
341*00b67f09SDavid van Moolenbroek 		isc_mem_put(cmctx, cache->db_argv,
342*00b67f09SDavid van Moolenbroek 			    cache->db_argc * sizeof(char *));
343*00b67f09SDavid van Moolenbroek  cleanup_dbtype:
344*00b67f09SDavid van Moolenbroek 	isc_mem_free(cmctx, cache->db_type);
345*00b67f09SDavid van Moolenbroek  cleanup_filelock:
346*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&cache->filelock);
347*00b67f09SDavid van Moolenbroek  cleanup_stats:
348*00b67f09SDavid van Moolenbroek 	isc_stats_detach(&cache->stats);
349*00b67f09SDavid van Moolenbroek  cleanup_lock:
350*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&cache->lock);
351*00b67f09SDavid van Moolenbroek  cleanup_mem:
352*00b67f09SDavid van Moolenbroek 	if (cache->name != NULL)
353*00b67f09SDavid van Moolenbroek 		isc_mem_free(cmctx, cache->name);
354*00b67f09SDavid van Moolenbroek 	isc_mem_detach(&cache->hmctx);
355*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
356*00b67f09SDavid van Moolenbroek 	return (result);
357*00b67f09SDavid van Moolenbroek }
358*00b67f09SDavid van Moolenbroek 
359*00b67f09SDavid van Moolenbroek static void
cache_free(dns_cache_t * cache)360*00b67f09SDavid van Moolenbroek cache_free(dns_cache_t *cache) {
361*00b67f09SDavid van Moolenbroek 	int i;
362*00b67f09SDavid van Moolenbroek 
363*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
364*00b67f09SDavid van Moolenbroek 	REQUIRE(cache->references == 0);
365*00b67f09SDavid van Moolenbroek 
366*00b67f09SDavid van Moolenbroek 	isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0);
367*00b67f09SDavid van Moolenbroek 
368*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.task != NULL)
369*00b67f09SDavid van Moolenbroek 		isc_task_detach(&cache->cleaner.task);
370*00b67f09SDavid van Moolenbroek 
371*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.overmem_event != NULL)
372*00b67f09SDavid van Moolenbroek 		isc_event_free(&cache->cleaner.overmem_event);
373*00b67f09SDavid van Moolenbroek 
374*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.resched_event != NULL)
375*00b67f09SDavid van Moolenbroek 		isc_event_free(&cache->cleaner.resched_event);
376*00b67f09SDavid van Moolenbroek 
377*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.iterator != NULL)
378*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&cache->cleaner.iterator);
379*00b67f09SDavid van Moolenbroek 
380*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&cache->cleaner.lock);
381*00b67f09SDavid van Moolenbroek 
382*00b67f09SDavid van Moolenbroek 	if (cache->filename) {
383*00b67f09SDavid van Moolenbroek 		isc_mem_free(cache->mctx, cache->filename);
384*00b67f09SDavid van Moolenbroek 		cache->filename = NULL;
385*00b67f09SDavid van Moolenbroek 	}
386*00b67f09SDavid van Moolenbroek 
387*00b67f09SDavid van Moolenbroek 	if (cache->db != NULL)
388*00b67f09SDavid van Moolenbroek 		dns_db_detach(&cache->db);
389*00b67f09SDavid van Moolenbroek 
390*00b67f09SDavid van Moolenbroek 	if (cache->db_argv != NULL) {
391*00b67f09SDavid van Moolenbroek 		/*
392*00b67f09SDavid van Moolenbroek 		 * We don't free db_argv[0] in "rbt" cache databases
393*00b67f09SDavid van Moolenbroek 		 * as it's a pointer to hmctx
394*00b67f09SDavid van Moolenbroek 		 */
395*00b67f09SDavid van Moolenbroek 		int extra = 0;
396*00b67f09SDavid van Moolenbroek 		if (strcmp(cache->db_type, "rbt") == 0)
397*00b67f09SDavid van Moolenbroek 			extra = 1;
398*00b67f09SDavid van Moolenbroek 		for (i = extra; i < cache->db_argc; i++)
399*00b67f09SDavid van Moolenbroek 			if (cache->db_argv[i] != NULL)
400*00b67f09SDavid van Moolenbroek 				isc_mem_free(cache->mctx, cache->db_argv[i]);
401*00b67f09SDavid van Moolenbroek 		isc_mem_put(cache->mctx, cache->db_argv,
402*00b67f09SDavid van Moolenbroek 			    cache->db_argc * sizeof(char *));
403*00b67f09SDavid van Moolenbroek 	}
404*00b67f09SDavid van Moolenbroek 
405*00b67f09SDavid van Moolenbroek 	if (cache->db_type != NULL)
406*00b67f09SDavid van Moolenbroek 		isc_mem_free(cache->mctx, cache->db_type);
407*00b67f09SDavid van Moolenbroek 
408*00b67f09SDavid van Moolenbroek 	if (cache->name != NULL)
409*00b67f09SDavid van Moolenbroek 		isc_mem_free(cache->mctx, cache->name);
410*00b67f09SDavid van Moolenbroek 
411*00b67f09SDavid van Moolenbroek 	if (cache->stats != NULL)
412*00b67f09SDavid van Moolenbroek 		isc_stats_detach(&cache->stats);
413*00b67f09SDavid van Moolenbroek 
414*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&cache->lock);
415*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&cache->filelock);
416*00b67f09SDavid van Moolenbroek 
417*00b67f09SDavid van Moolenbroek 	cache->magic = 0;
418*00b67f09SDavid van Moolenbroek 	isc_mem_detach(&cache->hmctx);
419*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
420*00b67f09SDavid van Moolenbroek }
421*00b67f09SDavid van Moolenbroek 
422*00b67f09SDavid van Moolenbroek 
423*00b67f09SDavid van Moolenbroek void
dns_cache_attach(dns_cache_t * cache,dns_cache_t ** targetp)424*00b67f09SDavid van Moolenbroek dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) {
425*00b67f09SDavid van Moolenbroek 
426*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
427*00b67f09SDavid van Moolenbroek 	REQUIRE(targetp != NULL && *targetp == NULL);
428*00b67f09SDavid van Moolenbroek 
429*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
430*00b67f09SDavid van Moolenbroek 	cache->references++;
431*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
432*00b67f09SDavid van Moolenbroek 
433*00b67f09SDavid van Moolenbroek 	*targetp = cache;
434*00b67f09SDavid van Moolenbroek }
435*00b67f09SDavid van Moolenbroek 
436*00b67f09SDavid van Moolenbroek void
dns_cache_detach(dns_cache_t ** cachep)437*00b67f09SDavid van Moolenbroek dns_cache_detach(dns_cache_t **cachep) {
438*00b67f09SDavid van Moolenbroek 	dns_cache_t *cache;
439*00b67f09SDavid van Moolenbroek 	isc_boolean_t free_cache = ISC_FALSE;
440*00b67f09SDavid van Moolenbroek 
441*00b67f09SDavid van Moolenbroek 	REQUIRE(cachep != NULL);
442*00b67f09SDavid van Moolenbroek 	cache = *cachep;
443*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
444*00b67f09SDavid van Moolenbroek 
445*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
446*00b67f09SDavid van Moolenbroek 	REQUIRE(cache->references > 0);
447*00b67f09SDavid van Moolenbroek 	cache->references--;
448*00b67f09SDavid van Moolenbroek 	if (cache->references == 0) {
449*00b67f09SDavid van Moolenbroek 		cache->cleaner.overmem = ISC_FALSE;
450*00b67f09SDavid van Moolenbroek 		free_cache = ISC_TRUE;
451*00b67f09SDavid van Moolenbroek 	}
452*00b67f09SDavid van Moolenbroek 
453*00b67f09SDavid van Moolenbroek 	*cachep = NULL;
454*00b67f09SDavid van Moolenbroek 
455*00b67f09SDavid van Moolenbroek 	if (free_cache) {
456*00b67f09SDavid van Moolenbroek 		/*
457*00b67f09SDavid van Moolenbroek 		 * When the cache is shut down, dump it to a file if one is
458*00b67f09SDavid van Moolenbroek 		 * specified.
459*00b67f09SDavid van Moolenbroek 		 */
460*00b67f09SDavid van Moolenbroek 		isc_result_t result = dns_cache_dump(cache);
461*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
462*00b67f09SDavid van Moolenbroek 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
463*00b67f09SDavid van Moolenbroek 				      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
464*00b67f09SDavid van Moolenbroek 				      "error dumping cache: %s ",
465*00b67f09SDavid van Moolenbroek 				      isc_result_totext(result));
466*00b67f09SDavid van Moolenbroek 
467*00b67f09SDavid van Moolenbroek 		/*
468*00b67f09SDavid van Moolenbroek 		 * If the cleaner task exists, let it free the cache.
469*00b67f09SDavid van Moolenbroek 		 */
470*00b67f09SDavid van Moolenbroek 		if (cache->live_tasks > 0) {
471*00b67f09SDavid van Moolenbroek 			isc_task_shutdown(cache->cleaner.task);
472*00b67f09SDavid van Moolenbroek 			free_cache = ISC_FALSE;
473*00b67f09SDavid van Moolenbroek 		}
474*00b67f09SDavid van Moolenbroek 	}
475*00b67f09SDavid van Moolenbroek 
476*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
477*00b67f09SDavid van Moolenbroek 
478*00b67f09SDavid van Moolenbroek 	if (free_cache)
479*00b67f09SDavid van Moolenbroek 		cache_free(cache);
480*00b67f09SDavid van Moolenbroek }
481*00b67f09SDavid van Moolenbroek 
482*00b67f09SDavid van Moolenbroek void
dns_cache_attachdb(dns_cache_t * cache,dns_db_t ** dbp)483*00b67f09SDavid van Moolenbroek dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp) {
484*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
485*00b67f09SDavid van Moolenbroek 	REQUIRE(dbp != NULL && *dbp == NULL);
486*00b67f09SDavid van Moolenbroek 	REQUIRE(cache->db != NULL);
487*00b67f09SDavid van Moolenbroek 
488*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
489*00b67f09SDavid van Moolenbroek 	dns_db_attach(cache->db, dbp);
490*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
491*00b67f09SDavid van Moolenbroek 
492*00b67f09SDavid van Moolenbroek }
493*00b67f09SDavid van Moolenbroek 
494*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_setfilename(dns_cache_t * cache,const char * filename)495*00b67f09SDavid van Moolenbroek dns_cache_setfilename(dns_cache_t *cache, const char *filename) {
496*00b67f09SDavid van Moolenbroek 	char *newname;
497*00b67f09SDavid van Moolenbroek 
498*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
499*00b67f09SDavid van Moolenbroek 	REQUIRE(filename != NULL);
500*00b67f09SDavid van Moolenbroek 
501*00b67f09SDavid van Moolenbroek 	newname = isc_mem_strdup(cache->mctx, filename);
502*00b67f09SDavid van Moolenbroek 	if (newname == NULL)
503*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
504*00b67f09SDavid van Moolenbroek 
505*00b67f09SDavid van Moolenbroek 	LOCK(&cache->filelock);
506*00b67f09SDavid van Moolenbroek 	if (cache->filename)
507*00b67f09SDavid van Moolenbroek 		isc_mem_free(cache->mctx, cache->filename);
508*00b67f09SDavid van Moolenbroek 	cache->filename = newname;
509*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->filelock);
510*00b67f09SDavid van Moolenbroek 
511*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
512*00b67f09SDavid van Moolenbroek }
513*00b67f09SDavid van Moolenbroek 
514*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_load(dns_cache_t * cache)515*00b67f09SDavid van Moolenbroek dns_cache_load(dns_cache_t *cache) {
516*00b67f09SDavid van Moolenbroek 	isc_result_t result;
517*00b67f09SDavid van Moolenbroek 
518*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
519*00b67f09SDavid van Moolenbroek 
520*00b67f09SDavid van Moolenbroek 	if (cache->filename == NULL)
521*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
522*00b67f09SDavid van Moolenbroek 
523*00b67f09SDavid van Moolenbroek 	LOCK(&cache->filelock);
524*00b67f09SDavid van Moolenbroek 	result = dns_db_load(cache->db, cache->filename);
525*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->filelock);
526*00b67f09SDavid van Moolenbroek 
527*00b67f09SDavid van Moolenbroek 	return (result);
528*00b67f09SDavid van Moolenbroek }
529*00b67f09SDavid van Moolenbroek 
530*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_dump(dns_cache_t * cache)531*00b67f09SDavid van Moolenbroek dns_cache_dump(dns_cache_t *cache) {
532*00b67f09SDavid van Moolenbroek 	isc_result_t result;
533*00b67f09SDavid van Moolenbroek 
534*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
535*00b67f09SDavid van Moolenbroek 
536*00b67f09SDavid van Moolenbroek 	if (cache->filename == NULL)
537*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
538*00b67f09SDavid van Moolenbroek 
539*00b67f09SDavid van Moolenbroek 	LOCK(&cache->filelock);
540*00b67f09SDavid van Moolenbroek 	result = dns_master_dump(cache->mctx, cache->db, NULL,
541*00b67f09SDavid van Moolenbroek 				 &dns_master_style_cache, cache->filename);
542*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->filelock);
543*00b67f09SDavid van Moolenbroek 	return (result);
544*00b67f09SDavid van Moolenbroek 
545*00b67f09SDavid van Moolenbroek }
546*00b67f09SDavid van Moolenbroek 
547*00b67f09SDavid van Moolenbroek void
dns_cache_setcleaninginterval(dns_cache_t * cache,unsigned int t)548*00b67f09SDavid van Moolenbroek dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
549*00b67f09SDavid van Moolenbroek 	isc_interval_t interval;
550*00b67f09SDavid van Moolenbroek 	isc_result_t result;
551*00b67f09SDavid van Moolenbroek 
552*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
553*00b67f09SDavid van Moolenbroek 
554*00b67f09SDavid van Moolenbroek 	/*
555*00b67f09SDavid van Moolenbroek 	 * It may be the case that the cache has already shut down.
556*00b67f09SDavid van Moolenbroek 	 * If so, it has no timer.
557*00b67f09SDavid van Moolenbroek 	 */
558*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.cleaning_timer == NULL)
559*00b67f09SDavid van Moolenbroek 		goto unlock;
560*00b67f09SDavid van Moolenbroek 
561*00b67f09SDavid van Moolenbroek 	cache->cleaner.cleaning_interval = t;
562*00b67f09SDavid van Moolenbroek 
563*00b67f09SDavid van Moolenbroek 	if (t == 0) {
564*00b67f09SDavid van Moolenbroek 		result = isc_timer_reset(cache->cleaner.cleaning_timer,
565*00b67f09SDavid van Moolenbroek 					 isc_timertype_inactive,
566*00b67f09SDavid van Moolenbroek 					 NULL, NULL, ISC_TRUE);
567*00b67f09SDavid van Moolenbroek 	} else {
568*00b67f09SDavid van Moolenbroek 		isc_interval_set(&interval, cache->cleaner.cleaning_interval,
569*00b67f09SDavid van Moolenbroek 				 0);
570*00b67f09SDavid van Moolenbroek 		result = isc_timer_reset(cache->cleaner.cleaning_timer,
571*00b67f09SDavid van Moolenbroek 					 isc_timertype_ticker,
572*00b67f09SDavid van Moolenbroek 					 NULL, &interval, ISC_FALSE);
573*00b67f09SDavid van Moolenbroek 	}
574*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
575*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
576*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
577*00b67f09SDavid van Moolenbroek 			      "could not set cache cleaning interval: %s",
578*00b67f09SDavid van Moolenbroek 			      isc_result_totext(result));
579*00b67f09SDavid van Moolenbroek 
580*00b67f09SDavid van Moolenbroek  unlock:
581*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
582*00b67f09SDavid van Moolenbroek }
583*00b67f09SDavid van Moolenbroek 
584*00b67f09SDavid van Moolenbroek unsigned int
dns_cache_getcleaninginterval(dns_cache_t * cache)585*00b67f09SDavid van Moolenbroek dns_cache_getcleaninginterval(dns_cache_t *cache) {
586*00b67f09SDavid van Moolenbroek 	unsigned int t;
587*00b67f09SDavid van Moolenbroek 
588*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
589*00b67f09SDavid van Moolenbroek 
590*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
591*00b67f09SDavid van Moolenbroek 	t = cache->cleaner.cleaning_interval;
592*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
593*00b67f09SDavid van Moolenbroek 
594*00b67f09SDavid van Moolenbroek 	return (t);
595*00b67f09SDavid van Moolenbroek }
596*00b67f09SDavid van Moolenbroek 
597*00b67f09SDavid van Moolenbroek const char *
dns_cache_getname(dns_cache_t * cache)598*00b67f09SDavid van Moolenbroek dns_cache_getname(dns_cache_t *cache) {
599*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
600*00b67f09SDavid van Moolenbroek 
601*00b67f09SDavid van Moolenbroek 	return (cache->name);
602*00b67f09SDavid van Moolenbroek }
603*00b67f09SDavid van Moolenbroek 
604*00b67f09SDavid van Moolenbroek /*
605*00b67f09SDavid van Moolenbroek  * Initialize the cache cleaner object at *cleaner.
606*00b67f09SDavid van Moolenbroek  * Space for the object must be allocated by the caller.
607*00b67f09SDavid van Moolenbroek  */
608*00b67f09SDavid van Moolenbroek 
609*00b67f09SDavid van Moolenbroek static isc_result_t
cache_cleaner_init(dns_cache_t * cache,isc_taskmgr_t * taskmgr,isc_timermgr_t * timermgr,cache_cleaner_t * cleaner)610*00b67f09SDavid van Moolenbroek cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
611*00b67f09SDavid van Moolenbroek 		   isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
612*00b67f09SDavid van Moolenbroek {
613*00b67f09SDavid van Moolenbroek 	isc_result_t result;
614*00b67f09SDavid van Moolenbroek 
615*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&cleaner->lock);
616*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
617*00b67f09SDavid van Moolenbroek 		goto fail;
618*00b67f09SDavid van Moolenbroek 
619*00b67f09SDavid van Moolenbroek 	cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
620*00b67f09SDavid van Moolenbroek 	cleaner->state = cleaner_s_idle;
621*00b67f09SDavid van Moolenbroek 	cleaner->cache = cache;
622*00b67f09SDavid van Moolenbroek 	cleaner->iterator = NULL;
623*00b67f09SDavid van Moolenbroek 	cleaner->overmem = ISC_FALSE;
624*00b67f09SDavid van Moolenbroek 	cleaner->replaceiterator = ISC_FALSE;
625*00b67f09SDavid van Moolenbroek 
626*00b67f09SDavid van Moolenbroek 	cleaner->task = NULL;
627*00b67f09SDavid van Moolenbroek 	cleaner->cleaning_timer = NULL;
628*00b67f09SDavid van Moolenbroek 	cleaner->resched_event = NULL;
629*00b67f09SDavid van Moolenbroek 	cleaner->overmem_event = NULL;
630*00b67f09SDavid van Moolenbroek 	cleaner->cleaning_interval = 0; /* Initially turned off. */
631*00b67f09SDavid van Moolenbroek 
632*00b67f09SDavid van Moolenbroek 	result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
633*00b67f09SDavid van Moolenbroek 				       &cleaner->iterator);
634*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
635*00b67f09SDavid van Moolenbroek 		goto cleanup;
636*00b67f09SDavid van Moolenbroek 
637*00b67f09SDavid van Moolenbroek 	if (taskmgr != NULL && timermgr != NULL) {
638*00b67f09SDavid van Moolenbroek 		result = isc_task_create(taskmgr, 1, &cleaner->task);
639*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
640*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
641*00b67f09SDavid van Moolenbroek 					 "isc_task_create() failed: %s",
642*00b67f09SDavid van Moolenbroek 					 dns_result_totext(result));
643*00b67f09SDavid van Moolenbroek 			result = ISC_R_UNEXPECTED;
644*00b67f09SDavid van Moolenbroek 			goto cleanup;
645*00b67f09SDavid van Moolenbroek 		}
646*00b67f09SDavid van Moolenbroek 		cleaner->cache->live_tasks++;
647*00b67f09SDavid van Moolenbroek 		isc_task_setname(cleaner->task, "cachecleaner", cleaner);
648*00b67f09SDavid van Moolenbroek 
649*00b67f09SDavid van Moolenbroek 		result = isc_task_onshutdown(cleaner->task,
650*00b67f09SDavid van Moolenbroek 					     cleaner_shutdown_action, cache);
651*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
652*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
653*00b67f09SDavid van Moolenbroek 					 "cache cleaner: "
654*00b67f09SDavid van Moolenbroek 					 "isc_task_onshutdown() failed: %s",
655*00b67f09SDavid van Moolenbroek 					 dns_result_totext(result));
656*00b67f09SDavid van Moolenbroek 			goto cleanup;
657*00b67f09SDavid van Moolenbroek 		}
658*00b67f09SDavid van Moolenbroek 
659*00b67f09SDavid van Moolenbroek 		result = isc_timer_create(timermgr, isc_timertype_inactive,
660*00b67f09SDavid van Moolenbroek 					   NULL, NULL, cleaner->task,
661*00b67f09SDavid van Moolenbroek 					   cleaning_timer_action, cleaner,
662*00b67f09SDavid van Moolenbroek 					   &cleaner->cleaning_timer);
663*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
664*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
665*00b67f09SDavid van Moolenbroek 					 "isc_timer_create() failed: %s",
666*00b67f09SDavid van Moolenbroek 					 dns_result_totext(result));
667*00b67f09SDavid van Moolenbroek 			result = ISC_R_UNEXPECTED;
668*00b67f09SDavid van Moolenbroek 			goto cleanup;
669*00b67f09SDavid van Moolenbroek 		}
670*00b67f09SDavid van Moolenbroek 
671*00b67f09SDavid van Moolenbroek 		cleaner->resched_event =
672*00b67f09SDavid van Moolenbroek 			isc_event_allocate(cache->mctx, cleaner,
673*00b67f09SDavid van Moolenbroek 					   DNS_EVENT_CACHECLEAN,
674*00b67f09SDavid van Moolenbroek 					   incremental_cleaning_action,
675*00b67f09SDavid van Moolenbroek 					   cleaner, sizeof(isc_event_t));
676*00b67f09SDavid van Moolenbroek 		if (cleaner->resched_event == NULL) {
677*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
678*00b67f09SDavid van Moolenbroek 			goto cleanup;
679*00b67f09SDavid van Moolenbroek 		}
680*00b67f09SDavid van Moolenbroek 
681*00b67f09SDavid van Moolenbroek 		cleaner->overmem_event =
682*00b67f09SDavid van Moolenbroek 			isc_event_allocate(cache->mctx, cleaner,
683*00b67f09SDavid van Moolenbroek 					   DNS_EVENT_CACHEOVERMEM,
684*00b67f09SDavid van Moolenbroek 					   overmem_cleaning_action,
685*00b67f09SDavid van Moolenbroek 					   cleaner, sizeof(isc_event_t));
686*00b67f09SDavid van Moolenbroek 		if (cleaner->overmem_event == NULL) {
687*00b67f09SDavid van Moolenbroek 			result = ISC_R_NOMEMORY;
688*00b67f09SDavid van Moolenbroek 			goto cleanup;
689*00b67f09SDavid van Moolenbroek 		}
690*00b67f09SDavid van Moolenbroek 	}
691*00b67f09SDavid van Moolenbroek 
692*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
693*00b67f09SDavid van Moolenbroek 
694*00b67f09SDavid van Moolenbroek  cleanup:
695*00b67f09SDavid van Moolenbroek 	if (cleaner->overmem_event != NULL)
696*00b67f09SDavid van Moolenbroek 		isc_event_free(&cleaner->overmem_event);
697*00b67f09SDavid van Moolenbroek 	if (cleaner->resched_event != NULL)
698*00b67f09SDavid van Moolenbroek 		isc_event_free(&cleaner->resched_event);
699*00b67f09SDavid van Moolenbroek 	if (cleaner->cleaning_timer != NULL)
700*00b67f09SDavid van Moolenbroek 		isc_timer_detach(&cleaner->cleaning_timer);
701*00b67f09SDavid van Moolenbroek 	if (cleaner->task != NULL)
702*00b67f09SDavid van Moolenbroek 		isc_task_detach(&cleaner->task);
703*00b67f09SDavid van Moolenbroek 	if (cleaner->iterator != NULL)
704*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&cleaner->iterator);
705*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&cleaner->lock);
706*00b67f09SDavid van Moolenbroek  fail:
707*00b67f09SDavid van Moolenbroek 	return (result);
708*00b67f09SDavid van Moolenbroek }
709*00b67f09SDavid van Moolenbroek 
710*00b67f09SDavid van Moolenbroek static void
begin_cleaning(cache_cleaner_t * cleaner)711*00b67f09SDavid van Moolenbroek begin_cleaning(cache_cleaner_t *cleaner) {
712*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
713*00b67f09SDavid van Moolenbroek 
714*00b67f09SDavid van Moolenbroek 	REQUIRE(CLEANER_IDLE(cleaner));
715*00b67f09SDavid van Moolenbroek 
716*00b67f09SDavid van Moolenbroek 	/*
717*00b67f09SDavid van Moolenbroek 	 * Create an iterator, if it does not already exist, and
718*00b67f09SDavid van Moolenbroek 	 * position it at the beginning of the cache.
719*00b67f09SDavid van Moolenbroek 	 */
720*00b67f09SDavid van Moolenbroek 	if (cleaner->iterator == NULL)
721*00b67f09SDavid van Moolenbroek 		result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
722*00b67f09SDavid van Moolenbroek 					       &cleaner->iterator);
723*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
724*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
725*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
726*00b67f09SDavid van Moolenbroek 			      "cache cleaner could not create "
727*00b67f09SDavid van Moolenbroek 			      "iterator: %s", isc_result_totext(result));
728*00b67f09SDavid van Moolenbroek 	else {
729*00b67f09SDavid van Moolenbroek 		dns_dbiterator_setcleanmode(cleaner->iterator, ISC_TRUE);
730*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_first(cleaner->iterator);
731*00b67f09SDavid van Moolenbroek 	}
732*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
733*00b67f09SDavid van Moolenbroek 		/*
734*00b67f09SDavid van Moolenbroek 		 * If the result is ISC_R_NOMORE, the database is empty,
735*00b67f09SDavid van Moolenbroek 		 * so there is nothing to be cleaned.
736*00b67f09SDavid van Moolenbroek 		 */
737*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_NOMORE && cleaner->iterator != NULL) {
738*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
739*00b67f09SDavid van Moolenbroek 					 "cache cleaner: "
740*00b67f09SDavid van Moolenbroek 					 "dns_dbiterator_first() failed: %s",
741*00b67f09SDavid van Moolenbroek 					 dns_result_totext(result));
742*00b67f09SDavid van Moolenbroek 			dns_dbiterator_destroy(&cleaner->iterator);
743*00b67f09SDavid van Moolenbroek 		} else if (cleaner->iterator != NULL) {
744*00b67f09SDavid van Moolenbroek 			result = dns_dbiterator_pause(cleaner->iterator);
745*00b67f09SDavid van Moolenbroek 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
746*00b67f09SDavid van Moolenbroek 		}
747*00b67f09SDavid van Moolenbroek 	} else {
748*00b67f09SDavid van Moolenbroek 		/*
749*00b67f09SDavid van Moolenbroek 		 * Pause the iterator to free its lock.
750*00b67f09SDavid van Moolenbroek 		 */
751*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_pause(cleaner->iterator);
752*00b67f09SDavid van Moolenbroek 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
753*00b67f09SDavid van Moolenbroek 
754*00b67f09SDavid van Moolenbroek 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
755*00b67f09SDavid van Moolenbroek 			      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
756*00b67f09SDavid van Moolenbroek 			      "begin cache cleaning, mem inuse %lu",
757*00b67f09SDavid van Moolenbroek 			    (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
758*00b67f09SDavid van Moolenbroek 		cleaner->state = cleaner_s_busy;
759*00b67f09SDavid van Moolenbroek 		isc_task_send(cleaner->task, &cleaner->resched_event);
760*00b67f09SDavid van Moolenbroek 	}
761*00b67f09SDavid van Moolenbroek 
762*00b67f09SDavid van Moolenbroek 	return;
763*00b67f09SDavid van Moolenbroek }
764*00b67f09SDavid van Moolenbroek 
765*00b67f09SDavid van Moolenbroek static void
end_cleaning(cache_cleaner_t * cleaner,isc_event_t * event)766*00b67f09SDavid van Moolenbroek end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
767*00b67f09SDavid van Moolenbroek 	isc_result_t result;
768*00b67f09SDavid van Moolenbroek 
769*00b67f09SDavid van Moolenbroek 	REQUIRE(CLEANER_BUSY(cleaner));
770*00b67f09SDavid van Moolenbroek 	REQUIRE(event != NULL);
771*00b67f09SDavid van Moolenbroek 
772*00b67f09SDavid van Moolenbroek 	result = dns_dbiterator_pause(cleaner->iterator);
773*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
774*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&cleaner->iterator);
775*00b67f09SDavid van Moolenbroek 
776*00b67f09SDavid van Moolenbroek 	dns_cache_setcleaninginterval(cleaner->cache,
777*00b67f09SDavid van Moolenbroek 				      cleaner->cleaning_interval);
778*00b67f09SDavid van Moolenbroek 
779*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
780*00b67f09SDavid van Moolenbroek 		      ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
781*00b67f09SDavid van Moolenbroek 		      (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
782*00b67f09SDavid van Moolenbroek 
783*00b67f09SDavid van Moolenbroek 	cleaner->state = cleaner_s_idle;
784*00b67f09SDavid van Moolenbroek 	cleaner->resched_event = event;
785*00b67f09SDavid van Moolenbroek }
786*00b67f09SDavid van Moolenbroek 
787*00b67f09SDavid van Moolenbroek /*
788*00b67f09SDavid van Moolenbroek  * This is run once for every cache-cleaning-interval as defined in named.conf.
789*00b67f09SDavid van Moolenbroek  */
790*00b67f09SDavid van Moolenbroek static void
cleaning_timer_action(isc_task_t * task,isc_event_t * event)791*00b67f09SDavid van Moolenbroek cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
792*00b67f09SDavid van Moolenbroek 	cache_cleaner_t *cleaner = event->ev_arg;
793*00b67f09SDavid van Moolenbroek 
794*00b67f09SDavid van Moolenbroek 	UNUSED(task);
795*00b67f09SDavid van Moolenbroek 
796*00b67f09SDavid van Moolenbroek 	INSIST(task == cleaner->task);
797*00b67f09SDavid van Moolenbroek 	INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
798*00b67f09SDavid van Moolenbroek 
799*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
800*00b67f09SDavid van Moolenbroek 		      ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
801*00b67f09SDavid van Moolenbroek 		      "cleaner state = %d", cleaner->state);
802*00b67f09SDavid van Moolenbroek 
803*00b67f09SDavid van Moolenbroek 	if (cleaner->state == cleaner_s_idle)
804*00b67f09SDavid van Moolenbroek 		begin_cleaning(cleaner);
805*00b67f09SDavid van Moolenbroek 
806*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
807*00b67f09SDavid van Moolenbroek }
808*00b67f09SDavid van Moolenbroek 
809*00b67f09SDavid van Moolenbroek /*
810*00b67f09SDavid van Moolenbroek  * This is called when the cache either surpasses its upper limit
811*00b67f09SDavid van Moolenbroek  * or shrinks beyond its lower limit.
812*00b67f09SDavid van Moolenbroek  */
813*00b67f09SDavid van Moolenbroek static void
overmem_cleaning_action(isc_task_t * task,isc_event_t * event)814*00b67f09SDavid van Moolenbroek overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
815*00b67f09SDavid van Moolenbroek 	cache_cleaner_t *cleaner = event->ev_arg;
816*00b67f09SDavid van Moolenbroek 	isc_boolean_t want_cleaning = ISC_FALSE;
817*00b67f09SDavid van Moolenbroek 
818*00b67f09SDavid van Moolenbroek 	UNUSED(task);
819*00b67f09SDavid van Moolenbroek 
820*00b67f09SDavid van Moolenbroek 	INSIST(task == cleaner->task);
821*00b67f09SDavid van Moolenbroek 	INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
822*00b67f09SDavid van Moolenbroek 	INSIST(cleaner->overmem_event == NULL);
823*00b67f09SDavid van Moolenbroek 
824*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
825*00b67f09SDavid van Moolenbroek 		      ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
826*00b67f09SDavid van Moolenbroek 		      "overmem = %d, state = %d", cleaner->overmem,
827*00b67f09SDavid van Moolenbroek 		      cleaner->state);
828*00b67f09SDavid van Moolenbroek 
829*00b67f09SDavid van Moolenbroek 	LOCK(&cleaner->lock);
830*00b67f09SDavid van Moolenbroek 
831*00b67f09SDavid van Moolenbroek 	if (cleaner->overmem) {
832*00b67f09SDavid van Moolenbroek 		if (cleaner->state == cleaner_s_idle)
833*00b67f09SDavid van Moolenbroek 			want_cleaning = ISC_TRUE;
834*00b67f09SDavid van Moolenbroek 	} else {
835*00b67f09SDavid van Moolenbroek 		if (cleaner->state == cleaner_s_busy)
836*00b67f09SDavid van Moolenbroek 			/*
837*00b67f09SDavid van Moolenbroek 			 * end_cleaning() can't be called here because
838*00b67f09SDavid van Moolenbroek 			 * then both cleaner->overmem_event and
839*00b67f09SDavid van Moolenbroek 			 * cleaner->resched_event will point to this
840*00b67f09SDavid van Moolenbroek 			 * event.  Set the state to done, and then
841*00b67f09SDavid van Moolenbroek 			 * when the incremental_cleaning_action() event
842*00b67f09SDavid van Moolenbroek 			 * is posted, it will handle the end_cleaning.
843*00b67f09SDavid van Moolenbroek 			 */
844*00b67f09SDavid van Moolenbroek 			cleaner->state = cleaner_s_done;
845*00b67f09SDavid van Moolenbroek 	}
846*00b67f09SDavid van Moolenbroek 
847*00b67f09SDavid van Moolenbroek 	cleaner->overmem_event = event;
848*00b67f09SDavid van Moolenbroek 
849*00b67f09SDavid van Moolenbroek 	UNLOCK(&cleaner->lock);
850*00b67f09SDavid van Moolenbroek 
851*00b67f09SDavid van Moolenbroek 	if (want_cleaning)
852*00b67f09SDavid van Moolenbroek 		begin_cleaning(cleaner);
853*00b67f09SDavid van Moolenbroek }
854*00b67f09SDavid van Moolenbroek 
855*00b67f09SDavid van Moolenbroek /*
856*00b67f09SDavid van Moolenbroek  * Do incremental cleaning.
857*00b67f09SDavid van Moolenbroek  */
858*00b67f09SDavid van Moolenbroek static void
incremental_cleaning_action(isc_task_t * task,isc_event_t * event)859*00b67f09SDavid van Moolenbroek incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
860*00b67f09SDavid van Moolenbroek 	cache_cleaner_t *cleaner = event->ev_arg;
861*00b67f09SDavid van Moolenbroek 	isc_result_t result;
862*00b67f09SDavid van Moolenbroek 	unsigned int n_names;
863*00b67f09SDavid van Moolenbroek 	isc_time_t start;
864*00b67f09SDavid van Moolenbroek 
865*00b67f09SDavid van Moolenbroek 	UNUSED(task);
866*00b67f09SDavid van Moolenbroek 
867*00b67f09SDavid van Moolenbroek 	INSIST(task == cleaner->task);
868*00b67f09SDavid van Moolenbroek 	INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
869*00b67f09SDavid van Moolenbroek 
870*00b67f09SDavid van Moolenbroek 	if (cleaner->state == cleaner_s_done) {
871*00b67f09SDavid van Moolenbroek 		cleaner->state = cleaner_s_busy;
872*00b67f09SDavid van Moolenbroek 		end_cleaning(cleaner, event);
873*00b67f09SDavid van Moolenbroek 		LOCK(&cleaner->cache->lock);
874*00b67f09SDavid van Moolenbroek 		LOCK(&cleaner->lock);
875*00b67f09SDavid van Moolenbroek 		if (cleaner->replaceiterator) {
876*00b67f09SDavid van Moolenbroek 			dns_dbiterator_destroy(&cleaner->iterator);
877*00b67f09SDavid van Moolenbroek 			(void) dns_db_createiterator(cleaner->cache->db,
878*00b67f09SDavid van Moolenbroek 						     ISC_FALSE,
879*00b67f09SDavid van Moolenbroek 						     &cleaner->iterator);
880*00b67f09SDavid van Moolenbroek 			cleaner->replaceiterator = ISC_FALSE;
881*00b67f09SDavid van Moolenbroek 		}
882*00b67f09SDavid van Moolenbroek 		UNLOCK(&cleaner->lock);
883*00b67f09SDavid van Moolenbroek 		UNLOCK(&cleaner->cache->lock);
884*00b67f09SDavid van Moolenbroek 		return;
885*00b67f09SDavid van Moolenbroek 	}
886*00b67f09SDavid van Moolenbroek 
887*00b67f09SDavid van Moolenbroek 	INSIST(CLEANER_BUSY(cleaner));
888*00b67f09SDavid van Moolenbroek 
889*00b67f09SDavid van Moolenbroek 	n_names = cleaner->increment;
890*00b67f09SDavid van Moolenbroek 
891*00b67f09SDavid van Moolenbroek 	REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
892*00b67f09SDavid van Moolenbroek 
893*00b67f09SDavid van Moolenbroek 	isc_time_now(&start);
894*00b67f09SDavid van Moolenbroek 	while (n_names-- > 0) {
895*00b67f09SDavid van Moolenbroek 		dns_dbnode_t *node = NULL;
896*00b67f09SDavid van Moolenbroek 
897*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_current(cleaner->iterator, &node,
898*00b67f09SDavid van Moolenbroek 						NULL);
899*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
900*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
901*00b67f09SDavid van Moolenbroek 				 "cache cleaner: dns_dbiterator_current() "
902*00b67f09SDavid van Moolenbroek 				 "failed: %s", dns_result_totext(result));
903*00b67f09SDavid van Moolenbroek 
904*00b67f09SDavid van Moolenbroek 			end_cleaning(cleaner, event);
905*00b67f09SDavid van Moolenbroek 			return;
906*00b67f09SDavid van Moolenbroek 		}
907*00b67f09SDavid van Moolenbroek 
908*00b67f09SDavid van Moolenbroek 		/*
909*00b67f09SDavid van Moolenbroek 		 * The node was not needed, but was required by
910*00b67f09SDavid van Moolenbroek 		 * dns_dbiterator_current().  Give up its reference.
911*00b67f09SDavid van Moolenbroek 		 */
912*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(cleaner->cache->db, &node);
913*00b67f09SDavid van Moolenbroek 
914*00b67f09SDavid van Moolenbroek 		/*
915*00b67f09SDavid van Moolenbroek 		 * Step to the next node.
916*00b67f09SDavid van Moolenbroek 		 */
917*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_next(cleaner->iterator);
918*00b67f09SDavid van Moolenbroek 
919*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
920*00b67f09SDavid van Moolenbroek 			/*
921*00b67f09SDavid van Moolenbroek 			 * Either the end was reached (ISC_R_NOMORE) or
922*00b67f09SDavid van Moolenbroek 			 * some error was signaled.  If the cache is still
923*00b67f09SDavid van Moolenbroek 			 * overmem and no error was encountered,
924*00b67f09SDavid van Moolenbroek 			 * keep trying to clean it, otherwise stop cleaning.
925*00b67f09SDavid van Moolenbroek 			 */
926*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_NOMORE)
927*00b67f09SDavid van Moolenbroek 				UNEXPECTED_ERROR(__FILE__, __LINE__,
928*00b67f09SDavid van Moolenbroek 						 "cache cleaner: "
929*00b67f09SDavid van Moolenbroek 						 "dns_dbiterator_next() "
930*00b67f09SDavid van Moolenbroek 						 "failed: %s",
931*00b67f09SDavid van Moolenbroek 						 dns_result_totext(result));
932*00b67f09SDavid van Moolenbroek 			else if (cleaner->overmem) {
933*00b67f09SDavid van Moolenbroek 				result = dns_dbiterator_first(cleaner->
934*00b67f09SDavid van Moolenbroek 							      iterator);
935*00b67f09SDavid van Moolenbroek 				if (result == ISC_R_SUCCESS) {
936*00b67f09SDavid van Moolenbroek 					isc_log_write(dns_lctx,
937*00b67f09SDavid van Moolenbroek 						      DNS_LOGCATEGORY_DATABASE,
938*00b67f09SDavid van Moolenbroek 						      DNS_LOGMODULE_CACHE,
939*00b67f09SDavid van Moolenbroek 						      ISC_LOG_DEBUG(1),
940*00b67f09SDavid van Moolenbroek 						      "cache cleaner: "
941*00b67f09SDavid van Moolenbroek 						      "still overmem, "
942*00b67f09SDavid van Moolenbroek 						      "reset and try again");
943*00b67f09SDavid van Moolenbroek 					continue;
944*00b67f09SDavid van Moolenbroek 				}
945*00b67f09SDavid van Moolenbroek 			}
946*00b67f09SDavid van Moolenbroek 
947*00b67f09SDavid van Moolenbroek 			end_cleaning(cleaner, event);
948*00b67f09SDavid van Moolenbroek 			return;
949*00b67f09SDavid van Moolenbroek 		}
950*00b67f09SDavid van Moolenbroek 	}
951*00b67f09SDavid van Moolenbroek 
952*00b67f09SDavid van Moolenbroek 	/*
953*00b67f09SDavid van Moolenbroek 	 * We have successfully performed a cleaning increment but have
954*00b67f09SDavid van Moolenbroek 	 * not gone through the entire cache.  Free the iterator locks
955*00b67f09SDavid van Moolenbroek 	 * and reschedule another batch.  If it fails, just try to continue
956*00b67f09SDavid van Moolenbroek 	 * anyway.
957*00b67f09SDavid van Moolenbroek 	 */
958*00b67f09SDavid van Moolenbroek 	result = dns_dbiterator_pause(cleaner->iterator);
959*00b67f09SDavid van Moolenbroek 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
960*00b67f09SDavid van Moolenbroek 
961*00b67f09SDavid van Moolenbroek 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
962*00b67f09SDavid van Moolenbroek 		      ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
963*00b67f09SDavid van Moolenbroek 		      "mem inuse %lu, sleeping", cleaner->increment,
964*00b67f09SDavid van Moolenbroek 		      (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
965*00b67f09SDavid van Moolenbroek 
966*00b67f09SDavid van Moolenbroek 	isc_task_send(task, &event);
967*00b67f09SDavid van Moolenbroek 	INSIST(CLEANER_BUSY(cleaner));
968*00b67f09SDavid van Moolenbroek 	return;
969*00b67f09SDavid van Moolenbroek }
970*00b67f09SDavid van Moolenbroek 
971*00b67f09SDavid van Moolenbroek /*
972*00b67f09SDavid van Moolenbroek  * Do immediate cleaning.
973*00b67f09SDavid van Moolenbroek  */
974*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_clean(dns_cache_t * cache,isc_stdtime_t now)975*00b67f09SDavid van Moolenbroek dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) {
976*00b67f09SDavid van Moolenbroek 	isc_result_t result;
977*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *iterator = NULL;
978*00b67f09SDavid van Moolenbroek 
979*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
980*00b67f09SDavid van Moolenbroek 
981*00b67f09SDavid van Moolenbroek 	result = dns_db_createiterator(cache->db, 0, &iterator);
982*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
983*00b67f09SDavid van Moolenbroek 		return result;
984*00b67f09SDavid van Moolenbroek 
985*00b67f09SDavid van Moolenbroek 	result = dns_dbiterator_first(iterator);
986*00b67f09SDavid van Moolenbroek 
987*00b67f09SDavid van Moolenbroek 	while (result == ISC_R_SUCCESS) {
988*00b67f09SDavid van Moolenbroek 		dns_dbnode_t *node = NULL;
989*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_current(iterator, &node,
990*00b67f09SDavid van Moolenbroek 						(dns_name_t *)NULL);
991*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
992*00b67f09SDavid van Moolenbroek 			break;
993*00b67f09SDavid van Moolenbroek 
994*00b67f09SDavid van Moolenbroek 		/*
995*00b67f09SDavid van Moolenbroek 		 * Check TTLs, mark expired rdatasets stale.
996*00b67f09SDavid van Moolenbroek 		 */
997*00b67f09SDavid van Moolenbroek 		result = dns_db_expirenode(cache->db, node, now);
998*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
999*00b67f09SDavid van Moolenbroek 			UNEXPECTED_ERROR(__FILE__, __LINE__,
1000*00b67f09SDavid van Moolenbroek 					 "cache cleaner: dns_db_expirenode() "
1001*00b67f09SDavid van Moolenbroek 					 "failed: %s",
1002*00b67f09SDavid van Moolenbroek 					 dns_result_totext(result));
1003*00b67f09SDavid van Moolenbroek 			/*
1004*00b67f09SDavid van Moolenbroek 			 * Continue anyway.
1005*00b67f09SDavid van Moolenbroek 			 */
1006*00b67f09SDavid van Moolenbroek 		}
1007*00b67f09SDavid van Moolenbroek 
1008*00b67f09SDavid van Moolenbroek 		/*
1009*00b67f09SDavid van Moolenbroek 		 * This is where the actual freeing takes place.
1010*00b67f09SDavid van Moolenbroek 		 */
1011*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(cache->db, &node);
1012*00b67f09SDavid van Moolenbroek 
1013*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_next(iterator);
1014*00b67f09SDavid van Moolenbroek 	}
1015*00b67f09SDavid van Moolenbroek 
1016*00b67f09SDavid van Moolenbroek 	dns_dbiterator_destroy(&iterator);
1017*00b67f09SDavid van Moolenbroek 
1018*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1019*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1020*00b67f09SDavid van Moolenbroek 
1021*00b67f09SDavid van Moolenbroek 	return (result);
1022*00b67f09SDavid van Moolenbroek }
1023*00b67f09SDavid van Moolenbroek 
1024*00b67f09SDavid van Moolenbroek static void
water(void * arg,int mark)1025*00b67f09SDavid van Moolenbroek water(void *arg, int mark) {
1026*00b67f09SDavid van Moolenbroek 	dns_cache_t *cache = arg;
1027*00b67f09SDavid van Moolenbroek 	isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
1028*00b67f09SDavid van Moolenbroek 
1029*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1030*00b67f09SDavid van Moolenbroek 
1031*00b67f09SDavid van Moolenbroek 	LOCK(&cache->cleaner.lock);
1032*00b67f09SDavid van Moolenbroek 
1033*00b67f09SDavid van Moolenbroek 	if (overmem != cache->cleaner.overmem) {
1034*00b67f09SDavid van Moolenbroek 		dns_db_overmem(cache->db, overmem);
1035*00b67f09SDavid van Moolenbroek 		cache->cleaner.overmem = overmem;
1036*00b67f09SDavid van Moolenbroek 		isc_mem_waterack(cache->mctx, mark);
1037*00b67f09SDavid van Moolenbroek 	}
1038*00b67f09SDavid van Moolenbroek 
1039*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.overmem_event != NULL)
1040*00b67f09SDavid van Moolenbroek 		isc_task_send(cache->cleaner.task,
1041*00b67f09SDavid van Moolenbroek 			      &cache->cleaner.overmem_event);
1042*00b67f09SDavid van Moolenbroek 
1043*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->cleaner.lock);
1044*00b67f09SDavid van Moolenbroek }
1045*00b67f09SDavid van Moolenbroek 
1046*00b67f09SDavid van Moolenbroek void
dns_cache_setcachesize(dns_cache_t * cache,size_t size)1047*00b67f09SDavid van Moolenbroek dns_cache_setcachesize(dns_cache_t *cache, size_t size) {
1048*00b67f09SDavid van Moolenbroek 	size_t hiwater, lowater;
1049*00b67f09SDavid van Moolenbroek 
1050*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1051*00b67f09SDavid van Moolenbroek 
1052*00b67f09SDavid van Moolenbroek 	/*
1053*00b67f09SDavid van Moolenbroek 	 * Impose a minimum cache size; pathological things happen if there
1054*00b67f09SDavid van Moolenbroek 	 * is too little room.
1055*00b67f09SDavid van Moolenbroek 	 */
1056*00b67f09SDavid van Moolenbroek 	if (size != 0U && size < DNS_CACHE_MINSIZE)
1057*00b67f09SDavid van Moolenbroek 		size = DNS_CACHE_MINSIZE;
1058*00b67f09SDavid van Moolenbroek 
1059*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
1060*00b67f09SDavid van Moolenbroek 	cache->size = size;
1061*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
1062*00b67f09SDavid van Moolenbroek 
1063*00b67f09SDavid van Moolenbroek 	hiwater = size - (size >> 3);	/* Approximately 7/8ths. */
1064*00b67f09SDavid van Moolenbroek 	lowater = size - (size >> 2);	/* Approximately 3/4ths. */
1065*00b67f09SDavid van Moolenbroek 
1066*00b67f09SDavid van Moolenbroek 	/*
1067*00b67f09SDavid van Moolenbroek 	 * If the cache was overmem and cleaning, but now with the new limits
1068*00b67f09SDavid van Moolenbroek 	 * it is no longer in an overmem condition, then the next
1069*00b67f09SDavid van Moolenbroek 	 * isc_mem_put for cache memory will do the right thing and trigger
1070*00b67f09SDavid van Moolenbroek 	 * water().
1071*00b67f09SDavid van Moolenbroek 	 */
1072*00b67f09SDavid van Moolenbroek 
1073*00b67f09SDavid van Moolenbroek 	if (size == 0U || hiwater == 0U || lowater == 0U)
1074*00b67f09SDavid van Moolenbroek 		/*
1075*00b67f09SDavid van Moolenbroek 		 * Disable cache memory limiting.
1076*00b67f09SDavid van Moolenbroek 		 */
1077*00b67f09SDavid van Moolenbroek 		isc_mem_setwater(cache->mctx, water, cache, 0, 0);
1078*00b67f09SDavid van Moolenbroek 	else
1079*00b67f09SDavid van Moolenbroek 		/*
1080*00b67f09SDavid van Moolenbroek 		 * Establish new cache memory limits (either for the first
1081*00b67f09SDavid van Moolenbroek 		 * time, or replacing other limits).
1082*00b67f09SDavid van Moolenbroek 		 */
1083*00b67f09SDavid van Moolenbroek 		isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
1084*00b67f09SDavid van Moolenbroek }
1085*00b67f09SDavid van Moolenbroek 
1086*00b67f09SDavid van Moolenbroek size_t
dns_cache_getcachesize(dns_cache_t * cache)1087*00b67f09SDavid van Moolenbroek dns_cache_getcachesize(dns_cache_t *cache) {
1088*00b67f09SDavid van Moolenbroek 	size_t size;
1089*00b67f09SDavid van Moolenbroek 
1090*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1091*00b67f09SDavid van Moolenbroek 
1092*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
1093*00b67f09SDavid van Moolenbroek 	size = cache->size;
1094*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
1095*00b67f09SDavid van Moolenbroek 
1096*00b67f09SDavid van Moolenbroek 	return (size);
1097*00b67f09SDavid van Moolenbroek }
1098*00b67f09SDavid van Moolenbroek 
1099*00b67f09SDavid van Moolenbroek /*
1100*00b67f09SDavid van Moolenbroek  * The cleaner task is shutting down; do the necessary cleanup.
1101*00b67f09SDavid van Moolenbroek  */
1102*00b67f09SDavid van Moolenbroek static void
cleaner_shutdown_action(isc_task_t * task,isc_event_t * event)1103*00b67f09SDavid van Moolenbroek cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
1104*00b67f09SDavid van Moolenbroek 	dns_cache_t *cache = event->ev_arg;
1105*00b67f09SDavid van Moolenbroek 	isc_boolean_t should_free = ISC_FALSE;
1106*00b67f09SDavid van Moolenbroek 
1107*00b67f09SDavid van Moolenbroek 	UNUSED(task);
1108*00b67f09SDavid van Moolenbroek 
1109*00b67f09SDavid van Moolenbroek 	INSIST(task == cache->cleaner.task);
1110*00b67f09SDavid van Moolenbroek 	INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
1111*00b67f09SDavid van Moolenbroek 
1112*00b67f09SDavid van Moolenbroek 	if (CLEANER_BUSY(&cache->cleaner))
1113*00b67f09SDavid van Moolenbroek 		end_cleaning(&cache->cleaner, event);
1114*00b67f09SDavid van Moolenbroek 	else
1115*00b67f09SDavid van Moolenbroek 		isc_event_free(&event);
1116*00b67f09SDavid van Moolenbroek 
1117*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
1118*00b67f09SDavid van Moolenbroek 
1119*00b67f09SDavid van Moolenbroek 	cache->live_tasks--;
1120*00b67f09SDavid van Moolenbroek 	INSIST(cache->live_tasks == 0);
1121*00b67f09SDavid van Moolenbroek 
1122*00b67f09SDavid van Moolenbroek 	if (cache->references == 0)
1123*00b67f09SDavid van Moolenbroek 		should_free = ISC_TRUE;
1124*00b67f09SDavid van Moolenbroek 
1125*00b67f09SDavid van Moolenbroek 	/*
1126*00b67f09SDavid van Moolenbroek 	 * By detaching the timer in the context of its task,
1127*00b67f09SDavid van Moolenbroek 	 * we are guaranteed that there will be no further timer
1128*00b67f09SDavid van Moolenbroek 	 * events.
1129*00b67f09SDavid van Moolenbroek 	 */
1130*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.cleaning_timer != NULL)
1131*00b67f09SDavid van Moolenbroek 		isc_timer_detach(&cache->cleaner.cleaning_timer);
1132*00b67f09SDavid van Moolenbroek 
1133*00b67f09SDavid van Moolenbroek 	/* Make sure we don't reschedule anymore. */
1134*00b67f09SDavid van Moolenbroek 	(void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
1135*00b67f09SDavid van Moolenbroek 
1136*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
1137*00b67f09SDavid van Moolenbroek 
1138*00b67f09SDavid van Moolenbroek 	if (should_free)
1139*00b67f09SDavid van Moolenbroek 		cache_free(cache);
1140*00b67f09SDavid van Moolenbroek }
1141*00b67f09SDavid van Moolenbroek 
1142*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_flush(dns_cache_t * cache)1143*00b67f09SDavid van Moolenbroek dns_cache_flush(dns_cache_t *cache) {
1144*00b67f09SDavid van Moolenbroek 	dns_db_t *db = NULL;
1145*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1146*00b67f09SDavid van Moolenbroek 
1147*00b67f09SDavid van Moolenbroek 	result = cache_create_db(cache, &db);
1148*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1149*00b67f09SDavid van Moolenbroek 		return (result);
1150*00b67f09SDavid van Moolenbroek 
1151*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
1152*00b67f09SDavid van Moolenbroek 	LOCK(&cache->cleaner.lock);
1153*00b67f09SDavid van Moolenbroek 	if (cache->cleaner.state == cleaner_s_idle) {
1154*00b67f09SDavid van Moolenbroek 		if (cache->cleaner.iterator != NULL)
1155*00b67f09SDavid van Moolenbroek 			dns_dbiterator_destroy(&cache->cleaner.iterator);
1156*00b67f09SDavid van Moolenbroek 		(void) dns_db_createiterator(db, ISC_FALSE,
1157*00b67f09SDavid van Moolenbroek 					     &cache->cleaner.iterator);
1158*00b67f09SDavid van Moolenbroek 	} else {
1159*00b67f09SDavid van Moolenbroek 		if (cache->cleaner.state == cleaner_s_busy)
1160*00b67f09SDavid van Moolenbroek 			cache->cleaner.state = cleaner_s_done;
1161*00b67f09SDavid van Moolenbroek 		cache->cleaner.replaceiterator = ISC_TRUE;
1162*00b67f09SDavid van Moolenbroek 	}
1163*00b67f09SDavid van Moolenbroek 	dns_db_detach(&cache->db);
1164*00b67f09SDavid van Moolenbroek 	cache->db = db;
1165*00b67f09SDavid van Moolenbroek 	dns_db_setcachestats(cache->db, cache->stats);
1166*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->cleaner.lock);
1167*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
1168*00b67f09SDavid van Moolenbroek 
1169*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
1170*00b67f09SDavid van Moolenbroek }
1171*00b67f09SDavid van Moolenbroek 
1172*00b67f09SDavid van Moolenbroek static isc_result_t
clearnode(dns_db_t * db,dns_dbnode_t * node)1173*00b67f09SDavid van Moolenbroek clearnode(dns_db_t *db, dns_dbnode_t *node) {
1174*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1175*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_t *iter = NULL;
1176*00b67f09SDavid van Moolenbroek 
1177*00b67f09SDavid van Moolenbroek 	result = dns_db_allrdatasets(db, node, NULL, (isc_stdtime_t)0, &iter);
1178*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1179*00b67f09SDavid van Moolenbroek 		return (result);
1180*00b67f09SDavid van Moolenbroek 
1181*00b67f09SDavid van Moolenbroek 	for (result = dns_rdatasetiter_first(iter);
1182*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
1183*00b67f09SDavid van Moolenbroek 	     result = dns_rdatasetiter_next(iter))
1184*00b67f09SDavid van Moolenbroek 	{
1185*00b67f09SDavid van Moolenbroek 		dns_rdataset_t rdataset;
1186*00b67f09SDavid van Moolenbroek 		dns_rdataset_init(&rdataset);
1187*00b67f09SDavid van Moolenbroek 
1188*00b67f09SDavid van Moolenbroek 		dns_rdatasetiter_current(iter, &rdataset);
1189*00b67f09SDavid van Moolenbroek 		result = dns_db_deleterdataset(db, node, NULL,
1190*00b67f09SDavid van Moolenbroek 					       rdataset.type, rdataset.covers);
1191*00b67f09SDavid van Moolenbroek 		dns_rdataset_disassociate(&rdataset);
1192*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
1193*00b67f09SDavid van Moolenbroek 			break;
1194*00b67f09SDavid van Moolenbroek 	}
1195*00b67f09SDavid van Moolenbroek 
1196*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE)
1197*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1198*00b67f09SDavid van Moolenbroek 
1199*00b67f09SDavid van Moolenbroek 	dns_rdatasetiter_destroy(&iter);
1200*00b67f09SDavid van Moolenbroek 	return (result);
1201*00b67f09SDavid van Moolenbroek }
1202*00b67f09SDavid van Moolenbroek 
1203*00b67f09SDavid van Moolenbroek static isc_result_t
cleartree(dns_db_t * db,dns_name_t * name)1204*00b67f09SDavid van Moolenbroek cleartree(dns_db_t *db, dns_name_t *name) {
1205*00b67f09SDavid van Moolenbroek 	isc_result_t result, answer = ISC_R_SUCCESS;
1206*00b67f09SDavid van Moolenbroek 	dns_dbiterator_t *iter = NULL;
1207*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1208*00b67f09SDavid van Moolenbroek 	dns_fixedname_t fnodename;
1209*00b67f09SDavid van Moolenbroek 	dns_name_t *nodename;
1210*00b67f09SDavid van Moolenbroek 
1211*00b67f09SDavid van Moolenbroek 	dns_fixedname_init(&fnodename);
1212*00b67f09SDavid van Moolenbroek 	nodename = dns_fixedname_name(&fnodename);
1213*00b67f09SDavid van Moolenbroek 
1214*00b67f09SDavid van Moolenbroek 	result = dns_db_createiterator(db, 0, &iter);
1215*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1216*00b67f09SDavid van Moolenbroek 		goto cleanup;
1217*00b67f09SDavid van Moolenbroek 
1218*00b67f09SDavid van Moolenbroek 	result = dns_dbiterator_seek(iter, name);
1219*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
1220*00b67f09SDavid van Moolenbroek 		goto cleanup;
1221*00b67f09SDavid van Moolenbroek 
1222*00b67f09SDavid van Moolenbroek 	while (result == ISC_R_SUCCESS) {
1223*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_current(iter, &node, nodename);
1224*00b67f09SDavid van Moolenbroek 		if (result == DNS_R_NEWORIGIN)
1225*00b67f09SDavid van Moolenbroek 			result = ISC_R_SUCCESS;
1226*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1227*00b67f09SDavid van Moolenbroek 			goto cleanup;
1228*00b67f09SDavid van Moolenbroek 		/*
1229*00b67f09SDavid van Moolenbroek 		 * Are we done?
1230*00b67f09SDavid van Moolenbroek 		 */
1231*00b67f09SDavid van Moolenbroek 		if (! dns_name_issubdomain(nodename, name))
1232*00b67f09SDavid van Moolenbroek 			goto cleanup;
1233*00b67f09SDavid van Moolenbroek 
1234*00b67f09SDavid van Moolenbroek 		/*
1235*00b67f09SDavid van Moolenbroek 		 * If clearnode fails record and move onto the next node.
1236*00b67f09SDavid van Moolenbroek 		 */
1237*00b67f09SDavid van Moolenbroek 		result = clearnode(db, node);
1238*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS && answer == ISC_R_SUCCESS)
1239*00b67f09SDavid van Moolenbroek 			answer = result;
1240*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1241*00b67f09SDavid van Moolenbroek 		result = dns_dbiterator_next(iter);
1242*00b67f09SDavid van Moolenbroek 	}
1243*00b67f09SDavid van Moolenbroek 
1244*00b67f09SDavid van Moolenbroek  cleanup:
1245*00b67f09SDavid van Moolenbroek 	if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND)
1246*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1247*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS && answer == ISC_R_SUCCESS)
1248*00b67f09SDavid van Moolenbroek 		answer = result;
1249*00b67f09SDavid van Moolenbroek 	if (node != NULL)
1250*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(db, &node);
1251*00b67f09SDavid van Moolenbroek 	if (iter != NULL)
1252*00b67f09SDavid van Moolenbroek 		dns_dbiterator_destroy(&iter);
1253*00b67f09SDavid van Moolenbroek 
1254*00b67f09SDavid van Moolenbroek 	return (answer);
1255*00b67f09SDavid van Moolenbroek }
1256*00b67f09SDavid van Moolenbroek 
1257*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_flushname(dns_cache_t * cache,dns_name_t * name)1258*00b67f09SDavid van Moolenbroek dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
1259*00b67f09SDavid van Moolenbroek 	return (dns_cache_flushnode(cache, name, ISC_FALSE));
1260*00b67f09SDavid van Moolenbroek }
1261*00b67f09SDavid van Moolenbroek 
1262*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_flushnode(dns_cache_t * cache,dns_name_t * name,isc_boolean_t tree)1263*00b67f09SDavid van Moolenbroek dns_cache_flushnode(dns_cache_t *cache, dns_name_t *name,
1264*00b67f09SDavid van Moolenbroek 		    isc_boolean_t tree)
1265*00b67f09SDavid van Moolenbroek {
1266*00b67f09SDavid van Moolenbroek 	isc_result_t result;
1267*00b67f09SDavid van Moolenbroek 	dns_dbnode_t *node = NULL;
1268*00b67f09SDavid van Moolenbroek 	dns_db_t *db = NULL;
1269*00b67f09SDavid van Moolenbroek 
1270*00b67f09SDavid van Moolenbroek 	if (dns_name_equal(name, dns_rootname))
1271*00b67f09SDavid van Moolenbroek 		return (dns_cache_flush(cache));
1272*00b67f09SDavid van Moolenbroek 
1273*00b67f09SDavid van Moolenbroek 	LOCK(&cache->lock);
1274*00b67f09SDavid van Moolenbroek 	if (cache->db != NULL)
1275*00b67f09SDavid van Moolenbroek 		dns_db_attach(cache->db, &db);
1276*00b67f09SDavid van Moolenbroek 	UNLOCK(&cache->lock);
1277*00b67f09SDavid van Moolenbroek 	if (db == NULL)
1278*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
1279*00b67f09SDavid van Moolenbroek 
1280*00b67f09SDavid van Moolenbroek 	if (tree) {
1281*00b67f09SDavid van Moolenbroek 		result = cleartree(cache->db, name);
1282*00b67f09SDavid van Moolenbroek 	} else {
1283*00b67f09SDavid van Moolenbroek 		result = dns_db_findnode(cache->db, name, ISC_FALSE, &node);
1284*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_NOTFOUND) {
1285*00b67f09SDavid van Moolenbroek 			result = ISC_R_SUCCESS;
1286*00b67f09SDavid van Moolenbroek 			goto cleanup_db;
1287*00b67f09SDavid van Moolenbroek 		}
1288*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
1289*00b67f09SDavid van Moolenbroek 			goto cleanup_db;
1290*00b67f09SDavid van Moolenbroek 		result = clearnode(cache->db, node);
1291*00b67f09SDavid van Moolenbroek 		dns_db_detachnode(cache->db, &node);
1292*00b67f09SDavid van Moolenbroek 	}
1293*00b67f09SDavid van Moolenbroek 
1294*00b67f09SDavid van Moolenbroek  cleanup_db:
1295*00b67f09SDavid van Moolenbroek 	dns_db_detach(&db);
1296*00b67f09SDavid van Moolenbroek 	return (result);
1297*00b67f09SDavid van Moolenbroek }
1298*00b67f09SDavid van Moolenbroek 
1299*00b67f09SDavid van Moolenbroek isc_stats_t *
dns_cache_getstats(dns_cache_t * cache)1300*00b67f09SDavid van Moolenbroek dns_cache_getstats(dns_cache_t *cache) {
1301*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1302*00b67f09SDavid van Moolenbroek 	return (cache->stats);
1303*00b67f09SDavid van Moolenbroek }
1304*00b67f09SDavid van Moolenbroek 
1305*00b67f09SDavid van Moolenbroek void
dns_cache_updatestats(dns_cache_t * cache,isc_result_t result)1306*00b67f09SDavid van Moolenbroek dns_cache_updatestats(dns_cache_t *cache, isc_result_t result) {
1307*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1308*00b67f09SDavid van Moolenbroek 	if (cache->stats == NULL)
1309*00b67f09SDavid van Moolenbroek 		return;
1310*00b67f09SDavid van Moolenbroek 
1311*00b67f09SDavid van Moolenbroek 	switch (result) {
1312*00b67f09SDavid van Moolenbroek 	case ISC_R_SUCCESS:
1313*00b67f09SDavid van Moolenbroek 	case DNS_R_NCACHENXDOMAIN:
1314*00b67f09SDavid van Moolenbroek 	case DNS_R_NCACHENXRRSET:
1315*00b67f09SDavid van Moolenbroek 	case DNS_R_CNAME:
1316*00b67f09SDavid van Moolenbroek 	case DNS_R_DNAME:
1317*00b67f09SDavid van Moolenbroek 	case DNS_R_GLUE:
1318*00b67f09SDavid van Moolenbroek 	case DNS_R_ZONECUT:
1319*00b67f09SDavid van Moolenbroek 		isc_stats_increment(cache->stats,
1320*00b67f09SDavid van Moolenbroek 				    dns_cachestatscounter_queryhits);
1321*00b67f09SDavid van Moolenbroek 		break;
1322*00b67f09SDavid van Moolenbroek 	default:
1323*00b67f09SDavid van Moolenbroek 		isc_stats_increment(cache->stats,
1324*00b67f09SDavid van Moolenbroek 				    dns_cachestatscounter_querymisses);
1325*00b67f09SDavid van Moolenbroek 	}
1326*00b67f09SDavid van Moolenbroek }
1327*00b67f09SDavid van Moolenbroek 
1328*00b67f09SDavid van Moolenbroek /*
1329*00b67f09SDavid van Moolenbroek  * XXX: Much of the following code has been copied in from statschannel.c.
1330*00b67f09SDavid van Moolenbroek  * We should refactor this into a generic function in stats.c that can be
1331*00b67f09SDavid van Moolenbroek  * called from both places.
1332*00b67f09SDavid van Moolenbroek  */
1333*00b67f09SDavid van Moolenbroek typedef struct
1334*00b67f09SDavid van Moolenbroek cache_dumparg {
1335*00b67f09SDavid van Moolenbroek 	isc_statsformat_t	type;
1336*00b67f09SDavid van Moolenbroek 	void			*arg;		/* type dependent argument */
1337*00b67f09SDavid van Moolenbroek 	int			ncounters;	/* for general statistics */
1338*00b67f09SDavid van Moolenbroek 	int			*counterindices; /* for general statistics */
1339*00b67f09SDavid van Moolenbroek 	isc_uint64_t		*countervalues;	 /* for general statistics */
1340*00b67f09SDavid van Moolenbroek 	isc_result_t		result;
1341*00b67f09SDavid van Moolenbroek } cache_dumparg_t;
1342*00b67f09SDavid van Moolenbroek 
1343*00b67f09SDavid van Moolenbroek static void
getcounter(isc_statscounter_t counter,isc_uint64_t val,void * arg)1344*00b67f09SDavid van Moolenbroek getcounter(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
1345*00b67f09SDavid van Moolenbroek 	cache_dumparg_t *dumparg = arg;
1346*00b67f09SDavid van Moolenbroek 
1347*00b67f09SDavid van Moolenbroek 	REQUIRE(counter < dumparg->ncounters);
1348*00b67f09SDavid van Moolenbroek 	dumparg->countervalues[counter] = val;
1349*00b67f09SDavid van Moolenbroek }
1350*00b67f09SDavid van Moolenbroek 
1351*00b67f09SDavid van Moolenbroek static void
getcounters(isc_stats_t * stats,isc_statsformat_t type,int ncounters,int * indices,isc_uint64_t * values)1352*00b67f09SDavid van Moolenbroek getcounters(isc_stats_t *stats, isc_statsformat_t type, int ncounters,
1353*00b67f09SDavid van Moolenbroek 	    int *indices, isc_uint64_t *values)
1354*00b67f09SDavid van Moolenbroek {
1355*00b67f09SDavid van Moolenbroek 	cache_dumparg_t dumparg;
1356*00b67f09SDavid van Moolenbroek 
1357*00b67f09SDavid van Moolenbroek 	memset(values, 0, sizeof(values[0]) * ncounters);
1358*00b67f09SDavid van Moolenbroek 
1359*00b67f09SDavid van Moolenbroek 	dumparg.type = type;
1360*00b67f09SDavid van Moolenbroek 	dumparg.ncounters = ncounters;
1361*00b67f09SDavid van Moolenbroek 	dumparg.counterindices = indices;
1362*00b67f09SDavid van Moolenbroek 	dumparg.countervalues = values;
1363*00b67f09SDavid van Moolenbroek 
1364*00b67f09SDavid van Moolenbroek 	isc_stats_dump(stats, getcounter, &dumparg, ISC_STATSDUMP_VERBOSE);
1365*00b67f09SDavid van Moolenbroek }
1366*00b67f09SDavid van Moolenbroek 
1367*00b67f09SDavid van Moolenbroek void
dns_cache_dumpstats(dns_cache_t * cache,FILE * fp)1368*00b67f09SDavid van Moolenbroek dns_cache_dumpstats(dns_cache_t *cache, FILE *fp) {
1369*00b67f09SDavid van Moolenbroek 	int indices[dns_cachestatscounter_max];
1370*00b67f09SDavid van Moolenbroek 	isc_uint64_t values[dns_cachestatscounter_max];
1371*00b67f09SDavid van Moolenbroek 
1372*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1373*00b67f09SDavid van Moolenbroek 
1374*00b67f09SDavid van Moolenbroek 	getcounters(cache->stats, isc_statsformat_file,
1375*00b67f09SDavid van Moolenbroek 		    dns_cachestatscounter_max, indices, values);
1376*00b67f09SDavid van Moolenbroek 
1377*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
1378*00b67f09SDavid van Moolenbroek 		values[dns_cachestatscounter_hits],
1379*00b67f09SDavid van Moolenbroek 		"cache hits");
1380*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
1381*00b67f09SDavid van Moolenbroek 		values[dns_cachestatscounter_misses],
1382*00b67f09SDavid van Moolenbroek 		"cache misses");
1383*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
1384*00b67f09SDavid van Moolenbroek 		values[dns_cachestatscounter_queryhits],
1385*00b67f09SDavid van Moolenbroek 		"cache hits (from query)");
1386*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
1387*00b67f09SDavid van Moolenbroek 		values[dns_cachestatscounter_querymisses],
1388*00b67f09SDavid van Moolenbroek 		"cache misses (from query)");
1389*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
1390*00b67f09SDavid van Moolenbroek 		values[dns_cachestatscounter_deletelru],
1391*00b67f09SDavid van Moolenbroek 		"cache records deleted due to memory exhaustion");
1392*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
1393*00b67f09SDavid van Moolenbroek 		values[dns_cachestatscounter_deletettl],
1394*00b67f09SDavid van Moolenbroek 		"cache records deleted due to TTL expiration");
1395*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", dns_db_nodecount(cache->db),
1396*00b67f09SDavid van Moolenbroek 		"cache database nodes");
1397*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", dns_db_hashsize(cache->db),
1398*00b67f09SDavid van Moolenbroek 		"cache database hash buckets");
1399*00b67f09SDavid van Moolenbroek 
1400*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_total(cache->mctx),
1401*00b67f09SDavid van Moolenbroek 		"cache tree memory total");
1402*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_inuse(cache->mctx),
1403*00b67f09SDavid van Moolenbroek 		"cache tree memory in use");
1404*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache->mctx),
1405*00b67f09SDavid van Moolenbroek 		"cache tree highest memory in use");
1406*00b67f09SDavid van Moolenbroek 
1407*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_total(cache->hmctx),
1408*00b67f09SDavid van Moolenbroek 		"cache heap memory total");
1409*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_inuse(cache->hmctx),
1410*00b67f09SDavid van Moolenbroek 		"cache heap memory in use");
1411*00b67f09SDavid van Moolenbroek 	fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache->hmctx),
1412*00b67f09SDavid van Moolenbroek 		"cache heap highest memory in use");
1413*00b67f09SDavid van Moolenbroek }
1414*00b67f09SDavid van Moolenbroek 
1415*00b67f09SDavid van Moolenbroek #ifdef HAVE_LIBXML2
1416*00b67f09SDavid van Moolenbroek #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(/*CONSTCOND*/0)
1417*00b67f09SDavid van Moolenbroek static int
renderstat(const char * name,isc_uint64_t value,xmlTextWriterPtr writer)1418*00b67f09SDavid van Moolenbroek renderstat(const char *name, isc_uint64_t value, xmlTextWriterPtr writer) {
1419*00b67f09SDavid van Moolenbroek 	int xmlrc;
1420*00b67f09SDavid van Moolenbroek 
1421*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
1422*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterWriteAttribute(writer,
1423*00b67f09SDavid van Moolenbroek 					 ISC_XMLCHAR "name", ISC_XMLCHAR name));
1424*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterWriteFormatString(writer,
1425*00b67f09SDavid van Moolenbroek 					    "%" ISC_PRINT_QUADFORMAT "u",
1426*00b67f09SDavid van Moolenbroek 					    value));
1427*00b67f09SDavid van Moolenbroek 	TRY0(xmlTextWriterEndElement(writer)); /* counter */
1428*00b67f09SDavid van Moolenbroek 
1429*00b67f09SDavid van Moolenbroek error:
1430*00b67f09SDavid van Moolenbroek 	return (xmlrc);
1431*00b67f09SDavid van Moolenbroek }
1432*00b67f09SDavid van Moolenbroek 
1433*00b67f09SDavid van Moolenbroek int
dns_cache_renderxml(dns_cache_t * cache,xmlTextWriterPtr writer)1434*00b67f09SDavid van Moolenbroek dns_cache_renderxml(dns_cache_t *cache, xmlTextWriterPtr writer) {
1435*00b67f09SDavid van Moolenbroek 	int indices[dns_cachestatscounter_max];
1436*00b67f09SDavid van Moolenbroek 	isc_uint64_t values[dns_cachestatscounter_max];
1437*00b67f09SDavid van Moolenbroek 	int xmlrc;
1438*00b67f09SDavid van Moolenbroek 
1439*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1440*00b67f09SDavid van Moolenbroek 
1441*00b67f09SDavid van Moolenbroek 	getcounters(cache->stats, isc_statsformat_file,
1442*00b67f09SDavid van Moolenbroek 		    dns_cachestatscounter_max, indices, values);
1443*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("CacheHits",
1444*00b67f09SDavid van Moolenbroek 		   values[dns_cachestatscounter_hits], writer));
1445*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("CacheMisses",
1446*00b67f09SDavid van Moolenbroek 		   values[dns_cachestatscounter_misses], writer));
1447*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("QueryHits",
1448*00b67f09SDavid van Moolenbroek 		   values[dns_cachestatscounter_queryhits], writer));
1449*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("QueryMisses",
1450*00b67f09SDavid van Moolenbroek 		   values[dns_cachestatscounter_querymisses], writer));
1451*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("DeleteLRU",
1452*00b67f09SDavid van Moolenbroek 		   values[dns_cachestatscounter_deletelru], writer));
1453*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("DeleteTTL",
1454*00b67f09SDavid van Moolenbroek 		   values[dns_cachestatscounter_deletettl], writer));
1455*00b67f09SDavid van Moolenbroek 
1456*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("CacheNodes", dns_db_nodecount(cache->db), writer));
1457*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("CacheBuckets", dns_db_hashsize(cache->db), writer));
1458*00b67f09SDavid van Moolenbroek 
1459*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("TreeMemTotal", isc_mem_total(cache->mctx), writer));
1460*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("TreeMemInUse", isc_mem_inuse(cache->mctx), writer));
1461*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("TreeMemMax", isc_mem_maxinuse(cache->mctx), writer));
1462*00b67f09SDavid van Moolenbroek 
1463*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("HeapMemTotal", isc_mem_total(cache->hmctx), writer));
1464*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("HeapMemInUse", isc_mem_inuse(cache->hmctx), writer));
1465*00b67f09SDavid van Moolenbroek 	TRY0(renderstat("HeapMemMax", isc_mem_maxinuse(cache->hmctx), writer));
1466*00b67f09SDavid van Moolenbroek error:
1467*00b67f09SDavid van Moolenbroek 	return (xmlrc);
1468*00b67f09SDavid van Moolenbroek }
1469*00b67f09SDavid van Moolenbroek #endif
1470*00b67f09SDavid van Moolenbroek 
1471*00b67f09SDavid van Moolenbroek #ifdef HAVE_JSON
1472*00b67f09SDavid van Moolenbroek #define CHECKMEM(m) do { \
1473*00b67f09SDavid van Moolenbroek 	if (m == NULL) { \
1474*00b67f09SDavid van Moolenbroek 		result = ISC_R_NOMEMORY;\
1475*00b67f09SDavid van Moolenbroek 		goto error;\
1476*00b67f09SDavid van Moolenbroek 	} \
1477*00b67f09SDavid van Moolenbroek } while(/*CONSTCOND*/0)
1478*00b67f09SDavid van Moolenbroek 
1479*00b67f09SDavid van Moolenbroek isc_result_t
dns_cache_renderjson(dns_cache_t * cache,json_object * cstats)1480*00b67f09SDavid van Moolenbroek dns_cache_renderjson(dns_cache_t *cache, json_object *cstats) {
1481*00b67f09SDavid van Moolenbroek 	isc_result_t result = ISC_R_SUCCESS;
1482*00b67f09SDavid van Moolenbroek 	int indices[dns_cachestatscounter_max];
1483*00b67f09SDavid van Moolenbroek 	isc_uint64_t values[dns_cachestatscounter_max];
1484*00b67f09SDavid van Moolenbroek 	json_object *obj;
1485*00b67f09SDavid van Moolenbroek 
1486*00b67f09SDavid van Moolenbroek 	REQUIRE(VALID_CACHE(cache));
1487*00b67f09SDavid van Moolenbroek 
1488*00b67f09SDavid van Moolenbroek 	getcounters(cache->stats, isc_statsformat_file,
1489*00b67f09SDavid van Moolenbroek 		    dns_cachestatscounter_max, indices, values);
1490*00b67f09SDavid van Moolenbroek 
1491*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(values[dns_cachestatscounter_hits]);
1492*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1493*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "CacheHits", obj);
1494*00b67f09SDavid van Moolenbroek 
1495*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(values[dns_cachestatscounter_misses]);
1496*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1497*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "CacheMisses", obj);
1498*00b67f09SDavid van Moolenbroek 
1499*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(values[dns_cachestatscounter_queryhits]);
1500*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1501*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "QueryHits", obj);
1502*00b67f09SDavid van Moolenbroek 
1503*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(values[dns_cachestatscounter_querymisses]);
1504*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1505*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "QueryMisses", obj);
1506*00b67f09SDavid van Moolenbroek 
1507*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(values[dns_cachestatscounter_deletelru]);
1508*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1509*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "DeleteLRU", obj);
1510*00b67f09SDavid van Moolenbroek 
1511*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(values[dns_cachestatscounter_deletettl]);
1512*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1513*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "DeleteTTL", obj);
1514*00b67f09SDavid van Moolenbroek 
1515*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(dns_db_nodecount(cache->db));
1516*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1517*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "CacheNodes", obj);
1518*00b67f09SDavid van Moolenbroek 
1519*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(dns_db_hashsize(cache->db));
1520*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1521*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "CacheBuckets", obj);
1522*00b67f09SDavid van Moolenbroek 
1523*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(isc_mem_total(cache->mctx));
1524*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1525*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "TreeMemTotal", obj);
1526*00b67f09SDavid van Moolenbroek 
1527*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(isc_mem_inuse(cache->mctx));
1528*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1529*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "TreeMemInUse", obj);
1530*00b67f09SDavid van Moolenbroek 
1531*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(isc_mem_maxinuse(cache->mctx));
1532*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1533*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "HeapMemMax", obj);
1534*00b67f09SDavid van Moolenbroek 
1535*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(isc_mem_total(cache->hmctx));
1536*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1537*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "HeapMemTotal", obj);
1538*00b67f09SDavid van Moolenbroek 
1539*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(isc_mem_inuse(cache->hmctx));
1540*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1541*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "HeapMemInUse", obj);
1542*00b67f09SDavid van Moolenbroek 
1543*00b67f09SDavid van Moolenbroek 	obj = json_object_new_int64(isc_mem_maxinuse(cache->hmctx));
1544*00b67f09SDavid van Moolenbroek 	CHECKMEM(obj);
1545*00b67f09SDavid van Moolenbroek 	json_object_object_add(cstats, "HeapMemMax", obj);
1546*00b67f09SDavid van Moolenbroek 
1547*00b67f09SDavid van Moolenbroek 	result = ISC_R_SUCCESS;
1548*00b67f09SDavid van Moolenbroek error:
1549*00b67f09SDavid van Moolenbroek 	return (result);
1550*00b67f09SDavid van Moolenbroek }
1551*00b67f09SDavid van Moolenbroek #endif
1552