1/*
2 * Copyright (C) 2004-2008, 2012, 2013  Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17/* $Id: acache.c,v 1.22 2008/02/07 23:46:54 tbox Exp $ */
18
19#include <config.h>
20
21#include <isc/atomic.h>
22#include <isc/event.h>
23#include <isc/hash.h>
24#include <isc/magic.h>
25#include <isc/mem.h>
26#include <isc/mutex.h>
27#include <isc/random.h>
28#include <isc/refcount.h>
29#include <isc/rwlock.h>
30#include <isc/serial.h>
31#include <isc/task.h>
32#include <isc/time.h>
33#include <isc/timer.h>
34
35#include <dns/acache.h>
36#include <dns/db.h>
37#include <dns/events.h>
38#include <dns/log.h>
39#include <dns/message.h>
40#include <dns/name.h>
41#include <dns/rdataset.h>
42#include <dns/result.h>
43#include <dns/zone.h>
44
45#define ACACHE_MAGIC			ISC_MAGIC('A', 'C', 'H', 'E')
46#define DNS_ACACHE_VALID(acache)	ISC_MAGIC_VALID(acache, ACACHE_MAGIC)
47
48#define ACACHEENTRY_MAGIC		ISC_MAGIC('A', 'C', 'E', 'T')
49#define DNS_ACACHEENTRY_VALID(entry)	ISC_MAGIC_VALID(entry, ACACHEENTRY_MAGIC)
50
51#define DBBUCKETS	67
52
53#if 0
54#define ATRACE(m)       isc_log_write(dns_lctx, \
55				      DNS_LOGCATEGORY_DATABASE, \
56				      DNS_LOGMODULE_ACACHE, \
57				      ISC_LOG_DEBUG(3), \
58				      "acache %p: %s", acache, (m))
59#define AATRACE(a,m)    isc_log_write(dns_lctx, \
60				      DNS_LOGCATEGORY_DATABASE, \
61				      DNS_LOGMODULE_ACACHE, \
62				      ISC_LOG_DEBUG(3), \
63				      "acache %p: %s", (a), (m))
64#else
65#define ATRACE(m)
66#define AATRACE(a, m)
67#endif
68
69/*
70 * The following variables control incremental cleaning.
71 * MINSIZE is how many bytes is the floor for dns_acache_setcachesize().
72 * CLEANERINCREMENT is how many entries are examined in one pass.
73 * (XXX simply derived from definitions in cache.c  There may be better
74 *  constants here.)
75 */
76#define DNS_ACACHE_MINSIZE 		2097152U /* Bytes.  2097152 = 2 MB */
77#define DNS_ACACHE_CLEANERINCREMENT	1000	 /* Number of entries. */
78
79#define DEFAULT_ACACHE_ENTRY_LOCK_COUNT	1009	 /*%< Should be prime. */
80
81#if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEATOMICSTORE)
82#define ACACHE_USE_RWLOCK 1
83#endif
84
85#ifdef ACACHE_USE_RWLOCK
86#define ACACHE_INITLOCK(l)	isc_rwlock_init((l), 0, 0)
87#define ACACHE_DESTROYLOCK(l)	isc_rwlock_destroy(l)
88#define ACACHE_LOCK(l, t)	RWLOCK((l), (t))
89#define ACACHE_UNLOCK(l, t)	RWUNLOCK((l), (t))
90
91#define acache_storetime(entry, t) \
92	(isc_atomic_store((isc_int32_t *)&(entry)->lastused, (t)))
93#else
94#define ACACHE_INITLOCK(l)	isc_mutex_init(l)
95#define ACACHE_DESTROYLOCK(l)	DESTROYLOCK(l)
96#define ACACHE_LOCK(l, t)	LOCK(l)
97#define ACACHE_UNLOCK(l, t)	UNLOCK(l)
98
99#define acache_storetime(entry, t) ((entry)->lastused = (t))
100#endif
101
102/* Locked by acache lock */
103typedef struct dbentry {
104	ISC_LINK(struct dbentry)	link;
105
106	dns_db_t			*db;
107	ISC_LIST(dns_acacheentry_t)	originlist;
108	ISC_LIST(dns_acacheentry_t)	referlist;
109} dbentry_t;
110
111typedef ISC_LIST(dbentry_t) dbentrylist_t;
112
113typedef struct acache_cleaner acache_cleaner_t;
114
115typedef enum {
116	cleaner_s_idle,	/* Waiting for cleaning-interval to expire. */
117	cleaner_s_busy,	/* Currently cleaning. */
118	cleaner_s_done  /* Freed enough memory after being overmem. */
119} cleaner_state_t;
120
121/*
122 * Convenience macros for comprehensive assertion checking.
123 */
124#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
125			 (c)->resched_event != NULL)
126#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
127			 (c)->resched_event == NULL)
128
129struct acache_cleaner {
130	isc_mutex_t		lock;
131	/*
132	 * Locks overmem_event, overmem.  (See cache.c)
133	 */
134
135	dns_acache_t		*acache;
136	unsigned int		cleaning_interval; /* The cleaning-interval
137						      from named.conf,
138						      in seconds. */
139
140	isc_stdtime_t		last_cleanup_time; /* The time when the last
141						      cleanup task completed */
142
143	isc_timer_t 		*cleaning_timer;
144	isc_event_t		*resched_event;	/* Sent by cleaner task to
145						   itself to reschedule */
146	isc_event_t		*overmem_event;
147
148	dns_acacheentry_t	*current_entry;	/* The bookmark entry to
149						   restart the cleaning.
150						   Locked by acache lock. */
151	int 		 	increment;	/* Number of entries to
152						   clean in one increment */
153
154	unsigned long		ncleaned;	/* Number of entries cleaned
155						   up (for logging purposes) */
156	cleaner_state_t  	state;		/* Idle/Busy/Done. */
157	isc_boolean_t	 	overmem;	/* The acache is in an overmem
158						   state. */
159};
160
161struct dns_acachestats {
162	unsigned int			hits;
163	unsigned int			queries;
164	unsigned int			misses;
165	unsigned int			adds;
166	unsigned int			deleted;
167	unsigned int			cleaned;
168	unsigned int			cleaner_runs;
169	unsigned int			overmem;
170	unsigned int			overmem_nocreates;
171	unsigned int			nomem;
172};
173
174/*
175 * The actual acache object.
176 */
177
178struct dns_acache {
179	unsigned int			magic;
180
181	isc_mem_t			*mctx;
182	isc_refcount_t			refs;
183
184#ifdef ACACHE_USE_RWLOCK
185	isc_rwlock_t 			*entrylocks;
186#else
187	isc_mutex_t 			*entrylocks;
188#endif
189
190	isc_mutex_t			lock;
191
192	int				live_cleaners;
193	acache_cleaner_t		cleaner;
194	ISC_LIST(dns_acacheentry_t)	entries;
195	unsigned int			dbentries;
196	dbentrylist_t			dbbucket[DBBUCKETS];
197
198	isc_boolean_t			shutting_down;
199
200	isc_task_t 			*task;
201	isc_event_t			cevent;
202	isc_boolean_t			cevent_sent;
203
204	dns_acachestats_t		stats;
205};
206
207struct dns_acacheentry {
208	unsigned int 		magic;
209
210	unsigned int		locknum;
211	isc_refcount_t 		references;
212
213	dns_acache_t 		*acache;
214
215	/* Data for Management of cache entries */
216	ISC_LINK(dns_acacheentry_t) link;
217	ISC_LINK(dns_acacheentry_t) olink;
218	ISC_LINK(dns_acacheentry_t) rlink;
219
220	dns_db_t 		*origdb; /* reference to the DB
221					    holding this entry */
222
223	/* Cache data */
224	dns_zone_t 		*zone;		/* zone this entry
225						   belongs to */
226	dns_db_t		*db;   		/* DB this entry belongs to */
227	dns_dbversion_t		*version;	/* the version of the DB */
228	dns_dbnode_t 		*node;		/* node this entry
229						   belongs to */
230	dns_name_t 		*foundname;	/* corresponding DNS name
231						   and rdataset */
232
233	/* Callback function and its argument */
234	void 			(*callback)(dns_acacheentry_t *, void **);
235	void 			*cbarg;
236
237	/* Timestamp of the last time this entry is referred to */
238	isc_stdtime32_t		lastused;
239};
240
241/*
242 *	Internal functions (and prototypes).
243 */
244static inline isc_boolean_t check_noentry(dns_acache_t *acache);
245static void destroy(dns_acache_t *acache);
246static void shutdown_entries(dns_acache_t *acache);
247static void shutdown_buckets(dns_acache_t *acache);
248static void destroy_entry(dns_acacheentry_t *ent);
249static inline void unlink_dbentries(dns_acache_t *acache,
250				    dns_acacheentry_t *ent);
251static inline isc_result_t finddbent(dns_acache_t *acache,
252				     dns_db_t *db, dbentry_t **dbentryp);
253static inline void clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry);
254static isc_result_t acache_cleaner_init(dns_acache_t *acache,
255					isc_timermgr_t *timermgr,
256					acache_cleaner_t *cleaner);
257static void acache_cleaning_timer_action(isc_task_t *task, isc_event_t *event);
258static void acache_incremental_cleaning_action(isc_task_t *task,
259					       isc_event_t *event);
260static void acache_overmem_cleaning_action(isc_task_t *task,
261					   isc_event_t *event);
262static void acache_cleaner_shutdown_action(isc_task_t *task,
263					   isc_event_t *event);
264
265/*
266 * acache should be locked.  If it is not, the stats can get out of whack,
267 * which is not a big deal for us since this is for debugging / stats
268 */
269static void
270reset_stats(dns_acache_t *acache) {
271	acache->stats.hits = 0;
272	acache->stats.queries = 0;
273	acache->stats.misses = 0;
274	acache->stats.adds = 0;
275	acache->stats.deleted = 0;
276	acache->stats.cleaned = 0;
277	acache->stats.overmem = 0;
278	acache->stats.overmem_nocreates = 0;
279	acache->stats.nomem = 0;
280}
281
282/*
283 * The acache must be locked before calling.
284 */
285static inline isc_boolean_t
286check_noentry(dns_acache_t *acache) {
287	if (ISC_LIST_EMPTY(acache->entries) && acache->dbentries == 0) {
288		return (ISC_TRUE);
289	}
290
291	return (ISC_FALSE);
292}
293
294/*
295 * The acache must be locked before calling.
296 */
297static void
298shutdown_entries(dns_acache_t *acache) {
299	dns_acacheentry_t *entry, *entry_next;
300
301	REQUIRE(DNS_ACACHE_VALID(acache));
302	INSIST(acache->shutting_down);
303
304	/*
305	 * Release the dependency of all entries, and detach them.
306	 */
307	for (entry = ISC_LIST_HEAD(acache->entries);
308	     entry != NULL;
309	     entry = entry_next) {
310		entry_next = ISC_LIST_NEXT(entry, link);
311
312		ACACHE_LOCK(&acache->entrylocks[entry->locknum],
313			    isc_rwlocktype_write);
314
315		/*
316		 * If the cleaner holds this entry, it will be unlinked and
317		 * freed in the cleaner later.
318		 */
319		if (acache->cleaner.current_entry != entry)
320			ISC_LIST_UNLINK(acache->entries, entry, link);
321		unlink_dbentries(acache, entry);
322		if (entry->callback != NULL) {
323			(entry->callback)(entry, &entry->cbarg);
324			entry->callback = NULL;
325		}
326
327		ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
328			      isc_rwlocktype_write);
329
330		if (acache->cleaner.current_entry != entry)
331			dns_acache_detachentry(&entry);
332	}
333}
334
335/*
336 * The acache must be locked before calling.
337 */
338static void
339shutdown_buckets(dns_acache_t *acache) {
340	int i;
341	dbentry_t *dbent;
342
343	REQUIRE(DNS_ACACHE_VALID(acache));
344	INSIST(acache->shutting_down);
345
346	for (i = 0; i < DBBUCKETS; i++) {
347		while ((dbent = ISC_LIST_HEAD(acache->dbbucket[i])) != NULL) {
348			INSIST(ISC_LIST_EMPTY(dbent->originlist) &&
349			       ISC_LIST_EMPTY(dbent->referlist));
350			ISC_LIST_UNLINK(acache->dbbucket[i], dbent, link);
351
352			dns_db_detach(&dbent->db);
353
354			isc_mem_put(acache->mctx, dbent, sizeof(*dbent));
355
356			acache->dbentries--;
357		}
358	}
359
360	INSIST(acache->dbentries == 0);
361}
362
363static void
364shutdown_task(isc_task_t *task, isc_event_t *ev) {
365	dns_acache_t *acache;
366
367	UNUSED(task);
368
369	acache = ev->ev_arg;
370	INSIST(DNS_ACACHE_VALID(acache));
371
372	isc_event_free(&ev);
373
374	LOCK(&acache->lock);
375
376	shutdown_entries(acache);
377	shutdown_buckets(acache);
378
379	UNLOCK(&acache->lock);
380
381	dns_acache_detach(&acache);
382}
383
384/* The acache and the entry must be locked before calling. */
385static inline void
386unlink_dbentries(dns_acache_t *acache, dns_acacheentry_t *ent) {
387	isc_result_t result;
388	dbentry_t *dbent;
389
390	if (ISC_LINK_LINKED(ent, olink)) {
391		INSIST(ent->origdb != NULL);
392		dbent = NULL;
393		result = finddbent(acache, ent->origdb, &dbent);
394		INSIST(result == ISC_R_SUCCESS);
395
396		ISC_LIST_UNLINK(dbent->originlist, ent, olink);
397	}
398	if (ISC_LINK_LINKED(ent, rlink)) {
399		INSIST(ent->db != NULL);
400		dbent = NULL;
401		result = finddbent(acache, ent->db, &dbent);
402		INSIST(result == ISC_R_SUCCESS);
403
404		ISC_LIST_UNLINK(dbent->referlist, ent, rlink);
405	}
406}
407
408/* There must not be a reference to this entry. */
409static void
410destroy_entry(dns_acacheentry_t *entry) {
411	dns_acache_t *acache;
412
413	REQUIRE(DNS_ACACHEENTRY_VALID(entry));
414
415	acache = entry->acache;
416	REQUIRE(DNS_ACACHE_VALID(acache));
417
418	/*
419	 * Since there is no reference to this entry, it is safe to call
420	 * clear_entry() here.
421	 */
422	clear_entry(acache, entry);
423
424	isc_mem_put(acache->mctx, entry, sizeof(*entry));
425
426	dns_acache_detach(&acache);
427}
428
429static void
430destroy(dns_acache_t *acache) {
431	int i;
432
433	REQUIRE(DNS_ACACHE_VALID(acache));
434
435	ATRACE("destroy");
436
437	isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0);
438
439	if (acache->cleaner.overmem_event != NULL)
440		isc_event_free(&acache->cleaner.overmem_event);
441
442	if (acache->cleaner.resched_event != NULL)
443		isc_event_free(&acache->cleaner.resched_event);
444
445	if (acache->task != NULL)
446		isc_task_detach(&acache->task);
447
448	for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
449		ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
450	isc_mem_put(acache->mctx, acache->entrylocks,
451		    sizeof(*acache->entrylocks) *
452		    DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
453
454	DESTROYLOCK(&acache->cleaner.lock);
455
456	DESTROYLOCK(&acache->lock);
457	acache->magic = 0;
458
459	isc_mem_putanddetach(&acache->mctx, acache, sizeof(*acache));
460}
461
462static inline isc_result_t
463finddbent(dns_acache_t *acache, dns_db_t *db, dbentry_t **dbentryp) {
464	int bucket;
465	dbentry_t *dbentry;
466
467	REQUIRE(DNS_ACACHE_VALID(acache));
468	REQUIRE(db != NULL);
469	REQUIRE(dbentryp != NULL && *dbentryp == NULL);
470
471	/*
472	 * The caller must be holding the acache lock.
473	 */
474
475	bucket = isc_hash_calc((const unsigned char *)&db,
476			       sizeof(db), ISC_TRUE) % DBBUCKETS;
477
478	for (dbentry = ISC_LIST_HEAD(acache->dbbucket[bucket]);
479	     dbentry != NULL;
480	     dbentry = ISC_LIST_NEXT(dbentry, link)) {
481		if (dbentry->db == db)
482			break;
483	}
484
485	*dbentryp = dbentry;
486
487	if (dbentry == NULL)
488		return (ISC_R_NOTFOUND);
489	else
490		return (ISC_R_SUCCESS);
491}
492
493static inline void
494clear_entry(dns_acache_t *acache, dns_acacheentry_t *entry) {
495	REQUIRE(DNS_ACACHE_VALID(acache));
496	REQUIRE(DNS_ACACHEENTRY_VALID(entry));
497
498	/*
499	 * The caller must be holing the entry lock.
500	 */
501
502	if (entry->foundname) {
503		dns_rdataset_t *rdataset, *rdataset_next;
504
505		for (rdataset = ISC_LIST_HEAD(entry->foundname->list);
506		     rdataset != NULL;
507		     rdataset = rdataset_next) {
508			rdataset_next = ISC_LIST_NEXT(rdataset, link);
509			ISC_LIST_UNLINK(entry->foundname->list,
510					rdataset, link);
511			dns_rdataset_disassociate(rdataset);
512			isc_mem_put(acache->mctx, rdataset, sizeof(*rdataset));
513		}
514		if (dns_name_dynamic(entry->foundname))
515			dns_name_free(entry->foundname, acache->mctx);
516		isc_mem_put(acache->mctx, entry->foundname,
517			    sizeof(*entry->foundname));
518		entry->foundname = NULL;
519	}
520
521	if (entry->node != NULL) {
522		INSIST(entry->db != NULL);
523		dns_db_detachnode(entry->db, &entry->node);
524	}
525	if (entry->version != NULL) {
526		INSIST(entry->db != NULL);
527		dns_db_closeversion(entry->db, &entry->version, ISC_FALSE);
528	}
529	if (entry->db != NULL)
530		dns_db_detach(&entry->db);
531	if (entry->zone != NULL)
532		dns_zone_detach(&entry->zone);
533
534	if (entry->origdb != NULL)
535		dns_db_detach(&entry->origdb);
536}
537
538static isc_result_t
539acache_cleaner_init(dns_acache_t *acache, isc_timermgr_t *timermgr,
540		    acache_cleaner_t *cleaner)
541{
542	int result;
543
544	ATRACE("acache cleaner init");
545
546	result = isc_mutex_init(&cleaner->lock);
547	if (result != ISC_R_SUCCESS)
548		goto fail;
549
550	cleaner->increment = DNS_ACACHE_CLEANERINCREMENT;
551	cleaner->state = cleaner_s_idle;
552	cleaner->acache = acache;
553	cleaner->overmem = ISC_FALSE;
554
555	cleaner->cleaning_timer = NULL;
556	cleaner->resched_event = NULL;
557	cleaner->overmem_event = NULL;
558	cleaner->current_entry = NULL;
559
560	if (timermgr != NULL) {
561		cleaner->acache->live_cleaners++;
562
563		result = isc_task_onshutdown(acache->task,
564					     acache_cleaner_shutdown_action,
565					     acache);
566		if (result != ISC_R_SUCCESS) {
567			UNEXPECTED_ERROR(__FILE__, __LINE__,
568					 "acache cleaner: "
569					 "isc_task_onshutdown() failed: %s",
570					 dns_result_totext(result));
571			goto cleanup;
572		}
573
574		cleaner->cleaning_interval = 0; /* Initially turned off. */
575		isc_stdtime_get(&cleaner->last_cleanup_time);
576		result = isc_timer_create(timermgr, isc_timertype_inactive,
577					  NULL, NULL,
578					  acache->task,
579					  acache_cleaning_timer_action,
580					  cleaner, &cleaner->cleaning_timer);
581		if (result != ISC_R_SUCCESS) {
582			UNEXPECTED_ERROR(__FILE__, __LINE__,
583					 "isc_timer_create() failed: %s",
584					 dns_result_totext(result));
585			result = ISC_R_UNEXPECTED;
586			goto cleanup;
587		}
588
589		cleaner->resched_event =
590			isc_event_allocate(acache->mctx, cleaner,
591					   DNS_EVENT_ACACHECLEAN,
592					   acache_incremental_cleaning_action,
593					   cleaner, sizeof(isc_event_t));
594		if (cleaner->resched_event == NULL) {
595			result = ISC_R_NOMEMORY;
596			goto cleanup;
597		}
598
599		cleaner->overmem_event =
600			isc_event_allocate(acache->mctx, cleaner,
601					   DNS_EVENT_ACACHEOVERMEM,
602					   acache_overmem_cleaning_action,
603					   cleaner, sizeof(isc_event_t));
604		if (cleaner->overmem_event == NULL) {
605			result = ISC_R_NOMEMORY;
606			goto cleanup;
607		}
608	}
609
610	return (ISC_R_SUCCESS);
611
612 cleanup:
613	if (cleaner->overmem_event != NULL)
614		isc_event_free(&cleaner->overmem_event);
615	if (cleaner->resched_event != NULL)
616		isc_event_free(&cleaner->resched_event);
617	if (cleaner->cleaning_timer != NULL)
618		isc_timer_detach(&cleaner->cleaning_timer);
619	cleaner->acache->live_cleaners--;
620	DESTROYLOCK(&cleaner->lock);
621 fail:
622	return (result);
623}
624
625static void
626begin_cleaning(acache_cleaner_t *cleaner) {
627	dns_acacheentry_t *head;
628	dns_acache_t *acache = cleaner->acache;
629
630	/*
631	 * This function does not have to lock the cleaner, since critical
632	 * parameters (except current_entry, which is locked by acache lock,)
633	 * are only used in a single task context.
634	 */
635
636	REQUIRE(CLEANER_IDLE(cleaner));
637	INSIST(DNS_ACACHE_VALID(acache));
638	INSIST(cleaner->current_entry == NULL);
639
640	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
641		      DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1),
642		      "begin acache cleaning, mem inuse %lu",
643		      (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
644
645	LOCK(&acache->lock);
646
647	head = ISC_LIST_HEAD(acache->entries);
648	if (head != NULL)
649		dns_acache_attachentry(head, &cleaner->current_entry);
650
651	UNLOCK(&acache->lock);
652
653	if (cleaner->current_entry != NULL) {
654		cleaner->ncleaned = 0;
655		cleaner->state = cleaner_s_busy;
656		isc_task_send(acache->task, &cleaner->resched_event);
657	}
658
659	return;
660}
661
662static void
663end_cleaning(acache_cleaner_t *cleaner, isc_event_t *event) {
664	dns_acache_t *acache = cleaner->acache;
665
666	REQUIRE(CLEANER_BUSY(cleaner));
667	REQUIRE(event != NULL);
668	REQUIRE(DNS_ACACHEENTRY_VALID(cleaner->current_entry));
669
670	/* No need to lock the cleaner (see begin_cleaning()). */
671
672	LOCK(&acache->lock);
673
674	/*
675	 * Even if the cleaner has the last reference to the entry, which means
676	 * the entry has been unused, it may still be linked if unlinking the
677	 * entry has been delayed due to the reference.
678	 */
679	if (isc_refcount_current(&cleaner->current_entry->references) == 1) {
680		INSIST(cleaner->current_entry->callback == NULL);
681
682		if (ISC_LINK_LINKED(cleaner->current_entry, link)) {
683			ISC_LIST_UNLINK(acache->entries,
684					cleaner->current_entry, link);
685		}
686	}
687	dns_acache_detachentry(&cleaner->current_entry);
688
689	if (cleaner->overmem)
690		acache->stats.overmem++;
691	acache->stats.cleaned += cleaner->ncleaned;
692	acache->stats.cleaner_runs++;
693
694	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
695		      ISC_LOG_NOTICE,
696		      "acache %p stats: hits=%d misses=%d queries=%d "
697		      "adds=%d deleted=%d "
698		      "cleaned=%d cleaner_runs=%d overmem=%d "
699		      "overmem_nocreates=%d nomem=%d",
700		      acache,
701		      acache->stats.hits, acache->stats.misses,
702		      acache->stats.queries,
703		      acache->stats.adds, acache->stats.deleted,
704		      acache->stats.cleaned, acache->stats.cleaner_runs,
705		      acache->stats.overmem, acache->stats.overmem_nocreates,
706		      acache->stats.nomem);
707	reset_stats(acache);
708
709	isc_stdtime_get(&cleaner->last_cleanup_time);
710
711	UNLOCK(&acache->lock);
712
713	dns_acache_setcleaninginterval(cleaner->acache,
714				       cleaner->cleaning_interval);
715
716	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
717		      ISC_LOG_DEBUG(1), "end acache cleaning, "
718		      "%lu entries cleaned, mem inuse %lu",
719		      cleaner->ncleaned,
720		      (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
721
722	if (cleaner->overmem) {
723		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
724			      DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
725			      "acache is still in overmem state "
726			      "after cleaning");
727	}
728
729	cleaner->ncleaned = 0;
730	cleaner->state = cleaner_s_idle;
731	cleaner->resched_event = event;
732}
733
734/*
735 * This is run once for every acache-cleaning-interval as defined
736 * in named.conf.
737 */
738static void
739acache_cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
740	acache_cleaner_t *cleaner = event->ev_arg;
741
742	UNUSED(task);
743
744	INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
745
746	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
747		      ISC_LOG_DEBUG(1), "acache cleaning timer fired, "
748		      "cleaner state = %d", cleaner->state);
749
750	if (cleaner->state == cleaner_s_idle)
751		begin_cleaning(cleaner);
752
753	isc_event_free(&event);
754}
755
756/* The caller must hold entry lock. */
757static inline isc_boolean_t
758entry_stale(acache_cleaner_t *cleaner, dns_acacheentry_t *entry,
759	    isc_stdtime32_t now32, unsigned int interval)
760{
761	/*
762	 * If the callback has been canceled, we definitely do not need the
763	 * entry.
764	 */
765	if (entry->callback == NULL)
766		return (ISC_TRUE);
767
768	if (interval > cleaner->cleaning_interval)
769		interval = cleaner->cleaning_interval;
770
771	if (entry->lastused + interval < now32)
772		return (ISC_TRUE);
773
774	/*
775	 * If the acache is in the overmem state, probabilistically decide if
776	 * the entry should be purged, based on the time passed from its last
777	 * use and the cleaning interval.
778	 */
779	if (cleaner->overmem) {
780		unsigned int passed;
781		isc_uint32_t val;
782
783		if (isc_serial_ge(now32, entry->lastused))
784			passed = now32 - entry->lastused; /* <= interval */
785		else
786			passed = 0;
787
788		if (passed > interval / 2)
789			return (ISC_TRUE);
790		isc_random_get(&val);
791		if (passed > interval / 4)
792			return (ISC_TF(val % 4 == 0));
793		return (ISC_TF(val % 8 == 0));
794	}
795
796	return (ISC_FALSE);
797}
798
799/*
800 * Do incremental cleaning.
801 */
802static void
803acache_incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
804	acache_cleaner_t *cleaner = event->ev_arg;
805	dns_acache_t *acache = cleaner->acache;
806	dns_acacheentry_t *entry, *next = NULL;
807	int n_entries;
808	isc_stdtime32_t now32, last32;
809	isc_stdtime_t now;
810	unsigned int interval;
811
812	INSIST(DNS_ACACHE_VALID(acache));
813	INSIST(task == acache->task);
814	INSIST(event->ev_type == DNS_EVENT_ACACHECLEAN);
815
816	if (cleaner->state == cleaner_s_done) {
817		cleaner->state = cleaner_s_busy;
818		end_cleaning(cleaner, event);
819		return;
820	}
821
822	INSIST(CLEANER_BUSY(cleaner));
823
824	n_entries = cleaner->increment;
825
826	isc_stdtime_get(&now);
827	isc_stdtime_convert32(now, &now32);
828
829	LOCK(&acache->lock);
830
831	entry = cleaner->current_entry;
832	isc_stdtime_convert32(cleaner->last_cleanup_time, &last32);
833	if (isc_serial_ge(now32, last32))
834		interval = now32 - last32;
835	else
836		interval = 0;
837
838	while (n_entries-- > 0) {
839		isc_boolean_t is_stale = ISC_FALSE;
840
841		INSIST(entry != NULL);
842
843		next = ISC_LIST_NEXT(entry, link);
844
845		ACACHE_LOCK(&acache->entrylocks[entry->locknum],
846			    isc_rwlocktype_write);
847
848		is_stale = entry_stale(cleaner, entry, now32, interval);
849		if (is_stale) {
850			ISC_LIST_UNLINK(acache->entries, entry, link);
851			unlink_dbentries(acache, entry);
852			if (entry->callback != NULL)
853				(entry->callback)(entry, &entry->cbarg);
854			entry->callback = NULL;
855
856			cleaner->ncleaned++;
857		}
858
859		ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
860			      isc_rwlocktype_write);
861
862		if (is_stale)
863			dns_acache_detachentry(&entry);
864
865		if (next == NULL) {
866			if (cleaner->overmem) {
867				entry = ISC_LIST_HEAD(acache->entries);
868				if (entry != NULL) {
869					/*
870					 * If we are still in the overmem
871					 * state, keep cleaning.  In case we
872					 * exit from the loop immediately after
873					 * this, reset next to the head entry
874					 * as we'll expect it will be never
875					 * NULL.
876					 */
877					isc_log_write(dns_lctx,
878						      DNS_LOGCATEGORY_DATABASE,
879						      DNS_LOGMODULE_ACACHE,
880						      ISC_LOG_DEBUG(1),
881						      "acache cleaner: "
882						      "still overmem, "
883						      "reset and try again");
884					next = entry;
885					continue;
886				}
887			}
888
889			UNLOCK(&acache->lock);
890			end_cleaning(cleaner, event);
891			return;
892		}
893
894		entry = next;
895	}
896
897	/*
898	 * We have successfully performed a cleaning increment but have
899	 * not gone through the entire cache.  Remember the entry that will
900	 * be the starting point in the next clean-up, and reschedule another
901	 * batch.  If it fails, just try to continue anyway.
902	 */
903	INSIST(next != NULL);
904	dns_acache_detachentry(&cleaner->current_entry);
905	dns_acache_attachentry(next, &cleaner->current_entry);
906
907	UNLOCK(&acache->lock);
908
909	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
910		      ISC_LOG_DEBUG(1), "acache cleaner: checked %d entries, "
911		      "mem inuse %lu, sleeping", cleaner->increment,
912		      (unsigned long)isc_mem_inuse(cleaner->acache->mctx));
913
914	isc_task_send(task, &event);
915	INSIST(CLEANER_BUSY(cleaner));
916
917	return;
918}
919
920/*
921 * This is called when the acache either surpasses its upper limit
922 * or shrinks beyond its lower limit.
923 */
924static void
925acache_overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
926	acache_cleaner_t *cleaner = event->ev_arg;
927	isc_boolean_t want_cleaning = ISC_FALSE;
928
929	UNUSED(task);
930
931	INSIST(event->ev_type == DNS_EVENT_ACACHEOVERMEM);
932	INSIST(cleaner->overmem_event == NULL);
933
934	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE,
935		      ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
936		      "overmem = %d, state = %d", cleaner->overmem,
937		      cleaner->state);
938
939	LOCK(&cleaner->lock);
940
941	if (cleaner->overmem) {
942		if (cleaner->state == cleaner_s_idle)
943			want_cleaning = ISC_TRUE;
944	} else {
945		if (cleaner->state == cleaner_s_busy)
946			/*
947			 * end_cleaning() can't be called here because
948			 * then both cleaner->overmem_event and
949			 * cleaner->resched_event will point to this
950			 * event.  Set the state to done, and then
951			 * when the acache_incremental_cleaning_action() event
952			 * is posted, it will handle the end_cleaning.
953			 */
954			cleaner->state = cleaner_s_done;
955	}
956
957	cleaner->overmem_event = event;
958
959	UNLOCK(&cleaner->lock);
960
961	if (want_cleaning)
962		begin_cleaning(cleaner);
963}
964
965static void
966water(void *arg, int mark) {
967	dns_acache_t *acache = arg;
968	isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
969
970	REQUIRE(DNS_ACACHE_VALID(acache));
971
972	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
973		      DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1),
974		      "acache memory reaches %s watermark, mem inuse %lu",
975		      overmem ? "high" : "low",
976		      (unsigned long)isc_mem_inuse(acache->mctx));
977
978	LOCK(&acache->cleaner.lock);
979
980	if (acache->cleaner.overmem != overmem) {
981		acache->cleaner.overmem = overmem;
982
983		if (acache->cleaner.overmem_event != NULL)
984			isc_task_send(acache->task,
985				      &acache->cleaner.overmem_event);
986		isc_mem_waterack(acache->mctx, mark);
987	}
988
989	UNLOCK(&acache->cleaner.lock);
990}
991
992/*
993 * The cleaner task is shutting down; do the necessary cleanup.
994 */
995static void
996acache_cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
997	dns_acache_t *acache = event->ev_arg;
998	isc_boolean_t should_free = ISC_FALSE;
999
1000	INSIST(task == acache->task);
1001	INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
1002	INSIST(DNS_ACACHE_VALID(acache));
1003
1004	ATRACE("acache cleaner shutdown");
1005
1006	if (CLEANER_BUSY(&acache->cleaner))
1007		end_cleaning(&acache->cleaner, event);
1008	else
1009		isc_event_free(&event);
1010
1011	LOCK(&acache->lock);
1012
1013	acache->live_cleaners--;
1014	INSIST(acache->live_cleaners == 0);
1015
1016	if (isc_refcount_current(&acache->refs) == 0) {
1017		INSIST(check_noentry(acache) == ISC_TRUE);
1018		should_free = ISC_TRUE;
1019	}
1020
1021	/*
1022	 * By detaching the timer in the context of its task,
1023	 * we are guaranteed that there will be no further timer
1024	 * events.
1025	 */
1026	if (acache->cleaner.cleaning_timer != NULL)
1027		isc_timer_detach(&acache->cleaner.cleaning_timer);
1028
1029	/* Make sure we don't reschedule anymore. */
1030	(void)isc_task_purge(task, NULL, DNS_EVENT_ACACHECLEAN, NULL);
1031
1032	UNLOCK(&acache->lock);
1033
1034	if (should_free)
1035		destroy(acache);
1036}
1037
1038/*
1039 *	Public functions.
1040 */
1041
1042isc_result_t
1043dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
1044		  isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr)
1045{
1046	int i;
1047	isc_result_t result;
1048	dns_acache_t *acache;
1049
1050	REQUIRE(acachep != NULL && *acachep == NULL);
1051	REQUIRE(mctx != NULL);
1052	REQUIRE(taskmgr != NULL);
1053
1054	acache = isc_mem_get(mctx, sizeof(*acache));
1055	if (acache == NULL)
1056		return (ISC_R_NOMEMORY);
1057
1058	ATRACE("create");
1059
1060	result = isc_refcount_init(&acache->refs, 1);
1061	if (result != ISC_R_SUCCESS) {
1062		isc_mem_put(mctx, acache, sizeof(*acache));
1063		return (result);
1064	}
1065
1066	result = isc_mutex_init(&acache->lock);
1067	if (result != ISC_R_SUCCESS) {
1068		isc_refcount_decrement(&acache->refs, NULL);
1069		isc_refcount_destroy(&acache->refs);
1070		isc_mem_put(mctx, acache, sizeof(*acache));
1071		return (result);
1072	}
1073
1074	acache->mctx = NULL;
1075	isc_mem_attach(mctx, &acache->mctx);
1076	ISC_LIST_INIT(acache->entries);
1077
1078	acache->shutting_down = ISC_FALSE;
1079
1080	acache->task = NULL;
1081	acache->entrylocks = NULL;
1082
1083	result = isc_task_create(taskmgr, 1, &acache->task);
1084	if (result != ISC_R_SUCCESS) {
1085		UNEXPECTED_ERROR(__FILE__, __LINE__,
1086				 "isc_task_create() failed(): %s",
1087				 dns_result_totext(result));
1088		result = ISC_R_UNEXPECTED;
1089		goto cleanup;
1090	}
1091	isc_task_setname(acache->task, "acachetask", acache);
1092	ISC_EVENT_INIT(&acache->cevent, sizeof(acache->cevent), 0, NULL,
1093		       DNS_EVENT_ACACHECONTROL, shutdown_task, NULL,
1094		       NULL, NULL, NULL);
1095	acache->cevent_sent = ISC_FALSE;
1096
1097	acache->dbentries = 0;
1098	for (i = 0; i < DBBUCKETS; i++)
1099		ISC_LIST_INIT(acache->dbbucket[i]);
1100
1101	acache->entrylocks = isc_mem_get(mctx, sizeof(*acache->entrylocks) *
1102					 DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
1103	if (acache->entrylocks == NULL) {
1104		result = ISC_R_NOMEMORY;
1105		goto cleanup;
1106	}
1107	for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) {
1108		result = ACACHE_INITLOCK(&acache->entrylocks[i]);
1109		if (result != ISC_R_SUCCESS) {
1110			while (i-- > 0)
1111				ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
1112			isc_mem_put(mctx, acache->entrylocks,
1113				    sizeof(*acache->entrylocks) *
1114				    DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
1115			acache->entrylocks = NULL;
1116			goto cleanup;
1117		}
1118	}
1119
1120	acache->live_cleaners = 0;
1121	result = acache_cleaner_init(acache, timermgr, &acache->cleaner);
1122	if (result != ISC_R_SUCCESS)
1123		goto cleanup;
1124
1125	acache->stats.cleaner_runs = 0;
1126	reset_stats(acache);
1127
1128	acache->magic = ACACHE_MAGIC;
1129
1130	*acachep = acache;
1131	return (ISC_R_SUCCESS);
1132
1133 cleanup:
1134	if (acache->task != NULL)
1135		isc_task_detach(&acache->task);
1136	DESTROYLOCK(&acache->lock);
1137	isc_refcount_decrement(&acache->refs, NULL);
1138	isc_refcount_destroy(&acache->refs);
1139	if (acache->entrylocks != NULL) {
1140		for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
1141			ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
1142		isc_mem_put(mctx, acache->entrylocks,
1143			    sizeof(*acache->entrylocks) *
1144			    DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
1145	}
1146	isc_mem_put(mctx, acache, sizeof(*acache));
1147	isc_mem_detach(&mctx);
1148
1149	return (result);
1150}
1151
1152void
1153dns_acache_attach(dns_acache_t *source, dns_acache_t **targetp) {
1154	REQUIRE(DNS_ACACHE_VALID(source));
1155	REQUIRE(targetp != NULL && *targetp == NULL);
1156
1157	AATRACE(source, "attach");
1158
1159	isc_refcount_increment(&source->refs, NULL);
1160
1161	*targetp = source;
1162}
1163
1164void
1165dns_acache_countquerymiss(dns_acache_t *acache) {
1166	acache->stats.misses++; 	/* XXXSK danger: unlocked! */
1167	acache->stats.queries++;	/* XXXSK danger: unlocked! */
1168}
1169
1170void
1171dns_acache_detach(dns_acache_t **acachep) {
1172	dns_acache_t *acache;
1173	unsigned int refs;
1174	isc_boolean_t should_free = ISC_FALSE;
1175
1176	REQUIRE(acachep != NULL && DNS_ACACHE_VALID(*acachep));
1177	acache = *acachep;
1178
1179	ATRACE("detach");
1180
1181	isc_refcount_decrement(&acache->refs, &refs);
1182	if (refs == 0) {
1183		INSIST(check_noentry(acache) == ISC_TRUE);
1184		should_free = ISC_TRUE;
1185	}
1186
1187	*acachep = NULL;
1188
1189	/*
1190	 * If we're exiting and the cleaner task exists, let it free the cache.
1191	 */
1192	if (should_free && acache->live_cleaners > 0) {
1193		isc_task_shutdown(acache->task);
1194		should_free = ISC_FALSE;
1195	}
1196
1197	if (should_free)
1198		destroy(acache);
1199}
1200
1201void
1202dns_acache_shutdown(dns_acache_t *acache) {
1203	REQUIRE(DNS_ACACHE_VALID(acache));
1204
1205	LOCK(&acache->lock);
1206
1207	ATRACE("shutdown");
1208
1209	if (!acache->shutting_down) {
1210		isc_event_t *event;
1211		dns_acache_t *acache_evarg = NULL;
1212
1213		INSIST(!acache->cevent_sent);
1214
1215		acache->shutting_down = ISC_TRUE;
1216
1217		isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0);
1218
1219		/*
1220		 * Self attach the object in order to prevent it from being
1221		 * destroyed while waiting for the event.
1222		 */
1223		dns_acache_attach(acache, &acache_evarg);
1224		event = &acache->cevent;
1225		event->ev_arg = acache_evarg;
1226		isc_task_send(acache->task, &event);
1227		acache->cevent_sent = ISC_TRUE;
1228	}
1229
1230	UNLOCK(&acache->lock);
1231}
1232
1233isc_result_t
1234dns_acache_setdb(dns_acache_t *acache, dns_db_t *db) {
1235	int bucket;
1236	dbentry_t *dbentry;
1237	isc_result_t result = ISC_R_SUCCESS;
1238
1239	REQUIRE(DNS_ACACHE_VALID(acache));
1240	REQUIRE(db != NULL);
1241
1242	ATRACE("setdb");
1243
1244	LOCK(&acache->lock);
1245
1246	dbentry = NULL;
1247	result = finddbent(acache, db, &dbentry);
1248	if (result == ISC_R_SUCCESS) {
1249		result = ISC_R_EXISTS;
1250		goto end;
1251	}
1252	result = ISC_R_SUCCESS;
1253
1254	dbentry = isc_mem_get(acache->mctx, sizeof(*dbentry));
1255	if (dbentry == NULL) {
1256		result = ISC_R_NOMEMORY;
1257		goto end;
1258	}
1259
1260	ISC_LINK_INIT(dbentry, link);
1261	ISC_LIST_INIT(dbentry->originlist);
1262	ISC_LIST_INIT(dbentry->referlist);
1263
1264	dbentry->db = NULL;
1265	dns_db_attach(db, &dbentry->db);
1266
1267	bucket = isc_hash_calc((const unsigned char *)&db,
1268			       sizeof(db), ISC_TRUE) % DBBUCKETS;
1269
1270	ISC_LIST_APPEND(acache->dbbucket[bucket], dbentry, link);
1271
1272	acache->dbentries++;
1273
1274 end:
1275	UNLOCK(&acache->lock);
1276
1277	return (result);
1278}
1279
1280isc_result_t
1281dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) {
1282	int bucket;
1283	isc_result_t result;
1284	dbentry_t *dbentry;
1285	dns_acacheentry_t *entry;
1286
1287	REQUIRE(DNS_ACACHE_VALID(acache));
1288	REQUIRE(db != NULL);
1289
1290	ATRACE("putdb");
1291
1292	LOCK(&acache->lock);
1293
1294	dbentry = NULL;
1295	result = finddbent(acache, db, &dbentry);
1296	if (result != ISC_R_SUCCESS) {
1297		/*
1298		 * The entry may have not been created due to memory shortage.
1299		 */
1300		UNLOCK(&acache->lock);
1301		return (ISC_R_NOTFOUND);
1302	}
1303
1304	/*
1305	 * Release corresponding cache entries: for each entry, release all
1306	 * links the entry has, and then callback to the entry holder (if any).
1307	 * If no other external references exist (this can happen if the
1308	 * original holder has canceled callback,) destroy it here.
1309	 */
1310	while ((entry = ISC_LIST_HEAD(dbentry->originlist)) != NULL) {
1311		ACACHE_LOCK(&acache->entrylocks[entry->locknum],
1312			    isc_rwlocktype_write);
1313
1314		/*
1315		 * Releasing olink first would avoid finddbent() in
1316		 * unlink_dbentries().
1317		 */
1318		ISC_LIST_UNLINK(dbentry->originlist, entry, olink);
1319		if (acache->cleaner.current_entry != entry)
1320			ISC_LIST_UNLINK(acache->entries, entry, link);
1321		unlink_dbentries(acache, entry);
1322
1323		if (entry->callback != NULL)
1324			(entry->callback)(entry, &entry->cbarg);
1325		entry->callback = NULL;
1326
1327		ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
1328			      isc_rwlocktype_write);
1329
1330		if (acache->cleaner.current_entry != entry)
1331			dns_acache_detachentry(&entry);
1332	}
1333	while ((entry = ISC_LIST_HEAD(dbentry->referlist)) != NULL) {
1334		ACACHE_LOCK(&acache->entrylocks[entry->locknum],
1335			    isc_rwlocktype_write);
1336
1337		ISC_LIST_UNLINK(dbentry->referlist, entry, rlink);
1338		if (acache->cleaner.current_entry != entry)
1339			ISC_LIST_UNLINK(acache->entries, entry, link);
1340		unlink_dbentries(acache, entry);
1341
1342		if (entry->callback != NULL)
1343			(entry->callback)(entry, &entry->cbarg);
1344		entry->callback = NULL;
1345
1346		ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
1347			      isc_rwlocktype_write);
1348
1349		if (acache->cleaner.current_entry != entry)
1350			dns_acache_detachentry(&entry);
1351	}
1352
1353	INSIST(ISC_LIST_EMPTY(dbentry->originlist) &&
1354	       ISC_LIST_EMPTY(dbentry->referlist));
1355
1356	bucket = isc_hash_calc((const unsigned char *)&db,
1357			       sizeof(db), ISC_TRUE) % DBBUCKETS;
1358	ISC_LIST_UNLINK(acache->dbbucket[bucket], dbentry, link);
1359	dns_db_detach(&dbentry->db);
1360
1361	isc_mem_put(acache->mctx, dbentry, sizeof(*dbentry));
1362
1363	acache->dbentries--;
1364
1365	acache->stats.deleted++;
1366
1367	UNLOCK(&acache->lock);
1368
1369	return (ISC_R_SUCCESS);
1370}
1371
1372isc_result_t
1373dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
1374		       void (*callback)(dns_acacheentry_t *, void **),
1375		       void *cbarg, dns_acacheentry_t **entryp)
1376{
1377	dns_acacheentry_t *newentry;
1378	isc_result_t result;
1379	isc_uint32_t r;
1380
1381	REQUIRE(DNS_ACACHE_VALID(acache));
1382	REQUIRE(entryp != NULL && *entryp == NULL);
1383	REQUIRE(origdb != NULL);
1384
1385	/*
1386	 * Should we exceed our memory limit for some reason (for
1387	 * example, if the cleaner does not run aggressively enough),
1388	 * then we will not create additional entries.
1389	 *
1390	 * XXXSK: It might be better to lock the acache->cleaner->lock,
1391	 * but locking may be an expensive bottleneck. If we misread
1392	 * the value, we will occasionally refuse to create a few
1393	 * cache entries, or create a few that we should not. I do not
1394	 * expect this to happen often, and it will not have very bad
1395	 * effects when it does. So no lock for now.
1396	 */
1397	if (acache->cleaner.overmem) {
1398		acache->stats.overmem_nocreates++; /* XXXSK danger: unlocked! */
1399		return (ISC_R_NORESOURCES);
1400	}
1401
1402	newentry = isc_mem_get(acache->mctx, sizeof(*newentry));
1403	if (newentry == NULL) {
1404		acache->stats.nomem++;  /* XXXMLG danger: unlocked! */
1405		return (ISC_R_NOMEMORY);
1406	}
1407
1408	isc_random_get(&r);
1409	newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT;
1410
1411	result = isc_refcount_init(&newentry->references, 1);
1412	if (result != ISC_R_SUCCESS) {
1413		isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
1414		return (result);
1415	};
1416
1417	ISC_LINK_INIT(newentry, link);
1418	ISC_LINK_INIT(newentry, olink);
1419	ISC_LINK_INIT(newentry, rlink);
1420
1421	newentry->acache = NULL;
1422	dns_acache_attach(acache, &newentry->acache);
1423
1424	newentry->zone = NULL;
1425	newentry->db = NULL;
1426	newentry->version = NULL;
1427	newentry->node = NULL;
1428	newentry->foundname = NULL;
1429
1430	newentry->callback = callback;
1431	newentry->cbarg = cbarg;
1432	newentry->origdb = NULL;
1433	dns_db_attach(origdb, &newentry->origdb);
1434
1435	isc_stdtime_get(&newentry->lastused);
1436
1437	newentry->magic = ACACHEENTRY_MAGIC;
1438
1439	*entryp = newentry;
1440
1441	return (ISC_R_SUCCESS);
1442}
1443
1444isc_result_t
1445dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
1446		    dns_db_t **dbp, dns_dbversion_t **versionp,
1447		    dns_dbnode_t **nodep, dns_name_t *fname,
1448		    dns_message_t *msg, isc_stdtime_t now)
1449{
1450	isc_result_t result = ISC_R_SUCCESS;
1451	dns_rdataset_t *erdataset;
1452	isc_stdtime32_t	now32;
1453	dns_acache_t *acache;
1454	int locknum;
1455
1456	REQUIRE(DNS_ACACHEENTRY_VALID(entry));
1457	REQUIRE(zonep == NULL || *zonep == NULL);
1458	REQUIRE(dbp != NULL && *dbp == NULL);
1459	REQUIRE(versionp != NULL && *versionp == NULL);
1460	REQUIRE(nodep != NULL && *nodep == NULL);
1461	REQUIRE(fname != NULL);
1462	REQUIRE(msg != NULL);
1463	acache = entry->acache;
1464	REQUIRE(DNS_ACACHE_VALID(acache));
1465
1466	locknum = entry->locknum;
1467	ACACHE_LOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
1468
1469	isc_stdtime_convert32(now, &now32);
1470	acache_storetime(entry, now32);
1471
1472	if (entry->zone != NULL && zonep != NULL)
1473		dns_zone_attach(entry->zone, zonep);
1474
1475	if (entry->db == NULL) {
1476		*dbp = NULL;
1477		*versionp = NULL;
1478	} else {
1479		dns_db_attach(entry->db, dbp);
1480		dns_db_attachversion(entry->db, entry->version, versionp);
1481	}
1482	if (entry->node == NULL)
1483		*nodep = NULL;
1484	else {
1485		dns_db_attachnode(entry->db, entry->node, nodep);
1486
1487		INSIST(entry->foundname != NULL);
1488		dns_name_copy(entry->foundname, fname, NULL);
1489		for (erdataset = ISC_LIST_HEAD(entry->foundname->list);
1490		     erdataset != NULL;
1491		     erdataset = ISC_LIST_NEXT(erdataset, link)) {
1492			dns_rdataset_t *ardataset;
1493
1494			ardataset = NULL;
1495			result = dns_message_gettemprdataset(msg, &ardataset);
1496			if (result != ISC_R_SUCCESS) {
1497				ACACHE_UNLOCK(&acache->entrylocks[locknum],
1498					      isc_rwlocktype_read);
1499				goto fail;
1500			}
1501
1502			/*
1503			 * XXXJT: if we simply clone the rdataset, we'll get
1504			 * lost wrt cyclic ordering.  We'll need an additional
1505			 * trick to get the latest counter from the original
1506			 * header.
1507			 */
1508			dns_rdataset_init(ardataset);
1509			dns_rdataset_clone(erdataset, ardataset);
1510			ISC_LIST_APPEND(fname->list, ardataset, link);
1511		}
1512	}
1513
1514	entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */
1515	entry->acache->stats.queries++;
1516
1517	ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
1518
1519	return (result);
1520
1521  fail:
1522	while ((erdataset = ISC_LIST_HEAD(fname->list)) != NULL) {
1523		ISC_LIST_UNLINK(fname->list, erdataset, link);
1524		dns_rdataset_disassociate(erdataset);
1525		dns_message_puttemprdataset(msg, &erdataset);
1526	}
1527	if (*nodep != NULL)
1528		dns_db_detachnode(*dbp, nodep);
1529	if (*versionp != NULL)
1530		dns_db_closeversion(*dbp, versionp, ISC_FALSE);
1531	if (*dbp != NULL)
1532		dns_db_detach(dbp);
1533	if (zonep != NULL && *zonep != NULL)
1534		dns_zone_detach(zonep);
1535
1536	return (result);
1537}
1538
1539isc_result_t
1540dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
1541		    dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version,
1542		    dns_dbnode_t *node, dns_name_t *fname)
1543{
1544	isc_result_t result;
1545	dbentry_t *odbent;
1546	dbentry_t *rdbent = NULL;
1547	isc_boolean_t close_version = ISC_FALSE;
1548	dns_acacheentry_t *dummy_entry = NULL;
1549
1550	REQUIRE(DNS_ACACHE_VALID(acache));
1551	REQUIRE(DNS_ACACHEENTRY_VALID(entry));
1552
1553	LOCK(&acache->lock);	/* XXX: need to lock it here for ordering */
1554	ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
1555
1556	/* Set zone */
1557	if (zone != NULL)
1558		dns_zone_attach(zone, &entry->zone);
1559	/* Set DB */
1560	if (db != NULL)
1561		dns_db_attach(db, &entry->db);
1562	/*
1563	 * Set DB version.  If the version is not given by the caller,
1564	 * which is the case for glue or cache DBs, use the current version.
1565	 */
1566	if (version == NULL) {
1567		if (db != NULL) {
1568			dns_db_currentversion(db, &version);
1569			close_version = ISC_TRUE;
1570		}
1571	}
1572	if (version != NULL) {
1573		INSIST(db != NULL);
1574		dns_db_attachversion(db, version, &entry->version);
1575	}
1576	if (close_version)
1577		dns_db_closeversion(db, &version, ISC_FALSE);
1578	/* Set DB node. */
1579	if (node != NULL) {
1580		INSIST(db != NULL);
1581		dns_db_attachnode(db, node, &entry->node);
1582	}
1583
1584	/*
1585	 * Set list of the corresponding rdatasets, if given.
1586	 * To minimize the overhead and memory consumption, we'll do this for
1587	 * positive cache only, in which case the DB node is non NULL.
1588	 * We do not want to cache incomplete information, so give up the
1589	 * entire entry when a memory shortage happen during the process.
1590	 */
1591	if (node != NULL) {
1592		dns_rdataset_t *ardataset, *crdataset;
1593
1594		entry->foundname = isc_mem_get(acache->mctx,
1595					       sizeof(*entry->foundname));
1596
1597		if (entry->foundname == NULL) {
1598			result = ISC_R_NOMEMORY;
1599			goto fail;
1600		}
1601		dns_name_init(entry->foundname, NULL);
1602		result = dns_name_dup(fname, acache->mctx,
1603				      entry->foundname);
1604		if (result != ISC_R_SUCCESS)
1605			goto fail;
1606
1607		for (ardataset = ISC_LIST_HEAD(fname->list);
1608		     ardataset != NULL;
1609		     ardataset = ISC_LIST_NEXT(ardataset, link)) {
1610			crdataset = isc_mem_get(acache->mctx,
1611						sizeof(*crdataset));
1612			if (crdataset == NULL) {
1613				result = ISC_R_NOMEMORY;
1614				goto fail;
1615			}
1616
1617			dns_rdataset_init(crdataset);
1618			dns_rdataset_clone(ardataset, crdataset);
1619			ISC_LIST_APPEND(entry->foundname->list, crdataset,
1620					link);
1621		}
1622	}
1623
1624	odbent = NULL;
1625	result = finddbent(acache, entry->origdb, &odbent);
1626	if (result != ISC_R_SUCCESS)
1627		goto fail;
1628	if (db != NULL) {
1629		rdbent = NULL;
1630		result = finddbent(acache, db, &rdbent);
1631		if (result != ISC_R_SUCCESS)
1632			goto fail;
1633	}
1634
1635	ISC_LIST_APPEND(acache->entries, entry, link);
1636	ISC_LIST_APPEND(odbent->originlist, entry, olink);
1637	if (rdbent != NULL)
1638		ISC_LIST_APPEND(rdbent->referlist, entry, rlink);
1639
1640	/*
1641	 * The additional cache needs an implicit reference to entries in its
1642	 * link.
1643	 */
1644	dns_acache_attachentry(entry, &dummy_entry);
1645
1646	ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
1647		      isc_rwlocktype_write);
1648
1649	acache->stats.adds++;
1650	UNLOCK(&acache->lock);
1651
1652	return (ISC_R_SUCCESS);
1653
1654 fail:
1655	clear_entry(acache, entry);
1656
1657	ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
1658		      isc_rwlocktype_write);
1659	UNLOCK(&acache->lock);
1660
1661	return (result);
1662}
1663
1664isc_boolean_t
1665dns_acache_cancelentry(dns_acacheentry_t *entry) {
1666	dns_acache_t *acache;
1667	isc_boolean_t callback_active;
1668
1669	REQUIRE(DNS_ACACHEENTRY_VALID(entry));
1670
1671	acache = entry->acache;
1672
1673	INSIST(DNS_ACACHE_VALID(entry->acache));
1674
1675	LOCK(&acache->lock);
1676	ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
1677
1678	callback_active = ISC_TF(entry->cbarg != NULL);
1679
1680	/*
1681	 * Release dependencies stored in this entry as much as possible.
1682	 * The main link cannot be released, since the acache object has
1683	 * a reference to this entry; the empty entry will be released in
1684	 * the next cleaning action.
1685	 */
1686	unlink_dbentries(acache, entry);
1687	clear_entry(entry->acache, entry);
1688
1689	entry->callback = NULL;
1690	entry->cbarg = NULL;
1691
1692	ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
1693		      isc_rwlocktype_write);
1694	UNLOCK(&acache->lock);
1695
1696	return (callback_active);
1697}
1698
1699void
1700dns_acache_attachentry(dns_acacheentry_t *source,
1701		       dns_acacheentry_t **targetp)
1702{
1703	REQUIRE(DNS_ACACHEENTRY_VALID(source));
1704	REQUIRE(targetp != NULL && *targetp == NULL);
1705
1706	isc_refcount_increment(&source->references, NULL);
1707
1708	*targetp = source;
1709}
1710
1711void
1712dns_acache_detachentry(dns_acacheentry_t **entryp) {
1713	dns_acacheentry_t *entry;
1714	unsigned int refs;
1715
1716	REQUIRE(entryp != NULL && DNS_ACACHEENTRY_VALID(*entryp));
1717	entry = *entryp;
1718
1719	isc_refcount_decrement(&entry->references, &refs);
1720
1721	/*
1722	 * If there are no references to the entry, the entry must have been
1723	 * unlinked and can be destroyed safely.
1724	 */
1725	if (refs == 0) {
1726		INSIST(!ISC_LINK_LINKED(entry, link));
1727		(*entryp)->acache->stats.deleted++;
1728		destroy_entry(entry);
1729	}
1730
1731	*entryp = NULL;
1732}
1733
1734void
1735dns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t) {
1736	isc_interval_t interval;
1737	isc_result_t result;
1738
1739	REQUIRE(DNS_ACACHE_VALID(acache));
1740
1741	ATRACE("dns_acache_setcleaninginterval");
1742
1743	LOCK(&acache->lock);
1744
1745	/*
1746	 * It may be the case that the acache has already shut down.
1747	 * If so, it has no timer.  (Not sure if this can really happen.)
1748	 */
1749	if (acache->cleaner.cleaning_timer == NULL)
1750		goto unlock;
1751
1752	acache->cleaner.cleaning_interval = t;
1753
1754	if (t == 0) {
1755		result = isc_timer_reset(acache->cleaner.cleaning_timer,
1756					 isc_timertype_inactive,
1757					 NULL, NULL, ISC_TRUE);
1758	} else {
1759		isc_interval_set(&interval, acache->cleaner.cleaning_interval,
1760				 0);
1761		result = isc_timer_reset(acache->cleaner.cleaning_timer,
1762					 isc_timertype_ticker,
1763					 NULL, &interval, ISC_FALSE);
1764	}
1765	if (result != ISC_R_SUCCESS)
1766		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1767			      DNS_LOGMODULE_ACACHE, ISC_LOG_WARNING,
1768			      "could not set acache cleaning interval: %s",
1769			      isc_result_totext(result));
1770	else
1771		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
1772			      DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE,
1773			      "acache %p cleaning interval set to %d.",
1774			      acache, t);
1775
1776 unlock:
1777	UNLOCK(&acache->lock);
1778}
1779
1780/*
1781 * This function was derived from cache.c:dns_cache_setcachesize().  See the
1782 * function for more details about the logic.
1783 */
1784void
1785dns_acache_setcachesize(dns_acache_t *acache, size_t size) {
1786	size_t hiwater, lowater;
1787
1788	REQUIRE(DNS_ACACHE_VALID(acache));
1789
1790	if (size != 0U && size < DNS_ACACHE_MINSIZE)
1791		size = DNS_ACACHE_MINSIZE;
1792
1793	hiwater = size - (size >> 3);
1794	lowater = size - (size >> 2);
1795
1796	if (size == 0U || hiwater == 0U || lowater == 0U)
1797		isc_mem_setwater(acache->mctx, water, acache, 0, 0);
1798	else
1799		isc_mem_setwater(acache->mctx, water, acache,
1800				 hiwater, lowater);
1801}
1802