/contrib/bind9/lib/dns/cache.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1207 lines · 815 code · 214 blank · 178 comment · 245 complexity · d1c43e0491de7ece6b1c62eade214957 MD5 · raw file

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