diff --git a/bin/named/server.c b/bin/named/server.c index ca31f3d01d..a4f5d32d35 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: server.c,v 1.216 2000/08/24 22:15:28 bwelling Exp $ */ +/* $Id: server.c,v 1.217 2000/08/31 12:15:07 marka Exp $ */ #include @@ -406,6 +406,7 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, dns_c_view_t *cview, dns_cache_t *cache = NULL; isc_result_t result; isc_uint32_t cleaning_interval; + isc_uint32_t max_cache_size; dns_tsig_keyring_t *ring; dns_c_iplist_t *forwarders; dns_view_t *pview = NULL; /* Production view */ @@ -470,6 +471,19 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, dns_c_view_t *cview, cleaning_interval = 3600; /* Default is 1 hour. */ dns_cache_setcleaninginterval(cache, cleaning_interval); + result = ISC_R_NOTFOUND; + if (cview != NULL) + result = dns_c_view_getmaxcachesize(cview, &max_cache_size); + if (result != ISC_R_SUCCESS) + result = dns_c_ctx_getmaxcachesize(cctx, &max_cache_size); + if (result != ISC_R_SUCCESS) + max_cache_size = 0; + /* + * XXX remove once rbt if fixed + */ + max_cache_size = 0; + dns_cache_setcachesize(cache, max_cache_size); + dns_cache_detach(&cache); /* diff --git a/lib/dns/cache.c b/lib/dns/cache.c index 58956bc0b5..51beaac096 100644 --- a/lib/dns/cache.c +++ b/lib/dns/cache.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cache.c,v 1.29 2000/08/26 01:36:47 bwelling Exp $ */ +/* $Id: cache.c,v 1.30 2000/08/31 12:15:08 marka Exp $ */ #include @@ -69,11 +69,13 @@ struct cache_cleaner { isc_timer_t *cleaning_timer; isc_event_t *resched_event; /* Sent by cleaner task to itself to reschedule */ + isc_event_t *overmem_event; dns_dbiterator_t *iterator; int increment; /* Number of names to clean in one increment */ cleaner_state_t state; /* Idle/Busy. */ + isc_boolean_t overmem; /* The cache is in a overmem state */ }; /* @@ -117,6 +119,9 @@ incremental_cleaning_action(isc_task_t *task, isc_event_t *event); static void cleaner_shutdown_action(isc_task_t *task, isc_event_t *event); +static void +overmem_cleaning_action(isc_task_t *task, isc_event_t *event); + isc_result_t dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr, dns_rdataclass_t rdclass, @@ -186,9 +191,14 @@ cache_free(dns_cache_t *cache) { REQUIRE(VALID_CACHE(cache)); REQUIRE(cache->references == 0); + isc_mem_setwater(cache->mctx, NULL, NULL, 0, 0); + if (cache->cleaner.task != NULL) isc_task_detach(&cache->cleaner.task); + if (cache->cleaner.overmem_event != NULL) + isc_event_free(&cache->cleaner.overmem_event); + if (cache->cleaner.resched_event != NULL) isc_event_free(&cache->cleaner.resched_event); @@ -236,8 +246,10 @@ dns_cache_detach(dns_cache_t **cachep) { LOCK(&cache->lock); REQUIRE(cache->references > 0); cache->references--; - if (cache->references == 0) + if (cache->references == 0) { + cache->cleaner.overmem = ISC_FALSE; free_cache = ISC_TRUE; + } UNLOCK(&cache->lock); *cachep = NULL; if (free_cache) { @@ -337,10 +349,12 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr, cleaner->state = cleaner_s_idle; cleaner->cache = cache; cleaner->iterator = NULL; + cleaner->overmem = ISC_FALSE; cleaner->task = NULL; cleaner->cleaning_timer = NULL; cleaner->resched_event = NULL; + cleaner->overmem_event = NULL; if (taskmgr != NULL && timermgr != NULL) { result = isc_task_create(taskmgr, 1, &cleaner->task); @@ -387,11 +401,23 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr, result = ISC_R_NOMEMORY; goto cleanup; } + + cleaner->overmem_event = + isc_event_allocate(cache->mctx, cleaner, + DNS_EVENT_CACHEOVERMEM, + overmem_cleaning_action, + cleaner, sizeof(isc_event_t)); + if (cleaner->overmem_event == NULL) { + result = ISC_R_NOMEMORY; + goto cleanup; + } } return (ISC_R_SUCCESS); cleanup: + if (cleaner->resched_event != NULL) + isc_event_free(&cleaner->resched_event); if (cleaner->cleaning_timer != NULL) isc_timer_detach(&cleaner->cleaning_timer); if (cleaner->task != NULL) @@ -479,6 +505,21 @@ cleaning_timer_action(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); } +static void +overmem_cleaning_action(isc_task_t *task, isc_event_t *event) { + cache_cleaner_t *cleaner = event->ev_arg; + + UNUSED(task); + + INSIST(task == cleaner->task); + INSIST(event->ev_type == DNS_EVENT_CACHEOVERMEM); + INSIST(cleaner->overmem_event == NULL); + + if (cleaner->state == cleaner_s_idle) + begin_cleaning(cleaner); + cleaner->overmem_event = event; +} + /* * Do incremental cleaning. */ @@ -547,6 +588,9 @@ incremental_cleaning_action(isc_task_t *task, isc_event_t *event) { } } +#if 0 + pause: +#endif /* * We have successfully performed a cleaning increment. */ @@ -572,6 +616,24 @@ incremental_cleaning_action(isc_task_t *task, isc_event_t *event) { */ end_cleaning(cleaner, event); INSIST(CLEANER_IDLE(cleaner)); + if (cleaner->overmem) { + /* Allow the iterators memory to be freed. */ + if (cleaner->overmem_event != NULL) { + /* XXX remove */ + fprintf(stderr, "overmem: restart\n"); + isc_task_send(cleaner->task, + &cleaner->overmem_event); + } +#if 0 + result = dns_dbiterator_first(cleaner->iterator); + if (result == ISC_R_SUCCESS) { + fprintf(stderr, "overmem: resetting and pausing\n"); + goto pause; + } + fprintf(stderr, "dns_dbiterator_first: %s\n", + dns_result_totext(result)); +#endif + } return; } @@ -583,6 +645,8 @@ dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) { isc_result_t result; dns_dbiterator_t *iterator = NULL; + REQUIRE(VALID_CACHE(cache)); + result = dns_db_createiterator(cache->db, ISC_FALSE, &iterator); if (result != ISC_R_SUCCESS) return result; @@ -626,6 +690,45 @@ dns_cache_clean(dns_cache_t *cache, isc_stdtime_t now) { return result; } +static void +water(void *arg, int mark) { + dns_cache_t *cache = arg; + isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); + + REQUIRE(VALID_CACHE(cache)); + dns_db_overmem(cache->db, overmem); + cache->cleaner.overmem = overmem; + + if (overmem && cache->cleaner.overmem_event != NULL) { + isc_task_send(cache->cleaner.task, + &cache->cleaner.overmem_event); + } +} + +void +dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) { + isc_uint32_t lowater; + isc_uint32_t hiwater; + + REQUIRE(VALID_CACHE(cache)); + +#if 0 + /* Impose a minumum cache size. */ + if (size != 0 && size < 100000) + size = 100000; +#endif + hiwater = size - (size >> 3); /* ~(7/8) */ + lowater = size - (size >> 2); /* ~(3/4) */ + + cache->cleaner.overmem = ISC_FALSE; + dns_db_overmem(cache->db, ISC_FALSE); + if (size == 0 || hiwater == 0 || lowater == 0) { + dns_db_overmem(cache->db, ISC_FALSE); + } else { + isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater); + } +} + /* * The cleaner task is shutting down; do the necessary cleanup. */ diff --git a/lib/dns/db.c b/lib/dns/db.c index 4da890937f..81719ccb16 100644 --- a/lib/dns/db.c +++ b/lib/dns/db.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.c,v 1.54 2000/08/21 22:19:04 bwelling Exp $ */ +/* $Id: db.c,v 1.55 2000/08/31 12:15:09 marka Exp $ */ /*** *** Imports @@ -624,6 +624,14 @@ dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node, type, covers)); } +void +dns_db_overmem(dns_db_t *db, isc_boolean_t overmem) { + + REQUIRE(DNS_DB_VALID(db)); + + (db->methods->overmem)(db, overmem); +} + isc_result_t dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp) { diff --git a/lib/dns/include/dns/cache.h b/lib/dns/include/dns/cache.h index 38f407441d..9af988f938 100644 --- a/lib/dns/include/dns/cache.h +++ b/lib/dns/include/dns/cache.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: cache.h,v 1.13 2000/08/01 01:23:43 tale Exp $ */ +/* $Id: cache.h,v 1.14 2000/08/31 12:15:12 marka Exp $ */ #ifndef DNS_CACHE_H #define DNS_CACHE_H 1 @@ -219,6 +219,12 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int interval); * Set the periodic cache cleaning interval to 'interval' seconds. */ +void +dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size); +/* + * Set cache size. 0 => infinite. + */ + ISC_LANG_ENDDECLS #endif /* DNS_CACHE_H */ diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index 5b15a3fd9a..631f16dde1 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: db.h,v 1.56 2000/08/22 01:20:05 bwelling Exp $ */ +/* $Id: db.h,v 1.57 2000/08/31 12:15:13 marka Exp $ */ #ifndef DNS_DB_H #define DNS_DB_H 1 @@ -140,6 +140,7 @@ typedef struct dns_dbmethods { dns_rdatatype_t type, dns_rdatatype_t covers); isc_boolean_t (*issecure)(dns_db_t *db); + void (*overmem)(dns_db_t *db, isc_boolean_t overmem); unsigned int (*nodecount)(dns_db_t *db); isc_boolean_t (*ispersistent)(dns_db_t *db); } dns_dbmethods_t; @@ -1131,6 +1132,12 @@ dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, isc_uint32_t *serialp); * 'ver' is a valid version. */ +void +dns_db_overmem(dns_db_t *db, isc_boolean_t overmem); +/* + * Enable / disable agressive cache cleaning. + */ + unsigned int dns_db_nodecount(dns_db_t *db); /* diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h index c30583384e..7e4778df45 100644 --- a/lib/dns/include/dns/events.h +++ b/lib/dns/include/dns/events.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: events.h,v 1.29 2000/08/15 03:33:50 marka Exp $ */ +/* $Id: events.h,v 1.30 2000/08/31 12:15:14 marka Exp $ */ #ifndef DNS_EVENTS_H #define DNS_EVENTS_H 1 @@ -53,6 +53,7 @@ #define DNS_EVENT_ZONE (ISC_EVENTCLASS_DNS + 24) #define DNS_EVENT_ZONESTARTXFRIN (ISC_EVENTCLASS_DNS + 25) #define DNS_EVENT_MASTERQUANTUM (ISC_EVENTCLASS_DNS + 26) +#define DNS_EVENT_CACHEOVERMEM (ISC_EVENTCLASS_DNS + 27) #define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0) #define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index d93c986fb5..7a93853f49 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: rbtdb.c,v 1.121 2000/08/26 01:36:52 bwelling Exp $ */ +/* $Id: rbtdb.c,v 1.122 2000/08/31 12:15:11 marka Exp $ */ /* * Principal Author: Bob Halley @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -164,6 +165,8 @@ typedef struct { rbtdb_version_t * current_version; rbtdb_version_t * future_version; rbtdb_versionlist_t open_versions; + isc_boolean_t overmem; + isc_random_t random; /* Locked by tree_lock. */ dns_rbt_t * tree; isc_boolean_t secure; @@ -327,6 +330,7 @@ free_rbtdb(dns_rbtdb_t *rbtdb) { REQUIRE(EMPTY(rbtdb->open_versions)); REQUIRE(rbtdb->future_version == NULL); + isc_random_invalidate(&rbtdb->random); if (rbtdb->current_version != NULL) isc_mem_put(rbtdb->common.mctx, rbtdb->current_version, sizeof (rbtdb_version_t)); @@ -2710,6 +2714,7 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; dns_rbtnode_t *rbtnode = node; rdatasetheader_t *header; + isc_uint32_t val; REQUIRE(VALID_RBTDB(rbtdb)); @@ -2728,6 +2733,17 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { */ header->attributes |= RDATASET_ATTR_STALE; rbtnode->dirty = 1; + if (rbtdb->overmem) + fprintf(stderr, "overmem stale\n"); + } else if (rbtdb->overmem) { + isc_random_get(&rbtdb->random, &val); + if ((val % 7) == 0) { + fprintf(stderr, "overmem expire\n"); + header->ttl = 0; + header->attributes |= RDATASET_ATTR_STALE; + rbtnode->dirty = 1; + } else + fprintf(stderr, "overmem skip\n"); } } @@ -2736,6 +2752,15 @@ expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { return (ISC_R_SUCCESS); } +static void +overmem(dns_db_t *db, isc_boolean_t overmem) { + dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; + + if ((rbtdb->common.attributes & DNS_DBATTR_CACHE) != 0) { + rbtdb->overmem = overmem; + } +} + static void printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db; @@ -3826,7 +3851,8 @@ static dns_dbmethods_t zone_methods = { deleterdataset, issecure, nodecount, - ispersistent + ispersistent, + overmem }; static dns_dbmethods_t cache_methods = { @@ -3854,7 +3880,8 @@ static dns_dbmethods_t cache_methods = { deleterdataset, issecure, nodecount, - ispersistent + ispersistent, + overmem }; isc_result_t @@ -4003,6 +4030,8 @@ dns_rbtdb_create rbtdb->references = 1; rbtdb->attributes = 0; rbtdb->secure = ISC_FALSE; + rbtdb->overmem = ISC_FALSE; + isc_random_init(&rbtdb->random); /* * Version Initialization. diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h index 5e1d77fe3b..b07cc645aa 100644 --- a/lib/isc/include/isc/mem.h +++ b/lib/isc/include/isc/mem.h @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.h,v 1.40 2000/08/01 01:30:27 tale Exp $ */ +/* $Id: mem.h,v 1.41 2000/08/31 12:15:17 marka Exp $ */ #ifndef ISC_MEM_H #define ISC_MEM_H 1 @@ -28,6 +28,10 @@ ISC_LANG_BEGINDECLS +#define ISC_MEM_LOWATER 0 +#define ISC_MEM_HIWATER 1 +typedef void (*isc_mem_water_t)(void *, int); + typedef void * (*isc_memalloc_t)(void *, size_t); typedef void (*isc_memfree_t)(void *, void *); @@ -147,6 +151,24 @@ isc_result_t isc_mem_createx(size_t, size_t, void *arg, isc_mem_t **); isc_result_t isc_mem_restore(isc_mem_t *); +void +isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater); +/* + * Set high and low water marks for this memory context. When the memory + * usage of 'mctx' exceeds 'hiwater', '(water)(water_arg, ISC_MEM_HIWATER)' + * will be called. When the usage drops below 'lowater', 'water' will + * again be called, this time with ISC_MEM_LOWATER. + * + * Requires: + * If 'water' is NULL then 'water_arg', 'hi_water' and 'lo_water' are + * ignored and the state is reset otherwise. + * 'water' to point to a valid function. + * 'hi_water > lo_water' + * 'lo_water != 0' + * 'hi_water != 0' + */ + /* * Memory pools */ diff --git a/lib/isc/mem.c b/lib/isc/mem.c index 833d47f68f..977732d81c 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.c,v 1.60 2000/08/26 01:23:12 bwelling Exp $ */ +/* $Id: mem.c,v 1.61 2000/08/31 12:15:16 marka Exp $ */ #include @@ -118,6 +118,11 @@ struct isc_mem { size_t quota; size_t total; size_t inuse; + size_t hi_water; + size_t lo_water; + isc_boolean_t hi_called; + isc_mem_water_t water; + void * water_arg; ISC_LIST(isc_mempool_t) pools; #ifdef ISC_MEM_TRACKLINES ISC_LIST(debuglink_t) debuglist; @@ -651,6 +656,11 @@ isc_mem_createx(size_t init_max_size, size_t target_size, ctx->quota = 0; ctx->total = 0; ctx->inuse = 0; + ctx->hi_water = 0; + ctx->lo_water = 0; + ctx->hi_called = ISC_FALSE; + ctx->water = NULL; + ctx->water_arg = NULL; ctx->magic = MEM_MAGIC; isc_ondestroy_init(&ctx->ondestroy); ISC_LIST_INIT(ctx->pools); @@ -813,26 +823,61 @@ check_overrun(void *mem, size_t size, size_t new_size) { void * isc__mem_get(isc_mem_t *ctx, size_t size FLARG) { void *ptr; + isc_boolean_t call_water = ISC_FALSE; REQUIRE(VALID_CONTEXT(ctx)); LOCK(&ctx->lock); ptr = mem_getunlocked(ctx, size); ADD_TRACE(ctx, ptr, size, file, line); + if (ctx->hi_water != 0 && !ctx->hi_called && + ctx->inuse > ctx->hi_water) { + ctx->hi_called = ISC_TRUE; + call_water = ISC_TRUE; + } UNLOCK(&ctx->lock); + + /* XXX remove */ + if (ctx->hi_water) + fprintf(stderr,"inuse %u, total %u\n", ctx->inuse, ctx->total); + + if (call_water) { + /* XXX remove */ + fprintf(stderr, "calling water(%p,ISC_MEM_HIWATER)\n", + ctx->water_arg); + (ctx->water)(ctx->water_arg, ISC_MEM_HIWATER); + } + return (ptr); } void isc__mem_put(isc_mem_t *ctx, void *ptr, size_t size FLARG) { + isc_boolean_t call_water = ISC_FALSE; + REQUIRE(VALID_CONTEXT(ctx)); REQUIRE(ptr != NULL); LOCK(&ctx->lock); DELETE_TRACE(ctx, ptr, size, file, line); mem_putunlocked(ctx, ptr, size); + if (ctx->hi_called && ctx->inuse < ctx->lo_water) { + ctx->hi_called = ISC_FALSE; + call_water = ISC_TRUE; + } UNLOCK(&ctx->lock); + + /* XXX remove */ + if (ctx->hi_water) + fprintf(stderr,"inuse %u, total %u\n", ctx->inuse, ctx->total); + + if (call_water) { + /* XXX remove */ + fprintf(stderr, "calling water(%p,ISC_MEM_LOWATER)\n", + ctx->water_arg); + (ctx->water)(ctx->water_arg, ISC_MEM_LOWATER); + } } isc_result_t @@ -1083,6 +1128,35 @@ isc_mem_inuse(isc_mem_t *ctx) { return (inuse); } +void +isc_mem_setwater(isc_mem_t *ctx, isc_mem_water_t water, void *water_arg, + size_t hiwater, size_t lowater) +{ + REQUIRE(VALID_CONTEXT(ctx)); + + if (water != NULL) { + REQUIRE(hiwater > lowater); + REQUIRE(hiwater > 0); + REQUIRE(lowater > 0); + } + + LOCK(&ctx->lock); + if (water == NULL) { + ctx->water = NULL; + ctx->water_arg = NULL; + ctx->hi_water = NULL; + ctx->lo_water = NULL; + ctx->hi_called = ISC_FALSE; + } else { + ctx->water = water; + ctx->water_arg = water_arg; + ctx->hi_water = hiwater; + ctx->lo_water = lowater; + ctx->hi_called = ISC_FALSE; + } + UNLOCK(&ctx->lock); +} + /* * Memory pool stuff */