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