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