cache.c revision fc8a6561cbb0a1fea849950a3217aacd3b8f1eac
1413616670fcb95b9ef236351502e4884ddca8bfTinderbox User * Copyright (C) 1999, 2000 Internet Software Consortium.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Permission to use, copy, modify, and distribute this software for any
ec5347e2c775f027573ce5648b910361aa926c01Automatic Updater * purpose with or without fee is hereby granted, provided that the above
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * copyright notice and this permission notice appear in all copies.
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
dafcb997e390efa4423883dafd100c975c4095d6Mark Andrews * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28a8f5b0de57d269cf2845c69cb6abe18cbd3b3aMark Andrews/* $Id: cache.c,v 1.18 2000/04/25 19:35:39 tale Exp $ */
28b863e609ff2d97b78663b46894494cfa2ea411Mark Andrews#define VALID_CACHE(cache) ((cache) != NULL && (cache)->magic == CACHE_MAGIC)
1a69a1a78cfaa86f3b68bbc965232b7876d4da2aDavid Lawrence * A cache_cleaner_t encapsulsates the state of the periodic
a98551ef592e9be6008e0141ceeb32efd586c5efMark Andrews * cache cleaning.
3ddd92da6651bc72aa79a04195ad389d86fd1a66Andreas Gustafssontypedef struct cache_cleaner cache_cleaner_t;
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews cleaner_s_idle, /* Waiting for cleaning-interval to expire. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews/* Convenience macros for comprehensive assertion checking. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
eb6bd543c7d072efdca509eb17f8f301c1467b53Mark Andrews unsigned int cleaning_interval; /* The cleaning-interval from
deaaf94332abbfdb3aff53675546acfed16e5eb6Mark Andrews named.conf, in seconds. */
c46f10e4a1702191b003cf8f8fc5059c15d29c48Mark Andrews isc_event_t *resched_event; /* Sent by cleaner task to
0b056755b2f423ba5f6adac8f7851d78f7d11437David Lawrence itself to reschedule */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence clean in one increment */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * The actual cache object.
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Unlocked */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence unsigned int magic;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Locked by 'lock'. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Locked by 'filelock'. */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence /* Access to the on-disk cache file is also locked by 'filelock'. */
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews *** Functions
0c8649cea98afc061dd2938fd315df53b8fc35caAndreas Gustafsson isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
ab023a65562e62b85a824509d829b6fad87e00b1Rob Austeincleaning_timer_action(isc_task_t *task, isc_event_t *event);
e672951ed28b2e9cc7a19c3d7fa4a258382f981cAutomatic Updaterincremental_cleaning_action(isc_task_t *task, isc_event_t *event);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencecleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrencedns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence char *db_type, unsigned int db_argc, char **db_argv,
330705066b03f6ce0bc08a4bbfc5d2418038c68dBrian Wellington "isc_mutex_init() failed: %s",
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence result = dns_db_create(cache->mctx, db_type, dns_rootname, ISC_TRUE,
8abddcd3f24476b945419659e7cb73bcb970886bDavid Lawrence result = cache_cleaner_init(cache, taskmgr, timermgr,
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafsson if (cache->cleaner.resched_event != NULL)
76c8294c81fb48b1da6e1fc5b83322a4cedb8e58Andreas Gustafsson isc_event_free(&cache->cleaner.resched_event);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence dns_dbiterator_destroy(&cache->cleaner.iterator);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews isc_mem_put(cache->mctx, cache, sizeof *cache);
6098d364b690cb9dabf96e9664c4689c8559bd2eMark Andrewsdns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) {
f1c1aab2c9e720399d66d8db5f40515d47c45ecfMark Andrews /* XXXRTH This is not locked! */
f1c1aab2c9e720399d66d8db5f40515d47c45ecfMark Andrewsdns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp) {
f1c1aab2c9e720399d66d8db5f40515d47c45ecfMark Andrewsdns_cache_setfilename(dns_cache_t *cahce, char *filename) /* ARGSUSED */
f1c1aab2c9e720399d66d8db5f40515d47c45ecfMark Andrews /* XXX handle TTLs in a way appropriate for the cache */
f1c1aab2c9e720399d66d8db5f40515d47c45ecfMark Andrews result = dns_db_load(cache->db, cache->filename);
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews /* XXX to be written */
aa05bbdef7f7827dde158dcc913f4dade84c8511Brian Wellingtondns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews if (t == 0) {
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews isc_timer_reset(cache->cleaner.cleaning_timer, isc_timertype_inactive,
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_interval_set(&interval, cache->cleaner.cleaning_interval, 0);
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews isc_timer_reset(cache->cleaner.cleaning_timer, isc_timertype_ticker,
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * Initialize the cache cleaner object at *cleaner.
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrews * Space for the object must be allocated by the caller.
2002be4f65776451676df6ee21a2e28f52bcad6dMark Andrewscache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
d4422ec231e58b60693620cf298276e47f04f0ecMark Andrews isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
bed8e84810a80dad3d37870be927d1dfd015f480Mark Andrews result = isc_task_create(taskmgr, 1, &cleaner->task);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "isc_task_create() failed: %s",
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_task_setname(cleaner->task, "cachecleaner", cleaner);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "cache cleaner: "
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "isc_task_onshutdown() failed: %s",
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews cleaner->cleaning_interval = 0; /* Initially turned off. */
cabaeca9ae5b98c80586b91e89cf552e17a75a9bBrian Wellington result = isc_timer_create(timermgr, isc_timertype_inactive,
389c749a5ee18f1c0d6278ae49f2aae5d5f0d2dcMark Andrews "isc_timer_create() failed: %s",
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence * Create an iterator and position it at the beginning of the cache.
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
735ca24fa61ad9cd0285776c2fc4c14032f8f194Mark Andrews "cache cleaner could not create "
d981ca645597116d227a48bf37cc5edc061c854dBob Halley result = dns_dbiterator_first(cleaner->iterator);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * The database is empty. We are done.
44a966dff66061ac3f266c6b451a70733eb78e82Mark Andrews "cache cleaner: dns_dbiterator_first() "
90e303b114e56db5809fdd19805243457fa43cd9Olafur Gudmundsson isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "begin cache cleaning");
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_task_send(cleaner->task, &cleaner->resched_event);
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrewsend_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrews isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrews "end cache cleaning");
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrews * This is run once for every cache-cleaning-interval as defined in named.conf.
3d17a3ba61a303d5c4d9867068d0fbe9f24d2988Mark Andrewscleaning_timer_action(isc_task_t *task, isc_event_t *event) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews "cache cleaner did not finish "
0e8cf9a887c70f96ac448b06c069d90b830215ccMark Andrews "in one cleaning-interval");
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews * Do incremental cleaning.
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrewsincremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
19d365e4448f1782611280b020987988b7ac3210Mark Andrews REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews while (n_names-- > 0) {
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = dns_dbiterator_current(cleaner->iterator, &node,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews "cache cleaner: dns_dbiterator_current() "
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* Check TTLs, mark expired rdatasets stale. */
3d5cad69ec20157912e95cf3b79316dfb0a314f3Mark Andrews result = dns_db_expirenode(cleaner->cache->db, node, now);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews "cache cleaner: dns_db_expirenode() "
19d365e4448f1782611280b020987988b7ac3210Mark Andrews "failed: %s",
f1cae4bcb7ee3060d893f5ab3ba55c1820bf3e4aBrian Wellington /* Continue anyway. */
7e9d637131516486630290d36c4c0db544cb700eMark Andrews /* This is where the actual freeing takes place. */
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson /* Step to the next node */
6bebabb376b93e7d12f53a253b197a3fc0e0b001Andreas Gustafsson result = dns_dbiterator_next(cleaner->iterator);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews /* We have successfully cleaned the whole cache. */
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews "cache cleaner: dns_dbiterator_next() "
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews /* We have successfully performed a cleaning increment. */
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews result = dns_dbiterator_pause(cleaner->iterator);
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews "cache cleaner: dns_dbiterator_pause() "
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews /* Try to continue. */
1bbd36c4db2c86762b582db4b0504e6e68a183f6Mark Andrews /* Still busy, reschedule. */
1bbd36c4db2c86762b582db4b0504e6e68a183f6Mark Andrews /* No longer busy; save the event for later use. */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * Do immediate cleaning.
1bbd36c4db2c86762b582db4b0504e6e68a183f6Mark Andrewsdns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) {
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator);
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews result = dns_dbiterator_current(iterator, &node,
f0a5bb8f86631ce638cb2b6c65bbb9bcf9b0cdc0Bob Halley /* Check TTLs, mark expired rdatasets stale. */
52637f592f705ca93fadc218e403fd55e8ce4aeaMark Andrews result = dns_db_expirenode(cache->db, node, now);
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews "cache cleaner: dns_db_expirenode() "
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence "failed: %s",
693ddf84daa745a0ea8ca311a8154dfa03eabc43Andreas Gustafsson /* Continue anyway. */
c03bb27f0675a6e60ceea66b451548e8481bc05cMark Andrews /* This is where the actual freeing takes place. */
5d51e67c3b4f35c1be742574aacc1d88fe6ed444Mark Andrews * The cleaner task is shutting down; do the necessary cleanup.
7c0378745269fe49a05904935afc42b85528f53aDavid Lawrencecleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
7e4cda9965e2edf2ec43c57967eec8eff7061ab0Andreas Gustafsson INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
942d1a339b1fe617f7d17d66cb5fccce798d15aeBrian Wellington * By detaching the timer in the context of its task,
93ed317bb43658ed48ee7439f7a36bb9bcf80c94Brian Wellington * we are guaranteed that there will be no further timer
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews isc_timer_detach(&cache->cleaner.cleaning_timer);
9916239908343b3eb17f0578de4c3cd6a313d85fMark Andrews /* Make sure we don't reschedule anymore. */