00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <config.h>
00023
00024 #include <isc/json.h>
00025 #include <isc/mem.h>
00026 #include <isc/print.h>
00027 #include <isc/string.h>
00028 #include <isc/stats.h>
00029 #include <isc/task.h>
00030 #include <isc/time.h>
00031 #include <isc/timer.h>
00032 #include <isc/util.h>
00033 #include <isc/xml.h>
00034
00035 #include <dns/cache.h>
00036 #include <dns/db.h>
00037 #include <dns/dbiterator.h>
00038 #include <dns/events.h>
00039 #include <dns/lib.h>
00040 #include <dns/log.h>
00041 #include <dns/masterdump.h>
00042 #include <dns/rdata.h>
00043 #include <dns/rdataset.h>
00044 #include <dns/rdatasetiter.h>
00045 #include <dns/result.h>
00046 #include <dns/stats.h>
00047
00048 #include "rbtdb.h"
00049
00050 #define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$')
00051 #define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC)
00052
00053
00054
00055
00056
00057
00058 #define DNS_CACHE_MINSIZE 2097152U
00059
00060
00061
00062
00063
00064 #define DNS_CACHE_CLEANERINCREMENT 1000U
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075 typedef struct cache_cleaner cache_cleaner_t;
00076
00077 typedef enum {
00078 cleaner_s_idle,
00079 cleaner_s_busy,
00080 cleaner_s_done
00081 } cleaner_state_t;
00082
00083
00084
00085
00086 #define CLEANER_IDLE(c) ((c)->state == cleaner_s_idle && \
00087 (c)->resched_event != NULL)
00088 #define CLEANER_BUSY(c) ((c)->state == cleaner_s_busy && \
00089 (c)->iterator != NULL && \
00090 (c)->resched_event == NULL)
00091
00092
00093
00094
00095
00096 struct cache_cleaner {
00097 isc_mutex_t lock;
00098
00099
00100
00101
00102
00103
00104
00105 dns_cache_t *cache;
00106 isc_task_t *task;
00107 unsigned int cleaning_interval;
00108
00109 isc_timer_t *cleaning_timer;
00110 isc_event_t *resched_event;
00111
00112 isc_event_t *overmem_event;
00113
00114 dns_dbiterator_t *iterator;
00115 unsigned int increment;
00116
00117 cleaner_state_t state;
00118 isc_boolean_t overmem;
00119 isc_boolean_t replaceiterator;
00120 };
00121
00122
00123
00124
00125
00126 struct dns_cache {
00127
00128 unsigned int magic;
00129 isc_mutex_t lock;
00130 isc_mutex_t filelock;
00131 isc_mem_t *mctx;
00132 isc_mem_t *hmctx;
00133 char *name;
00134
00135
00136 int references;
00137 int live_tasks;
00138 dns_rdataclass_t rdclass;
00139 dns_db_t *db;
00140 cache_cleaner_t cleaner;
00141 char *db_type;
00142 int db_argc;
00143 char **db_argv;
00144 size_t size;
00145 isc_stats_t *stats;
00146
00147
00148 char *filename;
00149
00150 };
00151
00152
00153
00154
00155
00156 static isc_result_t
00157 cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
00158 isc_timermgr_t *timermgr, cache_cleaner_t *cleaner);
00159
00160 static void
00161 cleaning_timer_action(isc_task_t *task, isc_event_t *event);
00162
00163 static void
00164 incremental_cleaning_action(isc_task_t *task, isc_event_t *event);
00165
00166 static void
00167 cleaner_shutdown_action(isc_task_t *task, isc_event_t *event);
00168
00169 static void
00170 overmem_cleaning_action(isc_task_t *task, isc_event_t *event);
00171
00172 static inline isc_result_t
00173 cache_create_db(dns_cache_t *cache, dns_db_t **db) {
00174 return (dns_db_create(cache->mctx, cache->db_type, dns_rootname,
00175 dns_dbtype_cache, cache->rdclass,
00176 cache->db_argc, cache->db_argv, db));
00177 }
00178
00179 isc_result_t
00180 dns_cache_create(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
00181 isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
00182 const char *db_type, unsigned int db_argc, char **db_argv,
00183 dns_cache_t **cachep)
00184 {
00185 return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass, "",
00186 db_type, db_argc, db_argv, cachep));
00187 }
00188
00189 isc_result_t
00190 dns_cache_create2(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
00191 isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
00192 const char *cachename, const char *db_type,
00193 unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
00194 {
00195 return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass,
00196 cachename, db_type, db_argc, db_argv,
00197 cachep));
00198 }
00199
00200 isc_result_t
00201 dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr,
00202 isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
00203 const char *cachename, const char *db_type,
00204 unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
00205 {
00206 isc_result_t result;
00207 dns_cache_t *cache;
00208 int i, extra = 0;
00209 isc_task_t *dbtask;
00210
00211 REQUIRE(cachep != NULL);
00212 REQUIRE(*cachep == NULL);
00213 REQUIRE(cmctx != NULL);
00214 REQUIRE(hmctx != NULL);
00215 REQUIRE(cachename != NULL);
00216
00217 cache = isc_mem_get(cmctx, sizeof(*cache));
00218 if (cache == NULL)
00219 return (ISC_R_NOMEMORY);
00220
00221 cache->mctx = cache->hmctx = NULL;
00222 isc_mem_attach(cmctx, &cache->mctx);
00223 isc_mem_attach(hmctx, &cache->hmctx);
00224
00225 cache->name = NULL;
00226 if (cachename != NULL) {
00227 cache->name = isc_mem_strdup(cmctx, cachename);
00228 if (cache->name == NULL) {
00229 result = ISC_R_NOMEMORY;
00230 goto cleanup_mem;
00231 }
00232 }
00233
00234 result = isc_mutex_init(&cache->lock);
00235 if (result != ISC_R_SUCCESS)
00236 goto cleanup_mem;
00237
00238 result = isc_mutex_init(&cache->filelock);
00239 if (result != ISC_R_SUCCESS)
00240 goto cleanup_lock;
00241
00242 cache->references = 1;
00243 cache->live_tasks = 0;
00244 cache->rdclass = rdclass;
00245
00246 cache->stats = NULL;
00247 result = isc_stats_create(cmctx, &cache->stats,
00248 dns_cachestatscounter_max);
00249 if (result != ISC_R_SUCCESS)
00250 goto cleanup_filelock;
00251
00252 cache->db_type = isc_mem_strdup(cmctx, db_type);
00253 if (cache->db_type == NULL) {
00254 result = ISC_R_NOMEMORY;
00255 goto cleanup_stats;
00256 }
00257
00258
00259
00260
00261
00262
00263 if (strcmp(cache->db_type, "rbt") == 0)
00264 extra = 1;
00265
00266 cache->db_argc = db_argc + extra;
00267 cache->db_argv = NULL;
00268
00269 if (cache->db_argc != 0) {
00270 cache->db_argv = isc_mem_get(cmctx,
00271 cache->db_argc * sizeof(char *));
00272 if (cache->db_argv == NULL) {
00273 result = ISC_R_NOMEMORY;
00274 goto cleanup_dbtype;
00275 }
00276
00277 for (i = 0; i < cache->db_argc; i++)
00278 cache->db_argv[i] = NULL;
00279
00280 cache->db_argv[0] = (char *) hmctx;
00281 for (i = extra; i < cache->db_argc; i++) {
00282 cache->db_argv[i] = isc_mem_strdup(cmctx,
00283 db_argv[i - extra]);
00284 if (cache->db_argv[i] == NULL) {
00285 result = ISC_R_NOMEMORY;
00286 goto cleanup_dbargv;
00287 }
00288 }
00289 }
00290
00291
00292
00293
00294 cache->db = NULL;
00295 result = cache_create_db(cache, &cache->db);
00296 if (result != ISC_R_SUCCESS)
00297 goto cleanup_dbargv;
00298 if (taskmgr != NULL) {
00299 dbtask = NULL;
00300 result = isc_task_create(taskmgr, 1, &dbtask);
00301 if (result != ISC_R_SUCCESS)
00302 goto cleanup_db;
00303
00304 isc_task_setname(dbtask, "cache_dbtask", NULL);
00305 dns_db_settask(cache->db, dbtask);
00306 isc_task_detach(&dbtask);
00307 }
00308
00309 cache->filename = NULL;
00310
00311 cache->magic = CACHE_MAGIC;
00312
00313
00314
00315
00316
00317 if (strcmp(db_type, "rbt") == 0)
00318 result = cache_cleaner_init(cache, NULL, NULL, &cache->cleaner);
00319 else {
00320 result = cache_cleaner_init(cache, taskmgr, timermgr,
00321 &cache->cleaner);
00322 }
00323 if (result != ISC_R_SUCCESS)
00324 goto cleanup_db;
00325
00326 result = dns_db_setcachestats(cache->db, cache->stats);
00327 if (result != ISC_R_SUCCESS)
00328 goto cleanup_db;
00329
00330
00331 *cachep = cache;
00332 return (ISC_R_SUCCESS);
00333
00334 cleanup_db:
00335 dns_db_detach(&cache->db);
00336 cleanup_dbargv:
00337 for (i = extra; i < cache->db_argc; i++)
00338 if (cache->db_argv[i] != NULL)
00339 isc_mem_free(cmctx, cache->db_argv[i]);
00340 if (cache->db_argv != NULL)
00341 isc_mem_put(cmctx, cache->db_argv,
00342 cache->db_argc * sizeof(char *));
00343 cleanup_dbtype:
00344 isc_mem_free(cmctx, cache->db_type);
00345 cleanup_filelock:
00346 DESTROYLOCK(&cache->filelock);
00347 cleanup_stats:
00348 isc_stats_detach(&cache->stats);
00349 cleanup_lock:
00350 DESTROYLOCK(&cache->lock);
00351 cleanup_mem:
00352 if (cache->name != NULL)
00353 isc_mem_free(cmctx, cache->name);
00354 isc_mem_detach(&cache->hmctx);
00355 isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
00356 return (result);
00357 }
00358
00359 static void
00360 cache_free(dns_cache_t *cache) {
00361 int i;
00362
00363 REQUIRE(VALID_CACHE(cache));
00364 REQUIRE(cache->references == 0);
00365
00366 isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0);
00367
00368 if (cache->cleaner.task != NULL)
00369 isc_task_detach(&cache->cleaner.task);
00370
00371 if (cache->cleaner.overmem_event != NULL)
00372 isc_event_free(&cache->cleaner.overmem_event);
00373
00374 if (cache->cleaner.resched_event != NULL)
00375 isc_event_free(&cache->cleaner.resched_event);
00376
00377 if (cache->cleaner.iterator != NULL)
00378 dns_dbiterator_destroy(&cache->cleaner.iterator);
00379
00380 DESTROYLOCK(&cache->cleaner.lock);
00381
00382 if (cache->filename) {
00383 isc_mem_free(cache->mctx, cache->filename);
00384 cache->filename = NULL;
00385 }
00386
00387 if (cache->db != NULL)
00388 dns_db_detach(&cache->db);
00389
00390 if (cache->db_argv != NULL) {
00391
00392
00393
00394
00395 int extra = 0;
00396 if (strcmp(cache->db_type, "rbt") == 0)
00397 extra = 1;
00398 for (i = extra; i < cache->db_argc; i++)
00399 if (cache->db_argv[i] != NULL)
00400 isc_mem_free(cache->mctx, cache->db_argv[i]);
00401 isc_mem_put(cache->mctx, cache->db_argv,
00402 cache->db_argc * sizeof(char *));
00403 }
00404
00405 if (cache->db_type != NULL)
00406 isc_mem_free(cache->mctx, cache->db_type);
00407
00408 if (cache->name != NULL)
00409 isc_mem_free(cache->mctx, cache->name);
00410
00411 if (cache->stats != NULL)
00412 isc_stats_detach(&cache->stats);
00413
00414 DESTROYLOCK(&cache->lock);
00415 DESTROYLOCK(&cache->filelock);
00416
00417 cache->magic = 0;
00418 isc_mem_detach(&cache->hmctx);
00419 isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
00420 }
00421
00422
00423 void
00424 dns_cache_attach(dns_cache_t *cache, dns_cache_t **targetp) {
00425
00426 REQUIRE(VALID_CACHE(cache));
00427 REQUIRE(targetp != NULL && *targetp == NULL);
00428
00429 LOCK(&cache->lock);
00430 cache->references++;
00431 UNLOCK(&cache->lock);
00432
00433 *targetp = cache;
00434 }
00435
00436 void
00437 dns_cache_detach(dns_cache_t **cachep) {
00438 dns_cache_t *cache;
00439 isc_boolean_t free_cache = ISC_FALSE;
00440
00441 REQUIRE(cachep != NULL);
00442 cache = *cachep;
00443 REQUIRE(VALID_CACHE(cache));
00444
00445 LOCK(&cache->lock);
00446 REQUIRE(cache->references > 0);
00447 cache->references--;
00448 if (cache->references == 0) {
00449 cache->cleaner.overmem = ISC_FALSE;
00450 free_cache = ISC_TRUE;
00451 }
00452
00453 *cachep = NULL;
00454
00455 if (free_cache) {
00456
00457
00458
00459
00460 isc_result_t result = dns_cache_dump(cache);
00461 if (result != ISC_R_SUCCESS)
00462 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
00463 DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
00464 "error dumping cache: %s ",
00465 isc_result_totext(result));
00466
00467
00468
00469
00470 if (cache->live_tasks > 0) {
00471 isc_task_shutdown(cache->cleaner.task);
00472 free_cache = ISC_FALSE;
00473 }
00474 }
00475
00476 UNLOCK(&cache->lock);
00477
00478 if (free_cache)
00479 cache_free(cache);
00480 }
00481
00482 void
00483 dns_cache_attachdb(dns_cache_t *cache, dns_db_t **dbp) {
00484 REQUIRE(VALID_CACHE(cache));
00485 REQUIRE(dbp != NULL && *dbp == NULL);
00486 REQUIRE(cache->db != NULL);
00487
00488 LOCK(&cache->lock);
00489 dns_db_attach(cache->db, dbp);
00490 UNLOCK(&cache->lock);
00491
00492 }
00493
00494 isc_result_t
00495 dns_cache_setfilename(dns_cache_t *cache, const char *filename) {
00496 char *newname;
00497
00498 REQUIRE(VALID_CACHE(cache));
00499 REQUIRE(filename != NULL);
00500
00501 newname = isc_mem_strdup(cache->mctx, filename);
00502 if (newname == NULL)
00503 return (ISC_R_NOMEMORY);
00504
00505 LOCK(&cache->filelock);
00506 if (cache->filename)
00507 isc_mem_free(cache->mctx, cache->filename);
00508 cache->filename = newname;
00509 UNLOCK(&cache->filelock);
00510
00511 return (ISC_R_SUCCESS);
00512 }
00513
00514 isc_result_t
00515 dns_cache_load(dns_cache_t *cache) {
00516 isc_result_t result;
00517
00518 REQUIRE(VALID_CACHE(cache));
00519
00520 if (cache->filename == NULL)
00521 return (ISC_R_SUCCESS);
00522
00523 LOCK(&cache->filelock);
00524 result = dns_db_load(cache->db, cache->filename);
00525 UNLOCK(&cache->filelock);
00526
00527 return (result);
00528 }
00529
00530 isc_result_t
00531 dns_cache_dump(dns_cache_t *cache) {
00532 isc_result_t result;
00533
00534 REQUIRE(VALID_CACHE(cache));
00535
00536 if (cache->filename == NULL)
00537 return (ISC_R_SUCCESS);
00538
00539 LOCK(&cache->filelock);
00540 result = dns_master_dump(cache->mctx, cache->db, NULL,
00541 &dns_master_style_cache, cache->filename);
00542 UNLOCK(&cache->filelock);
00543 return (result);
00544
00545 }
00546
00547 void
00548 dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
00549 isc_interval_t interval;
00550 isc_result_t result;
00551
00552 LOCK(&cache->lock);
00553
00554
00555
00556
00557
00558 if (cache->cleaner.cleaning_timer == NULL)
00559 goto unlock;
00560
00561 cache->cleaner.cleaning_interval = t;
00562
00563 if (t == 0) {
00564 result = isc_timer_reset(cache->cleaner.cleaning_timer,
00565 isc_timertype_inactive,
00566 NULL, NULL, ISC_TRUE);
00567 } else {
00568 isc_interval_set(&interval, cache->cleaner.cleaning_interval,
00569 0);
00570 result = isc_timer_reset(cache->cleaner.cleaning_timer,
00571 isc_timertype_ticker,
00572 NULL, &interval, ISC_FALSE);
00573 }
00574 if (result != ISC_R_SUCCESS)
00575 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
00576 DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
00577 "could not set cache cleaning interval: %s",
00578 isc_result_totext(result));
00579
00580 unlock:
00581 UNLOCK(&cache->lock);
00582 }
00583
00584 unsigned int
00585 dns_cache_getcleaninginterval(dns_cache_t *cache) {
00586 unsigned int t;
00587
00588 REQUIRE(VALID_CACHE(cache));
00589
00590 LOCK(&cache->lock);
00591 t = cache->cleaner.cleaning_interval;
00592 UNLOCK(&cache->lock);
00593
00594 return (t);
00595 }
00596
00597 const char *
00598 dns_cache_getname(dns_cache_t *cache) {
00599 REQUIRE(VALID_CACHE(cache));
00600
00601 return (cache->name);
00602 }
00603
00604
00605
00606
00607
00608
00609 static isc_result_t
00610 cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
00611 isc_timermgr_t *timermgr, cache_cleaner_t *cleaner)
00612 {
00613 isc_result_t result;
00614
00615 result = isc_mutex_init(&cleaner->lock);
00616 if (result != ISC_R_SUCCESS)
00617 goto fail;
00618
00619 cleaner->increment = DNS_CACHE_CLEANERINCREMENT;
00620 cleaner->state = cleaner_s_idle;
00621 cleaner->cache = cache;
00622 cleaner->iterator = NULL;
00623 cleaner->overmem = ISC_FALSE;
00624 cleaner->replaceiterator = ISC_FALSE;
00625
00626 cleaner->task = NULL;
00627 cleaner->cleaning_timer = NULL;
00628 cleaner->resched_event = NULL;
00629 cleaner->overmem_event = NULL;
00630 cleaner->cleaning_interval = 0;
00631
00632 result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
00633 &cleaner->iterator);
00634 if (result != ISC_R_SUCCESS)
00635 goto cleanup;
00636
00637 if (taskmgr != NULL && timermgr != NULL) {
00638 result = isc_task_create(taskmgr, 1, &cleaner->task);
00639 if (result != ISC_R_SUCCESS) {
00640 UNEXPECTED_ERROR(__FILE__, __LINE__,
00641 "isc_task_create() failed: %s",
00642 dns_result_totext(result));
00643 result = ISC_R_UNEXPECTED;
00644 goto cleanup;
00645 }
00646 cleaner->cache->live_tasks++;
00647 isc_task_setname(cleaner->task, "cachecleaner", cleaner);
00648
00649 result = isc_task_onshutdown(cleaner->task,
00650 cleaner_shutdown_action, cache);
00651 if (result != ISC_R_SUCCESS) {
00652 UNEXPECTED_ERROR(__FILE__, __LINE__,
00653 "cache cleaner: "
00654 "isc_task_onshutdown() failed: %s",
00655 dns_result_totext(result));
00656 goto cleanup;
00657 }
00658
00659 result = isc_timer_create(timermgr, isc_timertype_inactive,
00660 NULL, NULL, cleaner->task,
00661 cleaning_timer_action, cleaner,
00662 &cleaner->cleaning_timer);
00663 if (result != ISC_R_SUCCESS) {
00664 UNEXPECTED_ERROR(__FILE__, __LINE__,
00665 "isc_timer_create() failed: %s",
00666 dns_result_totext(result));
00667 result = ISC_R_UNEXPECTED;
00668 goto cleanup;
00669 }
00670
00671 cleaner->resched_event =
00672 isc_event_allocate(cache->mctx, cleaner,
00673 DNS_EVENT_CACHECLEAN,
00674 incremental_cleaning_action,
00675 cleaner, sizeof(isc_event_t));
00676 if (cleaner->resched_event == NULL) {
00677 result = ISC_R_NOMEMORY;
00678 goto cleanup;
00679 }
00680
00681 cleaner->overmem_event =
00682 isc_event_allocate(cache->mctx, cleaner,
00683 DNS_EVENT_CACHEOVERMEM,
00684 overmem_cleaning_action,
00685 cleaner, sizeof(isc_event_t));
00686 if (cleaner->overmem_event == NULL) {
00687 result = ISC_R_NOMEMORY;
00688 goto cleanup;
00689 }
00690 }
00691
00692 return (ISC_R_SUCCESS);
00693
00694 cleanup:
00695 if (cleaner->overmem_event != NULL)
00696 isc_event_free(&cleaner->overmem_event);
00697 if (cleaner->resched_event != NULL)
00698 isc_event_free(&cleaner->resched_event);
00699 if (cleaner->cleaning_timer != NULL)
00700 isc_timer_detach(&cleaner->cleaning_timer);
00701 if (cleaner->task != NULL)
00702 isc_task_detach(&cleaner->task);
00703 if (cleaner->iterator != NULL)
00704 dns_dbiterator_destroy(&cleaner->iterator);
00705 DESTROYLOCK(&cleaner->lock);
00706 fail:
00707 return (result);
00708 }
00709
00710 static void
00711 begin_cleaning(cache_cleaner_t *cleaner) {
00712 isc_result_t result = ISC_R_SUCCESS;
00713
00714 REQUIRE(CLEANER_IDLE(cleaner));
00715
00716
00717
00718
00719
00720 if (cleaner->iterator == NULL)
00721 result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
00722 &cleaner->iterator);
00723 if (result != ISC_R_SUCCESS)
00724 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
00725 DNS_LOGMODULE_CACHE, ISC_LOG_WARNING,
00726 "cache cleaner could not create "
00727 "iterator: %s", isc_result_totext(result));
00728 else {
00729 dns_dbiterator_setcleanmode(cleaner->iterator, ISC_TRUE);
00730 result = dns_dbiterator_first(cleaner->iterator);
00731 }
00732 if (result != ISC_R_SUCCESS) {
00733
00734
00735
00736
00737 if (result != ISC_R_NOMORE && cleaner->iterator != NULL) {
00738 UNEXPECTED_ERROR(__FILE__, __LINE__,
00739 "cache cleaner: "
00740 "dns_dbiterator_first() failed: %s",
00741 dns_result_totext(result));
00742 dns_dbiterator_destroy(&cleaner->iterator);
00743 } else if (cleaner->iterator != NULL) {
00744 result = dns_dbiterator_pause(cleaner->iterator);
00745 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00746 }
00747 } else {
00748
00749
00750
00751 result = dns_dbiterator_pause(cleaner->iterator);
00752 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00753
00754 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
00755 DNS_LOGMODULE_CACHE, ISC_LOG_DEBUG(1),
00756 "begin cache cleaning, mem inuse %lu",
00757 (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
00758 cleaner->state = cleaner_s_busy;
00759 isc_task_send(cleaner->task, &cleaner->resched_event);
00760 }
00761
00762 return;
00763 }
00764
00765 static void
00766 end_cleaning(cache_cleaner_t *cleaner, isc_event_t *event) {
00767 isc_result_t result;
00768
00769 REQUIRE(CLEANER_BUSY(cleaner));
00770 REQUIRE(event != NULL);
00771
00772 result = dns_dbiterator_pause(cleaner->iterator);
00773 if (result != ISC_R_SUCCESS)
00774 dns_dbiterator_destroy(&cleaner->iterator);
00775
00776 dns_cache_setcleaninginterval(cleaner->cache,
00777 cleaner->cleaning_interval);
00778
00779 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
00780 ISC_LOG_DEBUG(1), "end cache cleaning, mem inuse %lu",
00781 (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
00782
00783 cleaner->state = cleaner_s_idle;
00784 cleaner->resched_event = event;
00785 }
00786
00787
00788
00789
00790 static void
00791 cleaning_timer_action(isc_task_t *task, isc_event_t *event) {
00792 cache_cleaner_t *cleaner = event->ev_arg;
00793
00794 UNUSED(task);
00795
00796 INSIST(task == cleaner->task);
00797 INSIST(event->ev_type == ISC_TIMEREVENT_TICK);
00798
00799 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
00800 ISC_LOG_DEBUG(1), "cache cleaning timer fired, "
00801 "cleaner state = %d", cleaner->state);
00802
00803 if (cleaner->state == cleaner_s_idle)
00804 begin_cleaning(cleaner);
00805
00806 isc_event_free(&event);
00807 }
00808
00809
00810
00811
00812
00813 static void
00814 overmem_cleaning_action(isc_task_t *task, isc_event_t *event) {
00815 cache_cleaner_t *cleaner = event->ev_arg;
00816 isc_boolean_t want_cleaning = ISC_FALSE;
00817
00818 UNUSED(task);
00819
00820 INSIST(task == cleaner->task);
00821 INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM);
00822 INSIST(cleaner->overmem_event == NULL);
00823
00824 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
00825 ISC_LOG_DEBUG(1), "overmem_cleaning_action called, "
00826 "overmem = %d, state = %d", cleaner->overmem,
00827 cleaner->state);
00828
00829 LOCK(&cleaner->lock);
00830
00831 if (cleaner->overmem) {
00832 if (cleaner->state == cleaner_s_idle)
00833 want_cleaning = ISC_TRUE;
00834 } else {
00835 if (cleaner->state == cleaner_s_busy)
00836
00837
00838
00839
00840
00841
00842
00843
00844 cleaner->state = cleaner_s_done;
00845 }
00846
00847 cleaner->overmem_event = event;
00848
00849 UNLOCK(&cleaner->lock);
00850
00851 if (want_cleaning)
00852 begin_cleaning(cleaner);
00853 }
00854
00855
00856
00857
00858 static void
00859 incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
00860 cache_cleaner_t *cleaner = event->ev_arg;
00861 isc_result_t result;
00862 unsigned int n_names;
00863 isc_time_t start;
00864
00865 UNUSED(task);
00866
00867 INSIST(task == cleaner->task);
00868 INSIST(event->ev_type == DNS_EVENT_CACHECLEAN);
00869
00870 if (cleaner->state == cleaner_s_done) {
00871 cleaner->state = cleaner_s_busy;
00872 end_cleaning(cleaner, event);
00873 LOCK(&cleaner->cache->lock);
00874 LOCK(&cleaner->lock);
00875 if (cleaner->replaceiterator) {
00876 dns_dbiterator_destroy(&cleaner->iterator);
00877 (void) dns_db_createiterator(cleaner->cache->db,
00878 ISC_FALSE,
00879 &cleaner->iterator);
00880 cleaner->replaceiterator = ISC_FALSE;
00881 }
00882 UNLOCK(&cleaner->lock);
00883 UNLOCK(&cleaner->cache->lock);
00884 return;
00885 }
00886
00887 INSIST(CLEANER_BUSY(cleaner));
00888
00889 n_names = cleaner->increment;
00890
00891 REQUIRE(DNS_DBITERATOR_VALID(cleaner->iterator));
00892
00893 isc_time_now(&start);
00894 while (n_names-- > 0) {
00895 dns_dbnode_t *node = NULL;
00896
00897 result = dns_dbiterator_current(cleaner->iterator, &node,
00898 NULL);
00899 if (result != ISC_R_SUCCESS) {
00900 UNEXPECTED_ERROR(__FILE__, __LINE__,
00901 "cache cleaner: dns_dbiterator_current() "
00902 "failed: %s", dns_result_totext(result));
00903
00904 end_cleaning(cleaner, event);
00905 return;
00906 }
00907
00908
00909
00910
00911
00912 dns_db_detachnode(cleaner->cache->db, &node);
00913
00914
00915
00916
00917 result = dns_dbiterator_next(cleaner->iterator);
00918
00919 if (result != ISC_R_SUCCESS) {
00920
00921
00922
00923
00924
00925
00926 if (result != ISC_R_NOMORE)
00927 UNEXPECTED_ERROR(__FILE__, __LINE__,
00928 "cache cleaner: "
00929 "dns_dbiterator_next() "
00930 "failed: %s",
00931 dns_result_totext(result));
00932 else if (cleaner->overmem) {
00933 result = dns_dbiterator_first(cleaner->
00934 iterator);
00935 if (result == ISC_R_SUCCESS) {
00936 isc_log_write(dns_lctx,
00937 DNS_LOGCATEGORY_DATABASE,
00938 DNS_LOGMODULE_CACHE,
00939 ISC_LOG_DEBUG(1),
00940 "cache cleaner: "
00941 "still overmem, "
00942 "reset and try again");
00943 continue;
00944 }
00945 }
00946
00947 end_cleaning(cleaner, event);
00948 return;
00949 }
00950 }
00951
00952
00953
00954
00955
00956
00957
00958 result = dns_dbiterator_pause(cleaner->iterator);
00959 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00960
00961 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_CACHE,
00962 ISC_LOG_DEBUG(1), "cache cleaner: checked %u nodes, "
00963 "mem inuse %lu, sleeping", cleaner->increment,
00964 (unsigned long)isc_mem_inuse(cleaner->cache->mctx));
00965
00966 isc_task_send(task, &event);
00967 INSIST(CLEANER_BUSY(cleaner));
00968 return;
00969 }
00970
00971
00972
00973
00974 isc_result_t
00975 dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) {
00976 isc_result_t result;
00977 dns_dbiterator_t *iterator = NULL;
00978
00979 REQUIRE(VALID_CACHE(cache));
00980
00981 result = dns_db_createiterator(cache->db, 0, &iterator);
00982 if (result != ISC_R_SUCCESS)
00983 return result;
00984
00985 result = dns_dbiterator_first(iterator);
00986
00987 while (result == ISC_R_SUCCESS) {
00988 dns_dbnode_t *node = NULL;
00989 result = dns_dbiterator_current(iterator, &node,
00990 (dns_name_t *)NULL);
00991 if (result != ISC_R_SUCCESS)
00992 break;
00993
00994
00995
00996
00997 result = dns_db_expirenode(cache->db, node, now);
00998 if (result != ISC_R_SUCCESS) {
00999 UNEXPECTED_ERROR(__FILE__, __LINE__,
01000 "cache cleaner: dns_db_expirenode() "
01001 "failed: %s",
01002 dns_result_totext(result));
01003
01004
01005
01006 }
01007
01008
01009
01010
01011 dns_db_detachnode(cache->db, &node);
01012
01013 result = dns_dbiterator_next(iterator);
01014 }
01015
01016 dns_dbiterator_destroy(&iterator);
01017
01018 if (result == ISC_R_NOMORE)
01019 result = ISC_R_SUCCESS;
01020
01021 return (result);
01022 }
01023
01024 static void
01025 water(void *arg, int mark) {
01026 dns_cache_t *cache = arg;
01027 isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER);
01028
01029 REQUIRE(VALID_CACHE(cache));
01030
01031 LOCK(&cache->cleaner.lock);
01032
01033 if (overmem != cache->cleaner.overmem) {
01034 dns_db_overmem(cache->db, overmem);
01035 cache->cleaner.overmem = overmem;
01036 isc_mem_waterack(cache->mctx, mark);
01037 }
01038
01039 if (cache->cleaner.overmem_event != NULL)
01040 isc_task_send(cache->cleaner.task,
01041 &cache->cleaner.overmem_event);
01042
01043 UNLOCK(&cache->cleaner.lock);
01044 }
01045
01046 void
01047 dns_cache_setcachesize(dns_cache_t *cache, size_t size) {
01048 size_t hiwater, lowater;
01049
01050 REQUIRE(VALID_CACHE(cache));
01051
01052
01053
01054
01055
01056 if (size != 0U && size < DNS_CACHE_MINSIZE)
01057 size = DNS_CACHE_MINSIZE;
01058
01059 LOCK(&cache->lock);
01060 cache->size = size;
01061 UNLOCK(&cache->lock);
01062
01063 hiwater = size - (size >> 3);
01064 lowater = size - (size >> 2);
01065
01066
01067
01068
01069
01070
01071
01072
01073 if (size == 0U || hiwater == 0U || lowater == 0U)
01074
01075
01076
01077 isc_mem_setwater(cache->mctx, water, cache, 0, 0);
01078 else
01079
01080
01081
01082
01083 isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
01084 }
01085
01086 size_t
01087 dns_cache_getcachesize(dns_cache_t *cache) {
01088 size_t size;
01089
01090 REQUIRE(VALID_CACHE(cache));
01091
01092 LOCK(&cache->lock);
01093 size = cache->size;
01094 UNLOCK(&cache->lock);
01095
01096 return (size);
01097 }
01098
01099
01100
01101
01102 static void
01103 cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) {
01104 dns_cache_t *cache = event->ev_arg;
01105 isc_boolean_t should_free = ISC_FALSE;
01106
01107 UNUSED(task);
01108
01109 INSIST(task == cache->cleaner.task);
01110 INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN);
01111
01112 if (CLEANER_BUSY(&cache->cleaner))
01113 end_cleaning(&cache->cleaner, event);
01114 else
01115 isc_event_free(&event);
01116
01117 LOCK(&cache->lock);
01118
01119 cache->live_tasks--;
01120 INSIST(cache->live_tasks == 0);
01121
01122 if (cache->references == 0)
01123 should_free = ISC_TRUE;
01124
01125
01126
01127
01128
01129
01130 if (cache->cleaner.cleaning_timer != NULL)
01131 isc_timer_detach(&cache->cleaner.cleaning_timer);
01132
01133
01134 (void)isc_task_purge(task, NULL, DNS_EVENT_CACHECLEAN, NULL);
01135
01136 UNLOCK(&cache->lock);
01137
01138 if (should_free)
01139 cache_free(cache);
01140 }
01141
01142 isc_result_t
01143 dns_cache_flush(dns_cache_t *cache) {
01144 dns_db_t *db = NULL;
01145 isc_result_t result;
01146
01147 result = cache_create_db(cache, &db);
01148 if (result != ISC_R_SUCCESS)
01149 return (result);
01150
01151 LOCK(&cache->lock);
01152 LOCK(&cache->cleaner.lock);
01153 if (cache->cleaner.state == cleaner_s_idle) {
01154 if (cache->cleaner.iterator != NULL)
01155 dns_dbiterator_destroy(&cache->cleaner.iterator);
01156 (void) dns_db_createiterator(db, ISC_FALSE,
01157 &cache->cleaner.iterator);
01158 } else {
01159 if (cache->cleaner.state == cleaner_s_busy)
01160 cache->cleaner.state = cleaner_s_done;
01161 cache->cleaner.replaceiterator = ISC_TRUE;
01162 }
01163 dns_db_detach(&cache->db);
01164 cache->db = db;
01165 dns_db_setcachestats(cache->db, cache->stats);
01166 UNLOCK(&cache->cleaner.lock);
01167 UNLOCK(&cache->lock);
01168
01169 return (ISC_R_SUCCESS);
01170 }
01171
01172 static isc_result_t
01173 clearnode(dns_db_t *db, dns_dbnode_t *node) {
01174 isc_result_t result;
01175 dns_rdatasetiter_t *iter = NULL;
01176
01177 result = dns_db_allrdatasets(db, node, NULL, (isc_stdtime_t)0, &iter);
01178 if (result != ISC_R_SUCCESS)
01179 return (result);
01180
01181 for (result = dns_rdatasetiter_first(iter);
01182 result == ISC_R_SUCCESS;
01183 result = dns_rdatasetiter_next(iter))
01184 {
01185 dns_rdataset_t rdataset;
01186 dns_rdataset_init(&rdataset);
01187
01188 dns_rdatasetiter_current(iter, &rdataset);
01189 result = dns_db_deleterdataset(db, node, NULL,
01190 rdataset.type, rdataset.covers);
01191 dns_rdataset_disassociate(&rdataset);
01192 if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED)
01193 break;
01194 }
01195
01196 if (result == ISC_R_NOMORE)
01197 result = ISC_R_SUCCESS;
01198
01199 dns_rdatasetiter_destroy(&iter);
01200 return (result);
01201 }
01202
01203 static isc_result_t
01204 cleartree(dns_db_t *db, dns_name_t *name) {
01205 isc_result_t result, answer = ISC_R_SUCCESS;
01206 dns_dbiterator_t *iter = NULL;
01207 dns_dbnode_t *node = NULL;
01208 dns_fixedname_t fnodename;
01209 dns_name_t *nodename;
01210
01211 dns_fixedname_init(&fnodename);
01212 nodename = dns_fixedname_name(&fnodename);
01213
01214 result = dns_db_createiterator(db, 0, &iter);
01215 if (result != ISC_R_SUCCESS)
01216 goto cleanup;
01217
01218 result = dns_dbiterator_seek(iter, name);
01219 if (result != ISC_R_SUCCESS)
01220 goto cleanup;
01221
01222 while (result == ISC_R_SUCCESS) {
01223 result = dns_dbiterator_current(iter, &node, nodename);
01224 if (result == DNS_R_NEWORIGIN)
01225 result = ISC_R_SUCCESS;
01226 if (result != ISC_R_SUCCESS)
01227 goto cleanup;
01228
01229
01230
01231 if (! dns_name_issubdomain(nodename, name))
01232 goto cleanup;
01233
01234
01235
01236
01237 result = clearnode(db, node);
01238 if (result != ISC_R_SUCCESS && answer == ISC_R_SUCCESS)
01239 answer = result;
01240 dns_db_detachnode(db, &node);
01241 result = dns_dbiterator_next(iter);
01242 }
01243
01244 cleanup:
01245 if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND)
01246 result = ISC_R_SUCCESS;
01247 if (result != ISC_R_SUCCESS && answer == ISC_R_SUCCESS)
01248 answer = result;
01249 if (node != NULL)
01250 dns_db_detachnode(db, &node);
01251 if (iter != NULL)
01252 dns_dbiterator_destroy(&iter);
01253
01254 return (answer);
01255 }
01256
01257 isc_result_t
01258 dns_cache_flushname(dns_cache_t *cache, dns_name_t *name) {
01259 return (dns_cache_flushnode(cache, name, ISC_FALSE));
01260 }
01261
01262 isc_result_t
01263 dns_cache_flushnode(dns_cache_t *cache, dns_name_t *name,
01264 isc_boolean_t tree)
01265 {
01266 isc_result_t result;
01267 dns_dbnode_t *node = NULL;
01268 dns_db_t *db = NULL;
01269
01270 if (dns_name_equal(name, dns_rootname))
01271 return (dns_cache_flush(cache));
01272
01273 LOCK(&cache->lock);
01274 if (cache->db != NULL)
01275 dns_db_attach(cache->db, &db);
01276 UNLOCK(&cache->lock);
01277 if (db == NULL)
01278 return (ISC_R_SUCCESS);
01279
01280 if (tree) {
01281 result = cleartree(cache->db, name);
01282 } else {
01283 result = dns_db_findnode(cache->db, name, ISC_FALSE, &node);
01284 if (result == ISC_R_NOTFOUND) {
01285 result = ISC_R_SUCCESS;
01286 goto cleanup_db;
01287 }
01288 if (result != ISC_R_SUCCESS)
01289 goto cleanup_db;
01290 result = clearnode(cache->db, node);
01291 dns_db_detachnode(cache->db, &node);
01292 }
01293
01294 cleanup_db:
01295 dns_db_detach(&db);
01296 return (result);
01297 }
01298
01299 isc_stats_t *
01300 dns_cache_getstats(dns_cache_t *cache) {
01301 REQUIRE(VALID_CACHE(cache));
01302 return (cache->stats);
01303 }
01304
01305 void
01306 dns_cache_updatestats(dns_cache_t *cache, isc_result_t result) {
01307 REQUIRE(VALID_CACHE(cache));
01308 if (cache->stats == NULL)
01309 return;
01310
01311 switch (result) {
01312 case ISC_R_SUCCESS:
01313 case DNS_R_NCACHENXDOMAIN:
01314 case DNS_R_NCACHENXRRSET:
01315 case DNS_R_CNAME:
01316 case DNS_R_DNAME:
01317 case DNS_R_GLUE:
01318 case DNS_R_ZONECUT:
01319 isc_stats_increment(cache->stats,
01320 dns_cachestatscounter_queryhits);
01321 break;
01322 default:
01323 isc_stats_increment(cache->stats,
01324 dns_cachestatscounter_querymisses);
01325 }
01326 }
01327
01328
01329
01330
01331
01332
01333 typedef struct
01334 cache_dumparg {
01335 isc_statsformat_t type;
01336 void *arg;
01337 int ncounters;
01338 int *counterindices;
01339 isc_uint64_t *countervalues;
01340 isc_result_t result;
01341 } cache_dumparg_t;
01342
01343 static void
01344 getcounter(isc_statscounter_t counter, isc_uint64_t val, void *arg) {
01345 cache_dumparg_t *dumparg = arg;
01346
01347 REQUIRE(counter < dumparg->ncounters);
01348 dumparg->countervalues[counter] = val;
01349 }
01350
01351 static void
01352 getcounters(isc_stats_t *stats, isc_statsformat_t type, int ncounters,
01353 int *indices, isc_uint64_t *values)
01354 {
01355 cache_dumparg_t dumparg;
01356
01357 memset(values, 0, sizeof(values[0]) * ncounters);
01358
01359 dumparg.type = type;
01360 dumparg.ncounters = ncounters;
01361 dumparg.counterindices = indices;
01362 dumparg.countervalues = values;
01363
01364 isc_stats_dump(stats, getcounter, &dumparg, ISC_STATSDUMP_VERBOSE);
01365 }
01366
01367 void
01368 dns_cache_dumpstats(dns_cache_t *cache, FILE *fp) {
01369 int indices[dns_cachestatscounter_max];
01370 isc_uint64_t values[dns_cachestatscounter_max];
01371
01372 REQUIRE(VALID_CACHE(cache));
01373
01374 getcounters(cache->stats, isc_statsformat_file,
01375 dns_cachestatscounter_max, indices, values);
01376
01377 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
01378 values[dns_cachestatscounter_hits],
01379 "cache hits");
01380 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
01381 values[dns_cachestatscounter_misses],
01382 "cache misses");
01383 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
01384 values[dns_cachestatscounter_queryhits],
01385 "cache hits (from query)");
01386 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
01387 values[dns_cachestatscounter_querymisses],
01388 "cache misses (from query)");
01389 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
01390 values[dns_cachestatscounter_deletelru],
01391 "cache records deleted due to memory exhaustion");
01392 fprintf(fp, "%20" ISC_PRINT_QUADFORMAT "u %s\n",
01393 values[dns_cachestatscounter_deletettl],
01394 "cache records deleted due to TTL expiration");
01395 fprintf(fp, "%20u %s\n", dns_db_nodecount(cache->db),
01396 "cache database nodes");
01397 fprintf(fp, "%20u %s\n", dns_db_hashsize(cache->db),
01398 "cache database hash buckets");
01399
01400 fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_total(cache->mctx),
01401 "cache tree memory total");
01402 fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_inuse(cache->mctx),
01403 "cache tree memory in use");
01404 fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache->mctx),
01405 "cache tree highest memory in use");
01406
01407 fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_total(cache->hmctx),
01408 "cache heap memory total");
01409 fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_inuse(cache->hmctx),
01410 "cache heap memory in use");
01411 fprintf(fp, "%20u %s\n", (unsigned int) isc_mem_maxinuse(cache->hmctx),
01412 "cache heap highest memory in use");
01413 }
01414
01415 #ifdef HAVE_LIBXML2
01416 #define TRY0(a) do { xmlrc = (a); if (xmlrc < 0) goto error; } while(0)
01417 static int
01418 renderstat(const char *name, isc_uint64_t value, xmlTextWriterPtr writer) {
01419 int xmlrc;
01420
01421 TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "counter"));
01422 TRY0(xmlTextWriterWriteAttribute(writer,
01423 ISC_XMLCHAR "name", ISC_XMLCHAR name));
01424 TRY0(xmlTextWriterWriteFormatString(writer,
01425 "%" ISC_PRINT_QUADFORMAT "u",
01426 value));
01427 TRY0(xmlTextWriterEndElement(writer));
01428
01429 error:
01430 return (xmlrc);
01431 }
01432
01433 int
01434 dns_cache_renderxml(dns_cache_t *cache, xmlTextWriterPtr writer) {
01435 int indices[dns_cachestatscounter_max];
01436 isc_uint64_t values[dns_cachestatscounter_max];
01437 int xmlrc;
01438
01439 REQUIRE(VALID_CACHE(cache));
01440
01441 getcounters(cache->stats, isc_statsformat_file,
01442 dns_cachestatscounter_max, indices, values);
01443 TRY0(renderstat("CacheHits",
01444 values[dns_cachestatscounter_hits], writer));
01445 TRY0(renderstat("CacheMisses",
01446 values[dns_cachestatscounter_misses], writer));
01447 TRY0(renderstat("QueryHits",
01448 values[dns_cachestatscounter_queryhits], writer));
01449 TRY0(renderstat("QueryMisses",
01450 values[dns_cachestatscounter_querymisses], writer));
01451 TRY0(renderstat("DeleteLRU",
01452 values[dns_cachestatscounter_deletelru], writer));
01453 TRY0(renderstat("DeleteTTL",
01454 values[dns_cachestatscounter_deletettl], writer));
01455
01456 TRY0(renderstat("CacheNodes", dns_db_nodecount(cache->db), writer));
01457 TRY0(renderstat("CacheBuckets", dns_db_hashsize(cache->db), writer));
01458
01459 TRY0(renderstat("TreeMemTotal", isc_mem_total(cache->mctx), writer));
01460 TRY0(renderstat("TreeMemInUse", isc_mem_inuse(cache->mctx), writer));
01461 TRY0(renderstat("TreeMemMax", isc_mem_maxinuse(cache->mctx), writer));
01462
01463 TRY0(renderstat("HeapMemTotal", isc_mem_total(cache->hmctx), writer));
01464 TRY0(renderstat("HeapMemInUse", isc_mem_inuse(cache->hmctx), writer));
01465 TRY0(renderstat("HeapMemMax", isc_mem_maxinuse(cache->hmctx), writer));
01466 error:
01467 return (xmlrc);
01468 }
01469 #endif
01470
01471 #ifdef HAVE_JSON
01472 #define CHECKMEM(m) do { \
01473 if (m == NULL) { \
01474 result = ISC_R_NOMEMORY;\
01475 goto error;\
01476 } \
01477 } while(0)
01478
01479 isc_result_t
01480 dns_cache_renderjson(dns_cache_t *cache, json_object *cstats) {
01481 isc_result_t result = ISC_R_SUCCESS;
01482 int indices[dns_cachestatscounter_max];
01483 isc_uint64_t values[dns_cachestatscounter_max];
01484 json_object *obj;
01485
01486 REQUIRE(VALID_CACHE(cache));
01487
01488 getcounters(cache->stats, isc_statsformat_file,
01489 dns_cachestatscounter_max, indices, values);
01490
01491 obj = json_object_new_int64(values[dns_cachestatscounter_hits]);
01492 CHECKMEM(obj);
01493 json_object_object_add(cstats, "CacheHits", obj);
01494
01495 obj = json_object_new_int64(values[dns_cachestatscounter_misses]);
01496 CHECKMEM(obj);
01497 json_object_object_add(cstats, "CacheMisses", obj);
01498
01499 obj = json_object_new_int64(values[dns_cachestatscounter_queryhits]);
01500 CHECKMEM(obj);
01501 json_object_object_add(cstats, "QueryHits", obj);
01502
01503 obj = json_object_new_int64(values[dns_cachestatscounter_querymisses]);
01504 CHECKMEM(obj);
01505 json_object_object_add(cstats, "QueryMisses", obj);
01506
01507 obj = json_object_new_int64(values[dns_cachestatscounter_deletelru]);
01508 CHECKMEM(obj);
01509 json_object_object_add(cstats, "DeleteLRU", obj);
01510
01511 obj = json_object_new_int64(values[dns_cachestatscounter_deletettl]);
01512 CHECKMEM(obj);
01513 json_object_object_add(cstats, "DeleteTTL", obj);
01514
01515 obj = json_object_new_int64(dns_db_nodecount(cache->db));
01516 CHECKMEM(obj);
01517 json_object_object_add(cstats, "CacheNodes", obj);
01518
01519 obj = json_object_new_int64(dns_db_hashsize(cache->db));
01520 CHECKMEM(obj);
01521 json_object_object_add(cstats, "CacheBuckets", obj);
01522
01523 obj = json_object_new_int64(isc_mem_total(cache->mctx));
01524 CHECKMEM(obj);
01525 json_object_object_add(cstats, "TreeMemTotal", obj);
01526
01527 obj = json_object_new_int64(isc_mem_inuse(cache->mctx));
01528 CHECKMEM(obj);
01529 json_object_object_add(cstats, "TreeMemInUse", obj);
01530
01531 obj = json_object_new_int64(isc_mem_maxinuse(cache->mctx));
01532 CHECKMEM(obj);
01533 json_object_object_add(cstats, "HeapMemMax", obj);
01534
01535 obj = json_object_new_int64(isc_mem_total(cache->hmctx));
01536 CHECKMEM(obj);
01537 json_object_object_add(cstats, "HeapMemTotal", obj);
01538
01539 obj = json_object_new_int64(isc_mem_inuse(cache->hmctx));
01540 CHECKMEM(obj);
01541 json_object_object_add(cstats, "HeapMemInUse", obj);
01542
01543 obj = json_object_new_int64(isc_mem_maxinuse(cache->hmctx));
01544 CHECKMEM(obj);
01545 json_object_object_add(cstats, "HeapMemMax", obj);
01546
01547 result = ISC_R_SUCCESS;
01548 error:
01549 return (result);
01550 }
01551 #endif