1/*
2 * Copyright (C) 2004-2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id$ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/mem.h>
25#include <isc/string.h>
26#include <isc/task.h>
27#include <isc/time.h>
28#include <isc/timer.h>
29#include <isc/util.h>
30
31#include <dns/cache.h>
32#include <dns/db.h>
33#include <dns/dbiterator.h>
34#include <dns/events.h>
35#include <dns/lib.h>
36#include <dns/log.h>
37#include <dns/masterdump.h>
38#include <dns/rdata.h>
39#include <dns/rdataset.h>
40#include <dns/rdatasetiter.h>
41#include <dns/result.h>
42
43#include "rbtdb.h"
44
45#define CACHE_MAGIC		ISC_MAGIC('$', '$', '$', '$')
46#define VALID_CACHE(cache)	ISC_MAGIC_VALID(cache, CACHE_MAGIC)
47
48/*!
49 * Control incremental cleaning.
50 * DNS_CACHE_MINSIZE is how many bytes is the floor for dns_cache_setcachesize().
51 * See also DNS_CACHE_CLEANERINCREMENT
52 */
53#define DNS_CACHE_MINSIZE	2097152 /*%< Bytes.  2097152 = 2 MB */
54/*!
55 * Control incremental cleaning.
56 * CLEANERINCREMENT is how many nodes are examined in one pass.
57 * See also DNS_CACHE_MINSIZE
58 */
59#define DNS_CACHE_CLEANERINCREMENT	1000U	/*%< Number of nodes. */
60
61/***
62 ***	Types
63 ***/
64
65/*
66 * A cache_cleaner_t encapsulates the state of the periodic
67 * cache cleaning.
68 */
69
70typedef struct cache_cleaner cache_cleaner_t;
71
72typedef enum {
73	cleaner_s_idle,	/*%< Waiting for cleaning-interval to expire. */
74	cleaner_s_busy,	/*%< Currently cleaning. */
75	cleaner_s_done	/*%< Freed enough memory after being overmem. */
76} cleaner_state_t;
77
78/*
79 * Convenience macros for comprehensive assertion checking.
80 */
81#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
82			 (c)->resched_event != NULL)
83#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
84			 (c)->iterator != NULL && \
85			 (c)->resched_event == NULL)
86
87/*%
88 * Accesses to a cache cleaner object are synchronized through
89 * task/event serialization, or locked from the cache object.
90 */
91struct cache_cleaner {
92	isc_mutex_t	lock;
93	/*%<
94	 * Locks overmem_event, overmem.  Note: never allocate memory
95	 * while holding this lock - that could lead to deadlock since
96	 * the lock is take by water() which is called from the memory
97	 * allocator.
98	 */
99
100	dns_cache_t	*cache;
101	isc_task_t	*task;
102	unsigned int	cleaning_interval; /*% The cleaning-interval from
103					      named.conf, in seconds. */
104	isc_timer_t	*cleaning_timer;
105	isc_event_t	*resched_event;	/*% Sent by cleaner task to
106					   itself to reschedule */
107	isc_event_t	*overmem_event;
108
109	dns_dbiterator_t *iterator;
110	unsigned int	increment;	/*% Number of names to
111					   clean in one increment */
112	cleaner_state_t	state;		/*% Idle/Busy. */
113	isc_boolean_t	overmem;	/*% The cache is in an overmem state. */
114	isc_boolean_t	 replaceiterator;
115};
116
117/*%
118 * The actual cache object.
119 */
120
121struct dns_cache {
122	/* Unlocked. */
123	unsigned int		magic;
124	isc_mutex_t		lock;
125	isc_mutex_t		filelock;
126	isc_mem_t		*mctx;		/* Main cache memory */
127	isc_mem_t		*hmctx;		/* Heap memory */
128	char			*name;
129
130	/* Locked by 'lock'. */
131	int			references;
132	int			live_tasks;
133	dns_rdataclass_t	rdclass;
134	dns_db_t		*db;
135	cache_cleaner_t		cleaner;
136	char			*db_type;
137	int			db_argc;
138	char			**db_argv;
139	isc_uint32_t		size;
140
141	/* Locked by 'filelock'. */
142	char			*filename;
143	/* Access to the on-disk cache file is also locked by 'filelock'. */
144};
145
146/***
147 ***	Functions
148 ***/
149
150static isc_result_t
151cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
152		   isc_timermgr_t *timermgr, cache_cleaner_t *cleaner);
153
154static void
155cleaning_timer_action(isc_task_t *task, isc_event_t *event);
156
157static void
158incremental_cleaning_action(isc_task_t *task, isc_event_t *event);
159
160static void
161cleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
162
163static void
164overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
165
166static inline isc_result_t
167cache_create_db(dns_cache_t *cache, dns_db_t **db) {
168	return (dns_db_create(cache->mctx, cache->db_type, dns_rootname,
169			      dns_dbtype_cache, cache->rdclass,
170			      cache->db_argc, cache->db_argv, db));
171}
172
173isc_result_t
174dns_cache_create(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
175		 isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
176		 const char *db_type, unsigned int db_argc, char **db_argv,
177		 dns_cache_t **cachep)
178{
179	return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass, "",
180				  db_type, db_argc, db_argv, cachep));
181}
182
183isc_result_t
184dns_cache_create2(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
185		  isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
186		  const char *cachename, const char *db_type,
187		  unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
188{
189	return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass,
190				  cachename, db_type, db_argc, db_argv,
191				  cachep));
192}
193
194isc_result_t
195dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr,
196		  isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
197		  const char *cachename, const char *db_type,
198		  unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
199{
200	isc_result_t result;
201	dns_cache_t *cache;
202	int i, extra = 0;
203	isc_task_t *dbtask;
204
205	REQUIRE(cachep != NULL);
206	REQUIRE(*cachep == NULL);
207	REQUIRE(cmctx != NULL);
208	REQUIRE(hmctx != NULL);
209	REQUIRE(cachename != NULL);
210
211	cache = isc_mem_get(cmctx, sizeof(*cache));
212	if (cache == NULL)
213		return (ISC_R_NOMEMORY);
214
215	cache->mctx = cache->hmctx = NULL;
216	isc_mem_attach(cmctx, &cache->mctx);
217	isc_mem_attach(hmctx, &cache->hmctx);
218
219	cache->name = NULL;
220	if (cachename != NULL) {
221		cache->name = isc_mem_strdup(cmctx, cachename);
222		if (cache->name == NULL) {
223			result = ISC_R_NOMEMORY;
224			goto cleanup_mem;
225		}
226	}
227
228	result = isc_mutex_init(&cache->lock);
229	if (result != ISC_R_SUCCESS)
230		goto cleanup_mem;
231
232	result = isc_mutex_init(&cache->filelock);
233	if (result != ISC_R_SUCCESS)
234		goto cleanup_lock;
235
236	cache->references = 1;
237	cache->live_tasks = 0;
238	cache->rdclass = rdclass;
239
240	cache->db_type = isc_mem_strdup(cmctx, db_type);
241	if (cache->db_type == NULL) {
242		result = ISC_R_NOMEMORY;
243		goto cleanup_filelock;
244	}
245
246	/*
247	 * For databases of type "rbt" we pass hmctx to dns_db_create()
248	 * via cache->db_argv, followed by the rest of the arguments in
249	 * db_argv (of which there really shouldn't be any).
250	 */
251	if (strcmp(cache->db_type, "rbt") == 0)
252		extra = 1;
253
254	cache->db_argc = db_argc + extra;
255	cache->db_argv = NULL;
256
257	if (cache->db_argc != 0) {
258		cache->db_argv = isc_mem_get(cmctx,
259					     cache->db_argc * sizeof(char *));
260		if (cache->db_argv == NULL) {
261			result = ISC_R_NOMEMORY;
262			goto cleanup_dbtype;
263		}
264
265		for (i = 0; i < cache->db_argc; i++)
266			cache->db_argv[i] = NULL;
267
268		cache->db_argv[0] = (char *) hmctx;
269		for (i = extra; i < cache->db_argc; i++) {
270			cache->db_argv[i] = isc_mem_strdup(cmctx,
271							   db_argv[i - extra]);
272			if (cache->db_argv[i] == NULL) {
273				result = ISC_R_NOMEMORY;
274				goto cleanup_dbargv;
275			}
276		}
277	}
278
279	/*
280	 * Create the database
281	 */
282	cache->db = NULL;
283	result = cache_create_db(cache, &cache->db);
284	if (result != ISC_R_SUCCESS)
285		goto cleanup_dbargv;
286	if (taskmgr != NULL) {
287		dbtask = NULL;
288		result = isc_task_create(taskmgr, 1, &dbtask);
289		if (result != ISC_R_SUCCESS)
290			goto cleanup_db;
291		dns_db_settask(cache->db, dbtask);
292		isc_task_detach(&dbtask);
293	}
294
295	cache->filename = NULL;
296
297	cache->magic = CACHE_MAGIC;
298
299	/*
300	 * RBT-type cache DB has its own mechanism of cache cleaning and doesn't
301	 * need the control of the generic cleaner.
302	 */
303	if (strcmp(db_type, "rbt") == 0)
304		result = cache_cleaner_init(cache, NULL, NULL, &cache->cleaner);
305	else {
306		result = cache_cleaner_init(cache, taskmgr, timermgr,
307					    &cache->cleaner);
308	}
309	if (result != ISC_R_SUCCESS)
310		goto cleanup_db;
311
312	*cachep = cache;
313	return (ISC_R_SUCCESS);
314
315 cleanup_db:
316	dns_db_detach(&cache->db);
317 cleanup_dbargv:
318	for (i = extra; i < cache->db_argc; i++)
319		if (cache->db_argv[i] != NULL)
320			isc_mem_free(cmctx, cache->db_argv[i]);
321	if (cache->db_argv != NULL)
322		isc_mem_put(cmctx, cache->db_argv,
323			    cache->db_argc * sizeof(char *));
324 cleanup_dbtype:
325	isc_mem_free(cmctx, cache->db_type);
326 cleanup_filelock:
327	DESTROYLOCK(&cache->filelock);
328 cleanup_lock:
329	DESTROYLOCK(&cache->lock);
330 cleanup_mem:
331	if (cache->name != NULL)
332		isc_mem_free(cmctx, cache->name);
333	isc_mem_detach(&cache->hmctx);
334	isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
335	return (result);
336}
337
338static void
339cache_free(dns_cache_t *cache) {
340	int i;
341
342	REQUIRE(VALID_CACHE(cache));
343	REQUIRE(cache->references == 0);
344
345	isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0);
346
347	if (cache->cleaner.task != NULL)
348		isc_task_detach(&cache->cleaner.task);
349
350	if (cache->cleaner.overmem_event != NULL)
351		isc_event_free(&cache->cleaner.overmem_event);
352
353	if (cache->cleaner.resched_event != NULL)
354		isc_event_free(&cache->cleaner.resched_event);
355
356	if (cache->cleaner.iterator != NULL)
357		dns_dbiterator_destroy(&cache->cleaner.iterator);
358
359	DESTROYLOCK(&cache->cleaner.lock);
360
361	if (cache->filename) {
362		isc_mem_free(cache->mctx, cache->filename);
363		cache->filename = NULL;
364	}
365
366	if (cache->db != NULL)
367		dns_db_detach(&cache->db);
368
369	if (cache->db_argv != NULL) {
370		/*
371		 * We don't free db_argv[0] in "rbt" cache databases
372		 * as it's a pointer to hmctx
373		 */
374		int extra = 0;
375		if (strcmp(cache->db_type, "rbt") == 0)
376			extra = 1;
377		for (i = extra; i < cache->db_argc; i++)
378			if (cache->db_argv[i] != NULL)
379				isc_mem_free(cache->mctx, cache->db_argv[i]);
380		isc_mem_put(cache->mctx, cache->db_argv,
381			    cache->db_argc * sizeof(char *));
382	}
383
384	if (cache->db_type != NULL)
385		isc_mem_free(cache->mctx, cache->db_type);
386
387	if (cache->name != NULL)
388		isc_mem_free(cache->mctx, cache->name);
389
390	DESTROYLOCK(&cache->lock);
391	DESTROYLOCK(&cache->filelock);
392
393	cache->magic = 0;
394	isc_mem_detach(&cache->hmctx);
395	isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
396}
397
398
399void
400dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) {
401
402	REQUIRE(VALID_CACHE(cache));
403	REQUIRE(targetp != NULL && *targetp == NULL);
404
405	LOCK(&cache->lock);
406	cache->references++;
407	UNLOCK(&cache->lock);
408
409	*targetp = cache;
410}
411
412void
413dns_cache_detach(dns_cache_t **cachep) {
414	dns_cache_t *cache;
415	isc_boolean_t free_cache = ISC_FALSE;
416
417	REQUIRE(cachep != NULL);
418	cache = *cachep;
419	REQUIRE(VALID_CACHE(cache));
420
421	LOCK(&cache->lock);
422	REQUIRE(cache->references > 0);
423	cache->references--;
424	if (cache->references == 0) {
425		cache->cleaner.overmem = ISC_FALSE;
426		free_cache = ISC_TRUE;
427	}
428
429	*cachep = NULL;
430
431	if (free_cache) {
432		/*
433		 * When the cache is shut down, dump it to a file if one is
434		 * specified.
435		 */
436		isc_result_t result = dns_cache_dump(cache);
437		if (result != ISC_R_SUCCESS)
438			isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
439				      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
440				      "error dumping cache: %s ",
441				      isc_result_totext(result));
442
443		/*
444		 * If the cleaner task exists, let it free the cache.
445		 */
446		if (cache->live_tasks > 0) {
447			isc_task_shutdown(cache->cleaner.task);
448			free_cache = ISC_FALSE;
449		}
450	}
451
452	UNLOCK(&cache->lock);
453
454	if (free_cache)
455		cache_free(cache);
456}
457
458void
459dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp) {
460	REQUIRE(VALID_CACHE(cache));
461	REQUIRE(dbp != NULL && *dbp == NULL);
462	REQUIRE(cache->db != NULL);
463
464	LOCK(&cache->lock);
465	dns_db_attach(cache->db, dbp);
466	UNLOCK(&cache->lock);
467
468}
469
470isc_result_t
471dns_cache_setfilename(dns_cache_t *cache, const char *filename) {
472	char *newname;
473
474	REQUIRE(VALID_CACHE(cache));
475	REQUIRE(filename != NULL);
476
477	newname = isc_mem_strdup(cache->mctx, filename);
478	if (newname == NULL)
479		return (ISC_R_NOMEMORY);
480
481	LOCK(&cache->filelock);
482	if (cache->filename)
483		isc_mem_free(cache->mctx, cache->filename);
484	cache->filename = newname;
485	UNLOCK(&cache->filelock);
486
487	return (ISC_R_SUCCESS);
488}
489
490#ifdef BIND9
491isc_result_t
492dns_cache_load(dns_cache_t *cache) {
493	isc_result_t result;
494
495	REQUIRE(VALID_CACHE(cache));
496
497	if (cache->filename == NULL)
498		return (ISC_R_SUCCESS);
499
500	LOCK(&cache->filelock);
501	result = dns_db_load(cache->db, cache->filename);
502	UNLOCK(&cache->filelock);
503
504	return (result);
505}
506#endif /* BIND9 */
507
508isc_result_t
509dns_cache_dump(dns_cache_t *cache) {
510#ifdef BIND9
511	isc_result_t result;
512#endif
513
514	REQUIRE(VALID_CACHE(cache));
515
516	if (cache->filename == NULL)
517		return (ISC_R_SUCCESS);
518
519#ifdef BIND9
520	LOCK(&cache->filelock);
521	result = dns_master_dump(cache->mctx, cache->db, NULL,
522				 &dns_master_style_cache, cache->filename);
523	UNLOCK(&cache->filelock);
524	return (result);
525#else
526	return (ISC_R_NOTIMPLEMENTED);
527#endif
528
529}
530
531void
532dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
533	isc_interval_t interval;
534	isc_result_t result;
535
536	LOCK(&cache->lock);
537
538	/*
539	 * It may be the case that the cache has already shut down.
540	 * If so, it has no timer.
541	 */
542	if (cache->cleaner.cleaning_timer == NULL)
543		goto unlock;
544
545	cache->cleaner.cleaning_interval = t;
546
547	if (t == 0) {
548		result = isc_timer_reset(cache->cleaner.cleaning_timer,
549					 isc_timertype_inactive,
550					 NULL, NULL, ISC_TRUE);
551	} else {
552		isc_interval_set(&interval, cache->cleaner.cleaning_interval,
553				 0);
554		result = isc_timer_reset(cache->cleaner.cleaning_timer,
555					 isc_timertype_ticker,
556					 NULL, &interval, ISC_FALSE);
557	}
558	if (result != ISC_R_SUCCESS)
559		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
560			      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
561			      "could not set cache cleaning interval: %s",
562			      isc_result_totext(result));
563
564 unlock:
565	UNLOCK(&cache->lock);
566}
567
568unsigned int
569dns_cache_getcleaninginterval(dns_cache_t *cache) {
570	unsigned int t;
571
572	REQUIRE(VALID_CACHE(cache));
573
574	LOCK(&cache->lock);
575	t = cache->cleaner.cleaning_interval;
576	UNLOCK(&cache->lock);
577
578	return (t);
579}
580
581const char *
582dns_cache_getname(dns_cache_t *cache) {
583	REQUIRE(VALID_CACHE(cache));
584
585	return (cache->name);
586}
587
588/*
589 * Initialize the cache cleaner object at *cleaner.
590 * Space for the object must be allocated by the caller.
591 */
592
593static isc_result_t
594cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
595		   isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
596{
597	isc_result_t result;
598
599	result = isc_mutex_init(&cleaner->lock);
600	if (result != ISC_R_SUCCESS)
601		goto fail;
602
603	cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
604	cleaner->state = cleaner_s_idle;
605	cleaner->cache = cache;
606	cleaner->iterator = NULL;
607	cleaner->overmem = ISC_FALSE;
608	cleaner->replaceiterator = ISC_FALSE;
609
610	cleaner->task = NULL;
611	cleaner->cleaning_timer = NULL;
612	cleaner->resched_event = NULL;
613	cleaner->overmem_event = NULL;
614	cleaner->cleaning_interval = 0; /* Initially turned off. */
615
616	result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
617				       &cleaner->iterator);
618	if (result != ISC_R_SUCCESS)
619		goto cleanup;
620
621	if (taskmgr != NULL && timermgr != NULL) {
622		result = isc_task_create(taskmgr, 1, &cleaner->task);
623		if (result != ISC_R_SUCCESS) {
624			UNEXPECTED_ERROR(__FILE__, __LINE__,
625					 "isc_task_create() failed: %s",
626					 dns_result_totext(result));
627			result = ISC_R_UNEXPECTED;
628			goto cleanup;
629		}
630		cleaner->cache->live_tasks++;
631		isc_task_setname(cleaner->task, "cachecleaner", cleaner);
632
633		result = isc_task_onshutdown(cleaner->task,
634					     cleaner_shutdown_action, cache);
635		if (result != ISC_R_SUCCESS) {
636			UNEXPECTED_ERROR(__FILE__, __LINE__,
637					 "cache cleaner: "
638					 "isc_task_onshutdown() failed: %s",
639					 dns_result_totext(result));
640			goto cleanup;
641		}
642
643		result = isc_timer_create(timermgr, isc_timertype_inactive,
644					   NULL, NULL, cleaner->task,
645					   cleaning_timer_action, cleaner,
646					   &cleaner->cleaning_timer);
647		if (result != ISC_R_SUCCESS) {
648			UNEXPECTED_ERROR(__FILE__, __LINE__,
649					 "isc_timer_create() failed: %s",
650					 dns_result_totext(result));
651			result = ISC_R_UNEXPECTED;
652			goto cleanup;
653		}
654
655		cleaner->resched_event =
656			isc_event_allocate(cache->mctx, cleaner,
657					   DNS_EVENT_CACHECLEAN,
658					   incremental_cleaning_action,
659					   cleaner, sizeof(isc_event_t));
660		if (cleaner->resched_event == NULL) {
661			result = ISC_R_NOMEMORY;
662			goto cleanup;
663		}
664
665		cleaner->overmem_event =
666			isc_event_allocate(cache->mctx, cleaner,
667					   DNS_EVENT_CACHEOVERMEM,
668					   overmem_cleaning_action,
669					   cleaner, sizeof(isc_event_t));
670		if (cleaner->overmem_event == NULL) {
671			result = ISC_R_NOMEMORY;
672			goto cleanup;
673		}
674	}
675
676	return (ISC_R_SUCCESS);
677
678 cleanup:
679	if (cleaner->overmem_event != NULL)
680		isc_event_free(&cleaner->overmem_event);
681	if (cleaner->resched_event != NULL)
682		isc_event_free(&cleaner->resched_event);
683	if (cleaner->cleaning_timer != NULL)
684		isc_timer_detach(&cleaner->cleaning_timer);
685	if (cleaner->task != NULL)
686		isc_task_detach(&cleaner->task);
687	if (cleaner->iterator != NULL)
688		dns_dbiterator_destroy(&cleaner->iterator);
689	DESTROYLOCK(&cleaner->lock);
690 fail:
691	return (result);
692}
693
694static void
695begin_cleaning(cache_cleaner_t *cleaner) {
696	isc_result_t result = ISC_R_SUCCESS;
697
698	REQUIRE(CLEANER_IDLE(cleaner));
699
700	/*
701	 * Create an iterator, if it does not already exist, and
702	 * position it at the beginning of the cache.
703	 */
704	if (cleaner->iterator == NULL)
705		result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
706					       &cleaner->iterator);
707	if (result != ISC_R_SUCCESS)
708		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
709			      DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
710			      "cache cleaner could not create "
711			      "iterator: %s", isc_result_totext(result));
712	else {
713		dns_dbiterator_setcleanmode(cleaner->iterator, ISC_TRUE);
714		result = dns_dbiterator_first(cleaner->iterator);
715	}
716	if (result != ISC_R_SUCCESS) {
717		/*
718		 * If the result is ISC_R_NOMORE, the database is empty,
719		 * so there is nothing to be cleaned.
720		 */
721		if (result != ISC_R_NOMORE && cleaner->iterator != NULL) {
722			UNEXPECTED_ERROR(__FILE__, __LINE__,
723					 "cache cleaner: "
724					 "dns_dbiterator_first() failed: %s",
725					 dns_result_totext(result));
726			dns_dbiterator_destroy(&cleaner->iterator);
727		} else if (cleaner->iterator != NULL) {
728			result = dns_dbiterator_pause(cleaner->iterator);
729			RUNTIME_CHECK(result == ISC_R_SUCCESS);
730		}
731	} else {
732		/*
733		 * Pause the iterator to free its lock.
734		 */
735		result = dns_dbiterator_pause(cleaner->iterator);
736		RUNTIME_CHECK(result == ISC_R_SUCCESS);
737
738		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
739			      DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
740			      "begin cache cleaning, mem inuse %lu",
741			    (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
742		cleaner->state = cleaner_s_busy;
743		isc_task_send(cleaner->task, &cleaner->resched_event);
744	}
745
746	return;
747}
748
749static void
750end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
751	isc_result_t result;
752
753	REQUIRE(CLEANER_BUSY(cleaner));
754	REQUIRE(event != NULL);
755
756	result = dns_dbiterator_pause(cleaner->iterator);
757	if (result != ISC_R_SUCCESS)
758		dns_dbiterator_destroy(&cleaner->iterator);
759
760	dns_cache_setcleaninginterval(cleaner->cache,
761				      cleaner->cleaning_interval);
762
763	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
764		      ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
765		      (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
766
767	cleaner->state = cleaner_s_idle;
768	cleaner->resched_event = event;
769}
770
771/*
772 * This is run once for every cache-cleaning-interval as defined in named.conf.
773 */
774static void
775cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
776	cache_cleaner_t *cleaner = event->ev_arg;
777
778	UNUSED(task);
779
780	INSIST(task == cleaner->task);
781	INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
782
783	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
784		      ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
785		      "cleaner state = %d", cleaner->state);
786
787	if (cleaner->state == cleaner_s_idle)
788		begin_cleaning(cleaner);
789
790	isc_event_free(&event);
791}
792
793/*
794 * This is called when the cache either surpasses its upper limit
795 * or shrinks beyond its lower limit.
796 */
797static void
798overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
799	cache_cleaner_t *cleaner = event->ev_arg;
800	isc_boolean_t want_cleaning = ISC_FALSE;
801
802	UNUSED(task);
803
804	INSIST(task == cleaner->task);
805	INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
806	INSIST(cleaner->overmem_event == NULL);
807
808	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
809		      ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
810		      "overmem = %d, state = %d", cleaner->overmem,
811		      cleaner->state);
812
813	LOCK(&cleaner->lock);
814
815	if (cleaner->overmem) {
816		if (cleaner->state == cleaner_s_idle)
817			want_cleaning = ISC_TRUE;
818	} else {
819		if (cleaner->state == cleaner_s_busy)
820			/*
821			 * end_cleaning() can't be called here because
822			 * then both cleaner->overmem_event and
823			 * cleaner->resched_event will point to this
824			 * event.  Set the state to done, and then
825			 * when the incremental_cleaning_action() event
826			 * is posted, it will handle the end_cleaning.
827			 */
828			cleaner->state = cleaner_s_done;
829	}
830
831	cleaner->overmem_event = event;
832
833	UNLOCK(&cleaner->lock);
834
835	if (want_cleaning)
836		begin_cleaning(cleaner);
837}
838
839/*
840 * Do incremental cleaning.
841 */
842static void
843incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
844	cache_cleaner_t *cleaner = event->ev_arg;
845	isc_result_t result;
846	unsigned int n_names;
847	isc_time_t start;
848
849	UNUSED(task);
850
851	INSIST(task == cleaner->task);
852	INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
853
854	if (cleaner->state == cleaner_s_done) {
855		cleaner->state = cleaner_s_busy;
856		end_cleaning(cleaner, event);
857		LOCK(&cleaner->cache->lock);
858		LOCK(&cleaner->lock);
859		if (cleaner->replaceiterator) {
860			dns_dbiterator_destroy(&cleaner->iterator);
861			(void) dns_db_createiterator(cleaner->cache->db,
862						     ISC_FALSE,
863						     &cleaner->iterator);
864			cleaner->replaceiterator = ISC_FALSE;
865		}
866		UNLOCK(&cleaner->lock);
867		UNLOCK(&cleaner->cache->lock);
868		return;
869	}
870
871	INSIST(CLEANER_BUSY(cleaner));
872
873	n_names = cleaner->increment;
874
875	REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
876
877	isc_time_now(&start);
878	while (n_names-- > 0) {
879		dns_dbnode_t *node = NULL;
880
881		result = dns_dbiterator_current(cleaner->iterator, &node,
882						NULL);
883		if (result != ISC_R_SUCCESS) {
884			UNEXPECTED_ERROR(__FILE__, __LINE__,
885				 "cache cleaner: dns_dbiterator_current() "
886				 "failed: %s", dns_result_totext(result));
887
888			end_cleaning(cleaner, event);
889			return;
890		}
891
892		/*
893		 * The node was not needed, but was required by
894		 * dns_dbiterator_current().  Give up its reference.
895		 */
896		dns_db_detachnode(cleaner->cache->db, &node);
897
898		/*
899		 * Step to the next node.
900		 */
901		result = dns_dbiterator_next(cleaner->iterator);
902
903		if (result != ISC_R_SUCCESS) {
904			/*
905			 * Either the end was reached (ISC_R_NOMORE) or
906			 * some error was signaled.  If the cache is still
907			 * overmem and no error was encountered,
908			 * keep trying to clean it, otherwise stop cleaning.
909			 */
910			if (result != ISC_R_NOMORE)
911				UNEXPECTED_ERROR(__FILE__, __LINE__,
912						 "cache cleaner: "
913						 "dns_dbiterator_next() "
914						 "failed: %s",
915						 dns_result_totext(result));
916			else if (cleaner->overmem) {
917				result = dns_dbiterator_first(cleaner->
918							      iterator);
919				if (result == ISC_R_SUCCESS) {
920					isc_log_write(dns_lctx,
921						      DNS_LOGCATEGORY_DATABASE,
922						      DNS_LOGMODULE_CACHE,
923						      ISC_LOG_DEBUG(1),
924						      "cache cleaner: "
925						      "still overmem, "
926						      "reset and try again");
927					continue;
928				}
929			}
930
931			end_cleaning(cleaner, event);
932			return;
933		}
934	}
935
936	/*
937	 * We have successfully performed a cleaning increment but have
938	 * not gone through the entire cache.  Free the iterator locks
939	 * and reschedule another batch.  If it fails, just try to continue
940	 * anyway.
941	 */
942	result = dns_dbiterator_pause(cleaner->iterator);
943	RUNTIME_CHECK(result == ISC_R_SUCCESS);
944
945	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
946		      ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
947		      "mem inuse %lu, sleeping", cleaner->increment,
948		      (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
949
950	isc_task_send(task, &event);
951	INSIST(CLEANER_BUSY(cleaner));
952	return;
953}
954
955/*
956 * Do immediate cleaning.
957 */
958isc_result_t
959dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) {
960	isc_result_t result;
961	dns_dbiterator_t *iterator = NULL;
962
963	REQUIRE(VALID_CACHE(cache));
964
965	result = dns_db_createiterator(cache->db, 0, &iterator);
966	if (result != ISC_R_SUCCESS)
967		return result;
968
969	result = dns_dbiterator_first(iterator);
970
971	while (result == ISC_R_SUCCESS) {
972		dns_dbnode_t *node = NULL;
973		result = dns_dbiterator_current(iterator, &node,
974						(dns_name_t *)NULL);
975		if (result != ISC_R_SUCCESS)
976			break;
977
978		/*
979		 * Check TTLs, mark expired rdatasets stale.
980		 */
981		result = dns_db_expirenode(cache->db, node, now);
982		if (result != ISC_R_SUCCESS) {
983			UNEXPECTED_ERROR(__FILE__, __LINE__,
984					 "cache cleaner: dns_db_expirenode() "
985					 "failed: %s",
986					 dns_result_totext(result));
987			/*
988			 * Continue anyway.
989			 */
990		}
991
992		/*
993		 * This is where the actual freeing takes place.
994		 */
995		dns_db_detachnode(cache->db, &node);
996
997		result = dns_dbiterator_next(iterator);
998	}
999
1000	dns_dbiterator_destroy(&iterator);
1001
1002	if (result == ISC_R_NOMORE)
1003		result = ISC_R_SUCCESS;
1004
1005	return (result);
1006}
1007
1008static void
1009water(void *arg, int mark) {
1010	dns_cache_t *cache = arg;
1011	isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
1012
1013	REQUIRE(VALID_CACHE(cache));
1014
1015	LOCK(&cache->cleaner.lock);
1016
1017	if (overmem != cache->cleaner.overmem) {
1018		dns_db_overmem(cache->db, overmem);
1019		cache->cleaner.overmem = overmem;
1020		isc_mem_waterack(cache->mctx, mark);
1021	}
1022
1023	if (cache->cleaner.overmem_event != NULL)
1024		isc_task_send(cache->cleaner.task,
1025			      &cache->cleaner.overmem_event);
1026
1027	UNLOCK(&cache->cleaner.lock);
1028}
1029
1030void
1031dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
1032	isc_uint32_t lowater;
1033	isc_uint32_t hiwater;
1034
1035	REQUIRE(VALID_CACHE(cache));
1036
1037	/*
1038	 * Impose a minimum cache size; pathological things happen if there
1039	 * is too little room.
1040	 */
1041	if (size != 0 && size < DNS_CACHE_MINSIZE)
1042		size = DNS_CACHE_MINSIZE;
1043
1044	LOCK(&cache->lock);
1045	cache->size = size;
1046	UNLOCK(&cache->lock);
1047
1048	hiwater = size - (size >> 3);	/* Approximately 7/8ths. */
1049	lowater = size - (size >> 2);	/* Approximately 3/4ths. */
1050
1051	/*
1052	 * If the cache was overmem and cleaning, but now with the new limits
1053	 * it is no longer in an overmem condition, then the next
1054	 * isc_mem_put for cache memory will do the right thing and trigger
1055	 * water().
1056	 */
1057
1058	if (size == 0 || hiwater == 0 || lowater == 0)
1059		/*
1060		 * Disable cache memory limiting.
1061		 */
1062		isc_mem_setwater(cache->mctx, water, cache, 0, 0);
1063	else
1064		/*
1065		 * Establish new cache memory limits (either for the first
1066		 * time, or replacing other limits).
1067		 */
1068		isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
1069}
1070
1071isc_uint32_t
1072dns_cache_getcachesize(dns_cache_t *cache) {
1073	isc_uint32_t size;
1074
1075	REQUIRE(VALID_CACHE(cache));
1076
1077	LOCK(&cache->lock);
1078	size = cache->size;
1079	UNLOCK(&cache->lock);
1080
1081	return (size);
1082}
1083
1084/*
1085 * The cleaner task is shutting down; do the necessary cleanup.
1086 */
1087static void
1088cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
1089	dns_cache_t *cache = event->ev_arg;
1090	isc_boolean_t should_free = ISC_FALSE;
1091
1092	UNUSED(task);
1093
1094	INSIST(task == cache->cleaner.task);
1095	INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
1096
1097	if (CLEANER_BUSY(&cache->cleaner))
1098		end_cleaning(&cache->cleaner, event);
1099	else
1100		isc_event_free(&event);
1101
1102	LOCK(&cache->lock);
1103
1104	cache->live_tasks--;
1105	INSIST(cache->live_tasks == 0);
1106
1107	if (cache->references == 0)
1108		should_free = ISC_TRUE;
1109
1110	/*
1111	 * By detaching the timer in the context of its task,
1112	 * we are guaranteed that there will be no further timer
1113	 * events.
1114	 */
1115	if (cache->cleaner.cleaning_timer != NULL)
1116		isc_timer_detach(&cache->cleaner.cleaning_timer);
1117
1118	/* Make sure we don't reschedule anymore. */
1119	(void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
1120
1121	UNLOCK(&cache->lock);
1122
1123	if (should_free)
1124		cache_free(cache);
1125}
1126
1127isc_result_t
1128dns_cache_flush(dns_cache_t *cache) {
1129	dns_db_t *db = NULL;
1130	isc_result_t result;
1131
1132	result = cache_create_db(cache, &db);
1133	if (result != ISC_R_SUCCESS)
1134		return (result);
1135
1136	LOCK(&cache->lock);
1137	LOCK(&cache->cleaner.lock);
1138	if (cache->cleaner.state == cleaner_s_idle) {
1139		if (cache->cleaner.iterator != NULL)
1140			dns_dbiterator_destroy(&cache->cleaner.iterator);
1141		(void) dns_db_createiterator(db, ISC_FALSE,
1142					     &cache->cleaner.iterator);
1143	} else {
1144		if (cache->cleaner.state == cleaner_s_busy)
1145			cache->cleaner.state = cleaner_s_done;
1146		cache->cleaner.replaceiterator = ISC_TRUE;
1147	}
1148	dns_db_detach(&cache->db);
1149	cache->db = db;
1150	UNLOCK(&cache->cleaner.lock);
1151	UNLOCK(&cache->lock);
1152
1153	return (ISC_R_SUCCESS);
1154}
1155
1156isc_result_t
1157dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
1158	isc_result_t result;
1159	dns_rdatasetiter_t *iter = NULL;
1160	dns_dbnode_t *node = NULL;
1161	dns_db_t *db = NULL;
1162
1163	LOCK(&cache->lock);
1164	if (cache->db != NULL)
1165		dns_db_attach(cache->db, &db);
1166	UNLOCK(&cache->lock);
1167	if (db == NULL)
1168		return (ISC_R_SUCCESS);
1169	result = dns_db_findnode(cache->db, name, ISC_FALSE, &node);
1170	if (result == ISC_R_NOTFOUND) {
1171		result = ISC_R_SUCCESS;
1172		goto cleanup_db;
1173	}
1174	if (result != ISC_R_SUCCESS)
1175		goto cleanup_db;
1176
1177	result = dns_db_allrdatasets(cache->db, node, NULL,
1178				     (isc_stdtime_t)0, &iter);
1179	if (result != ISC_R_SUCCESS)
1180		goto cleanup_node;
1181
1182	for (result = dns_rdatasetiter_first(iter);
1183	     result == ISC_R_SUCCESS;
1184	     result = dns_rdatasetiter_next(iter))
1185	{
1186		dns_rdataset_t rdataset;
1187		dns_rdataset_init(&rdataset);
1188
1189		dns_rdatasetiter_current(iter, &rdataset);
1190		result = dns_db_deleterdataset(cache->db, node, NULL,
1191					       rdataset.type, rdataset.covers);
1192		dns_rdataset_disassociate(&rdataset);
1193		if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
1194			break;
1195	}
1196	if (result == ISC_R_NOMORE)
1197		result = ISC_R_SUCCESS;
1198
1199	dns_rdatasetiter_destroy(&iter);
1200
1201 cleanup_node:
1202	dns_db_detachnode(cache->db, &node);
1203
1204 cleanup_db:
1205	dns_db_detach(&db);
1206	return (result);
1207}
1208