mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-08 04:02:05 -04:00
2526. [func] New named option "attach-cache" that allows multiple
views to share a single cache to save memory and improve lookup efficiency. [RT 18905]
This commit is contained in:
parent
2cc6eb92f9
commit
7781f25078
11 changed files with 664 additions and 122 deletions
4
CHANGES
4
CHANGES
|
|
@ -1,3 +1,7 @@
|
|||
2526. [func] New named option "attach-cache" that allows multiple
|
||||
views to share a single cache to save memory and
|
||||
improve lookup efficiency. [RT 18905]
|
||||
|
||||
2525. [func] New logging category "query-errors" to provide detailed
|
||||
internal information about query failures, especially
|
||||
about server failures. [RT #19027]
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: server.h,v 1.93 2008/04/03 05:55:51 marka Exp $ */
|
||||
/* $Id: server.h,v 1.94 2009/01/09 22:24:36 jinmei Exp $ */
|
||||
|
||||
#ifndef NAMED_SERVER_H
|
||||
#define NAMED_SERVER_H 1
|
||||
|
|
@ -91,6 +91,7 @@ struct ns_server {
|
|||
isc_boolean_t flushonshutdown;
|
||||
isc_boolean_t log_queries; /*%< For BIND 8 compatibility */
|
||||
|
||||
ns_cachelist_t cachelist; /*%< Possibly shared caches */
|
||||
dns_stats_t * nsstats; /*%< Server statistics */
|
||||
dns_stats_t * rcvquerystats; /*% Incoming query statistics */
|
||||
dns_stats_t * opcodestats; /*%< Incoming message statistics */
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: types.h,v 1.29 2008/01/17 23:46:59 tbox Exp $ */
|
||||
/* $Id: types.h,v 1.30 2009/01/09 22:24:36 jinmei Exp $ */
|
||||
|
||||
#ifndef NAMED_TYPES_H
|
||||
#define NAMED_TYPES_H 1
|
||||
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include <dns/types.h>
|
||||
|
||||
typedef struct ns_cache ns_cache_t;
|
||||
typedef ISC_LIST(ns_cache_t) ns_cachelist_t;
|
||||
typedef struct ns_client ns_client_t;
|
||||
typedef struct ns_clientmgr ns_clientmgr_t;
|
||||
typedef struct ns_query ns_query_t;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: server.c,v 1.522 2008/12/25 02:02:39 jinmei Exp $ */
|
||||
/* $Id: server.c,v 1.523 2009/01/09 22:24:36 jinmei Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
|
@ -142,6 +142,14 @@
|
|||
fatal(msg, result); \
|
||||
} while (0) \
|
||||
|
||||
/*%
|
||||
* Maximum ADB size for views that share a cache. Use this limit to suppress
|
||||
* the total of memory footprint, which should be the main reason for sharing
|
||||
* a cache. Only effective when a finite max-cache-size is specified.
|
||||
* This is currently defined to be 8MB.
|
||||
*/
|
||||
#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608
|
||||
|
||||
struct ns_dispatch {
|
||||
isc_sockaddr_t addr;
|
||||
unsigned int dispatchgen;
|
||||
|
|
@ -149,6 +157,14 @@ struct ns_dispatch {
|
|||
ISC_LINK(struct ns_dispatch) link;
|
||||
};
|
||||
|
||||
struct ns_cache {
|
||||
dns_cache_t *cache;
|
||||
dns_view_t *primaryview;
|
||||
isc_boolean_t needflush;
|
||||
isc_boolean_t adbsizeadjusted;
|
||||
ISC_LINK(ns_cache_t) link;
|
||||
};
|
||||
|
||||
struct dumpcontext {
|
||||
isc_mem_t *mctx;
|
||||
isc_boolean_t dumpcache;
|
||||
|
|
@ -973,6 +989,63 @@ setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
|
|||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static ns_cache_t *
|
||||
cachelist_find(ns_cachelist_t *cachelist, const char *cachename) {
|
||||
ns_cache_t *nsc;
|
||||
|
||||
for (nsc = ISC_LIST_HEAD(*cachelist);
|
||||
nsc != NULL;
|
||||
nsc = ISC_LIST_NEXT(nsc, link)) {
|
||||
if (strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
|
||||
return (nsc);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
cache_reusable(dns_view_t *originview, dns_view_t *view,
|
||||
isc_boolean_t new_zero_no_soattl)
|
||||
{
|
||||
if (originview->checknames != view->checknames ||
|
||||
dns_resolver_getzeronosoattl(originview->resolver) !=
|
||||
new_zero_no_soattl ||
|
||||
originview->acceptexpired != view->acceptexpired ||
|
||||
originview->enablevalidation != view->enablevalidation ||
|
||||
originview->maxcachettl != view->maxcachettl ||
|
||||
originview->maxncachettl != view->maxncachettl) {
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
static isc_boolean_t
|
||||
cache_sharable(dns_view_t *originview, dns_view_t *view,
|
||||
isc_boolean_t new_zero_no_soattl,
|
||||
unsigned int new_cleaning_interval,
|
||||
isc_uint32_t new_max_cache_size)
|
||||
{
|
||||
/*
|
||||
* If the cache cannot even reused for the same view, it cannot be
|
||||
* shared with other views.
|
||||
*/
|
||||
if (!cache_reusable(originview, view, new_zero_no_soattl))
|
||||
return (ISC_FALSE);
|
||||
|
||||
/*
|
||||
* Check other cache related parameters that must be consistent among
|
||||
* the sharing views.
|
||||
*/
|
||||
if (dns_cache_getcleaninginterval(originview->cache) !=
|
||||
new_cleaning_interval ||
|
||||
dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
|
||||
return (ISC_FALSE);
|
||||
}
|
||||
|
||||
return (ISC_TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Configure 'view' according to 'vconfig', taking defaults from 'config'
|
||||
* where values are missing in 'vconfig'.
|
||||
|
|
@ -982,8 +1055,9 @@ setquerystats(dns_zone_t *zone, isc_mem_t *mctx, isc_boolean_t on) {
|
|||
*/
|
||||
static isc_result_t
|
||||
configure_view(dns_view_t *view, const cfg_obj_t *config,
|
||||
const cfg_obj_t *vconfig, isc_mem_t *mctx,
|
||||
cfg_aclconfctx_t *actx, isc_boolean_t need_hints)
|
||||
const cfg_obj_t *vconfig, ns_cachelist_t *cachelist,
|
||||
isc_mem_t *mctx, cfg_aclconfctx_t *actx,
|
||||
isc_boolean_t need_hints)
|
||||
{
|
||||
const cfg_obj_t *maps[4];
|
||||
const cfg_obj_t *cfgmaps[3];
|
||||
|
|
@ -1005,6 +1079,7 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
dns_cache_t *cache = NULL;
|
||||
isc_result_t result;
|
||||
isc_uint32_t max_adb_size;
|
||||
unsigned int cleaning_interval;
|
||||
isc_uint32_t max_cache_size;
|
||||
isc_uint32_t max_acache_size;
|
||||
isc_uint32_t lame_ttl;
|
||||
|
|
@ -1014,8 +1089,10 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
dns_dispatch_t *dispatch4 = NULL;
|
||||
dns_dispatch_t *dispatch6 = NULL;
|
||||
isc_boolean_t reused_cache = ISC_FALSE;
|
||||
isc_boolean_t shared_cache = ISC_FALSE;
|
||||
int i;
|
||||
const char *str;
|
||||
const char *cachename = NULL;
|
||||
dns_order_t *order = NULL;
|
||||
isc_uint32_t udpsize;
|
||||
unsigned int resopts = 0;
|
||||
|
|
@ -1029,6 +1106,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
const cfg_obj_t *disablelist = NULL;
|
||||
dns_stats_t *resstats = NULL;
|
||||
dns_stats_t *resquerystats = NULL;
|
||||
ns_cache_t *nsc;
|
||||
isc_boolean_t zero_no_soattl;
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
|
|
@ -1170,59 +1249,13 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
#endif
|
||||
|
||||
/*
|
||||
* Configure the view's cache. Try to reuse an existing
|
||||
* cache if possible, otherwise create a new cache.
|
||||
* Note that the ADB is not preserved in either case.
|
||||
* When a matching view is found, the associated statistics are
|
||||
* also retrieved and reused.
|
||||
*
|
||||
* XXX Determining when it is safe to reuse a cache is
|
||||
* tricky. When the view's configuration changes, the cached
|
||||
* data may become invalid because it reflects our old
|
||||
* view of the world. As more view attributes become
|
||||
* configurable, we will have to add code here to check
|
||||
* whether they have changed in ways that could
|
||||
* invalidate the cache.
|
||||
* Obtain configuration parameters that affect the decision of whether
|
||||
* we can reuse/share an existing cache.
|
||||
*/
|
||||
result = dns_viewlist_find(&ns_g_server->viewlist,
|
||||
view->name, view->rdclass,
|
||||
&pview);
|
||||
if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
if (pview != NULL) {
|
||||
INSIST(pview->cache != NULL);
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(3),
|
||||
"reusing existing cache");
|
||||
reused_cache = ISC_TRUE;
|
||||
dns_cache_attach(pview->cache, &cache);
|
||||
dns_view_getresstats(pview, &resstats);
|
||||
dns_view_getresquerystats(pview, &resquerystats);
|
||||
dns_view_detach(&pview);
|
||||
} else {
|
||||
CHECK(isc_mem_create(0, 0, &cmctx));
|
||||
CHECK(dns_cache_create(cmctx, ns_g_taskmgr, ns_g_timermgr,
|
||||
view->rdclass, "rbt", 0, NULL, &cache));
|
||||
isc_mem_setname(cmctx, "cache", NULL);
|
||||
}
|
||||
dns_view_setcache(view, cache);
|
||||
|
||||
/*
|
||||
* cache-file cannot be inherited if views are present, but this
|
||||
* should be caught by the configuration checking stage.
|
||||
*/
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "cache-file", &obj);
|
||||
if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
|
||||
CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
|
||||
if (!reused_cache)
|
||||
CHECK(dns_cache_load(cache));
|
||||
}
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "cleaning-interval", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_cache_setcleaninginterval(cache, cfg_obj_asuint32(obj) * 60);
|
||||
cleaning_interval = cfg_obj_asuint32(obj) * 60;
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "max-cache-size", &obj);
|
||||
|
|
@ -1244,13 +1277,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
}
|
||||
max_cache_size = (isc_uint32_t)value;
|
||||
}
|
||||
dns_cache_setcachesize(cache, max_cache_size);
|
||||
|
||||
dns_cache_detach(&cache);
|
||||
|
||||
/*
|
||||
* Check-names.
|
||||
*/
|
||||
/* Check-names. */
|
||||
obj = NULL;
|
||||
result = ns_checknames_get(maps, "response", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
|
|
@ -1268,6 +1296,159 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
} else
|
||||
INSIST(0);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
zero_no_soattl = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "dnssec-accept-expired", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->acceptexpired = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "dnssec-validation", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->enablevalidation = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "max-cache-ttl", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->maxcachettl = cfg_obj_asuint32(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "max-ncache-ttl", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->maxncachettl = cfg_obj_asuint32(obj);
|
||||
if (view->maxncachettl > 7 * 24 * 3600)
|
||||
view->maxncachettl = 7 * 24 * 3600;
|
||||
|
||||
/*
|
||||
* Configure the view's cache.
|
||||
*
|
||||
* First, check to see if there are any attach-cache options. If yes,
|
||||
* attempt to lookup an existing cache at attach it to the view. If
|
||||
* there is not one, then try to reuse an existing cache if possible;
|
||||
* otherwise create a new cache.
|
||||
*
|
||||
* Note that the ADB is not preserved or shared in either case.
|
||||
*
|
||||
* When a matching view is found, the associated statistics are also
|
||||
* retrieved and reused.
|
||||
*
|
||||
* XXX Determining when it is safe to reuse or share a cache is tricky.
|
||||
* When the view's configuration changes, the cached data may become
|
||||
* invalid because it reflects our old view of the world. We check
|
||||
* some of the configuration parameters that could invalidate the cache
|
||||
* or otherwise make it unsharable, but there are other configuration
|
||||
* options that should be checked. For example, if a view uses a
|
||||
* forwarder, changes in the forwarder configuration may invalidate
|
||||
* the cache. At the moment, it's the administrator's responsibility to
|
||||
* ensure these configuration options don't invalidate reusing/sharing.
|
||||
*/
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "attach-cache", &obj);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
cachename = cfg_obj_asstring(obj);
|
||||
else
|
||||
cachename = view->name;
|
||||
cache = NULL;
|
||||
nsc = cachelist_find(cachelist, cachename);
|
||||
if (nsc != NULL) {
|
||||
if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
|
||||
cleaning_interval, max_cache_size)) {
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
|
||||
"views %s and %s can't share the cache "
|
||||
"due to configuration parameter mismatch",
|
||||
nsc->primaryview->name, view->name);
|
||||
result = ISC_R_FAILURE;
|
||||
goto cleanup;
|
||||
}
|
||||
dns_cache_attach(nsc->cache, &cache);
|
||||
shared_cache = ISC_TRUE;
|
||||
} else {
|
||||
if (strcmp(cachename, view->name) == 0) {
|
||||
result = dns_viewlist_find(&ns_g_server->viewlist,
|
||||
cachename, view->rdclass,
|
||||
&pview);
|
||||
if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
if (pview != NULL) {
|
||||
if (cache_reusable(pview, view,
|
||||
zero_no_soattl)) {
|
||||
isc_log_write(ns_g_lctx,
|
||||
NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER,
|
||||
ISC_LOG_DEBUG(1),
|
||||
"cache cannot be reused "
|
||||
"for view %s due to "
|
||||
"configuration parameter "
|
||||
"mismatch", view->name);
|
||||
} else {
|
||||
INSIST(pview->cache != NULL);
|
||||
isc_log_write(ns_g_lctx,
|
||||
NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER,
|
||||
ISC_LOG_DEBUG(3),
|
||||
"reusing existing cache");
|
||||
reused_cache = ISC_TRUE;
|
||||
dns_cache_attach(pview->cache, &cache);
|
||||
}
|
||||
dns_view_getresstats(pview, &resstats);
|
||||
dns_view_getresquerystats(pview,
|
||||
&resquerystats);
|
||||
dns_view_detach(&pview);
|
||||
}
|
||||
}
|
||||
if (cache == NULL) {
|
||||
/*
|
||||
* Create a cache with the desired name. This normally
|
||||
* equals the view name, but may also be a forward
|
||||
* reference to a view that share the cache with this
|
||||
* view but is not yet configured. If it is not the
|
||||
* view name but not a forward reference either, then it
|
||||
* is simply a named cache that is not shared.
|
||||
*/
|
||||
CHECK(isc_mem_create(0, 0, &cmctx));
|
||||
isc_mem_setname(cmctx, "cache", NULL);
|
||||
CHECK(dns_cache_create2(cmctx, ns_g_taskmgr,
|
||||
ns_g_timermgr, view->rdclass,
|
||||
cachename, "rbt", 0, NULL,
|
||||
&cache));
|
||||
}
|
||||
nsc = isc_mem_get(mctx, sizeof(*nsc));
|
||||
if (nsc == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup;
|
||||
}
|
||||
nsc->cache = NULL;
|
||||
dns_cache_attach(cache, &nsc->cache);
|
||||
nsc->primaryview = view;
|
||||
nsc->needflush = ISC_FALSE;
|
||||
nsc->adbsizeadjusted = ISC_FALSE;
|
||||
ISC_LINK_INIT(nsc, link);
|
||||
ISC_LIST_APPEND(*cachelist, nsc, link);
|
||||
}
|
||||
dns_view_setcache2(view, cache, shared_cache);
|
||||
|
||||
/*
|
||||
* cache-file cannot be inherited if views are present, but this
|
||||
* should be caught by the configuration checking stage.
|
||||
*/
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "cache-file", &obj);
|
||||
if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
|
||||
CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
|
||||
if (!reused_cache && !shared_cache)
|
||||
CHECK(dns_cache_load(cache));
|
||||
}
|
||||
|
||||
dns_cache_setcleaninginterval(cache, cleaning_interval);
|
||||
dns_cache_setcachesize(cache, max_cache_size);
|
||||
|
||||
dns_cache_detach(&cache);
|
||||
|
||||
/*
|
||||
* Resolver.
|
||||
*
|
||||
|
|
@ -1301,13 +1482,23 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
dns_view_setresquerystats(view, resquerystats);
|
||||
|
||||
/*
|
||||
* Set the ADB cache size to 1/8th of the max-cache-size.
|
||||
* Set the ADB cache size to 1/8th of the max-cache-size or
|
||||
* MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
|
||||
*/
|
||||
max_adb_size = 0;
|
||||
if (max_cache_size != 0) {
|
||||
max_adb_size = max_cache_size / 8;
|
||||
if (max_adb_size == 0)
|
||||
max_adb_size = 1; /* Force minimum. */
|
||||
if (view != nsc->primaryview &&
|
||||
max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
|
||||
max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
|
||||
if (!nsc->adbsizeadjusted) {
|
||||
dns_adb_setadbsize(nsc->primaryview->adb,
|
||||
MAX_ADB_SIZE_FOR_CACHESHARE);
|
||||
nsc->adbsizeadjusted = ISC_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
dns_adb_setadbsize(view->adb, max_adb_size);
|
||||
|
||||
|
|
@ -1322,10 +1513,8 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
lame_ttl = 1800;
|
||||
dns_resolver_setlamettl(view->resolver, lame_ttl);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "zero-no-soa-ttl-cache", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_resolver_setzeronosoattl(view->resolver, cfg_obj_asboolean(obj));
|
||||
/* Specify whether to use 0-TTL for negative response for SOA query */
|
||||
dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
|
||||
|
||||
/*
|
||||
* Set the resolver's EDNS UDP size.
|
||||
|
|
@ -1661,16 +1850,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->enablednssec = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "dnssec-accept-expired", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->acceptexpired = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "dnssec-validation", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->enablevalidation = cfg_obj_asboolean(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "dnssec-lookaside", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
|
|
@ -1725,18 +1904,6 @@ configure_view(dns_view_t *view, const cfg_obj_t *config,
|
|||
if (result == ISC_R_SUCCESS)
|
||||
CHECK(mustbesecure(obj, view->resolver));
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "max-cache-ttl", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->maxcachettl = cfg_obj_asuint32(obj);
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "max-ncache-ttl", &obj);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
view->maxncachettl = cfg_obj_asuint32(obj);
|
||||
if (view->maxncachettl > 7 * 24 * 3600)
|
||||
view->maxncachettl = 7 * 24 * 3600;
|
||||
|
||||
obj = NULL;
|
||||
result = ns_config_get(maps, "preferred-glue", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
|
|
@ -2893,10 +3060,13 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||
isc_uint32_t interface_interval;
|
||||
isc_uint32_t reserved;
|
||||
isc_uint32_t udpsize;
|
||||
ns_cachelist_t cachelist, tmpcachelist;
|
||||
unsigned int maxsocks;
|
||||
ns_cache_t *nsc;
|
||||
|
||||
cfg_aclconfctx_init(&aclconfctx);
|
||||
ISC_LIST_INIT(viewlist);
|
||||
ISC_LIST_INIT(cachelist);
|
||||
|
||||
/* Ensure exclusive access to configuration data. */
|
||||
result = isc_task_beginexclusive(server->task);
|
||||
|
|
@ -3283,7 +3453,7 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||
|
||||
CHECK(create_view(vconfig, &viewlist, &view));
|
||||
INSIST(view != NULL);
|
||||
CHECK(configure_view(view, config, vconfig,
|
||||
CHECK(configure_view(view, config, vconfig, &cachelist,
|
||||
ns_g_mctx, &aclconfctx, ISC_TRUE));
|
||||
dns_view_freeze(view);
|
||||
dns_view_detach(&view);
|
||||
|
|
@ -3301,7 +3471,7 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||
* In either case, we need to configure and freeze it.
|
||||
*/
|
||||
CHECK(create_view(NULL, &viewlist, &view));
|
||||
CHECK(configure_view(view, config, NULL, ns_g_mctx,
|
||||
CHECK(configure_view(view, config, NULL, &cachelist, ns_g_mctx,
|
||||
&aclconfctx, ISC_TRUE));
|
||||
dns_view_freeze(view);
|
||||
dns_view_detach(&view);
|
||||
|
|
@ -3320,8 +3490,8 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||
{
|
||||
const cfg_obj_t *vconfig = cfg_listelt_value(element);
|
||||
CHECK(create_view(vconfig, &viewlist, &view));
|
||||
CHECK(configure_view(view, config, vconfig, ns_g_mctx,
|
||||
&aclconfctx, ISC_FALSE));
|
||||
CHECK(configure_view(view, config, vconfig, &cachelist,
|
||||
ns_g_mctx, &aclconfctx, ISC_FALSE));
|
||||
dns_view_freeze(view);
|
||||
dns_view_detach(&view);
|
||||
view = NULL;
|
||||
|
|
@ -3334,6 +3504,13 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||
server->viewlist = viewlist;
|
||||
viewlist = tmpviewlist;
|
||||
|
||||
/*
|
||||
* Swap our new cache list with the production one.
|
||||
*/
|
||||
tmpcachelist = server->cachelist;
|
||||
server->cachelist = cachelist;
|
||||
cachelist = tmpcachelist;
|
||||
|
||||
/*
|
||||
* Load the TKEY information from the configuration.
|
||||
*/
|
||||
|
|
@ -3625,6 +3802,13 @@ load_configuration(const char *filename, ns_server_t *server,
|
|||
dns_view_detach(&view);
|
||||
}
|
||||
|
||||
/* Same cleanup for cache list. */
|
||||
while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
|
||||
ISC_LIST_UNLINK(cachelist, nsc, link);
|
||||
dns_cache_detach(&nsc->cache);
|
||||
isc_mem_put(server->mctx, nsc, sizeof(*nsc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the listening interfaces in accordance with the source
|
||||
* addresses specified in views and zones.
|
||||
|
|
@ -3770,6 +3954,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
|
|||
dns_view_t *view, *view_next;
|
||||
ns_server_t *server = (ns_server_t *)event->ev_arg;
|
||||
isc_boolean_t flush = server->flushonshutdown;
|
||||
ns_cache_t *nsc;
|
||||
|
||||
UNUSED(task);
|
||||
INSIST(task == server->task);
|
||||
|
|
@ -3799,6 +3984,12 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
|
|||
dns_view_detach(&view);
|
||||
}
|
||||
|
||||
while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
|
||||
ISC_LIST_UNLINK(server->cachelist, nsc, link);
|
||||
dns_cache_detach(&nsc->cache);
|
||||
isc_mem_put(server->mctx, nsc, sizeof(*nsc));
|
||||
}
|
||||
|
||||
isc_timer_detach(&server->interface_timer);
|
||||
isc_timer_detach(&server->heartbeat_timer);
|
||||
isc_timer_detach(&server->pps_timer);
|
||||
|
|
@ -3953,6 +4144,8 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
|
|||
|
||||
ISC_LIST_INIT(server->statschannels);
|
||||
|
||||
ISC_LIST_INIT(server->cachelist);
|
||||
|
||||
server->magic = NS_SERVER_MAGIC;
|
||||
*serverp = server;
|
||||
}
|
||||
|
|
@ -3991,6 +4184,7 @@ ns_server_destroy(ns_server_t **serverp) {
|
|||
isc_event_free(&server->reload_event);
|
||||
|
||||
INSIST(ISC_LIST_EMPTY(server->viewlist));
|
||||
INSIST(ISC_LIST_EMPTY(server->cachelist));
|
||||
|
||||
dns_aclenv_destroy(&server->aclenv);
|
||||
|
||||
|
|
@ -4652,15 +4846,23 @@ dumpdone(void *arg, isc_result_t result) {
|
|||
nextview:
|
||||
fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
|
||||
resume:
|
||||
if (dctx->zone == NULL && dctx->cache == NULL && dctx->dumpcache) {
|
||||
if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
|
||||
fprintf(dctx->fp,
|
||||
";\n; Cache of view '%s' is shared as '%s'\n",
|
||||
dctx->view->view->name,
|
||||
dns_cache_getname(dctx->view->view->cache));
|
||||
} else if (dctx->zone == NULL && dctx->cache == NULL &&
|
||||
dctx->dumpcache)
|
||||
{
|
||||
style = &dns_master_style_cache;
|
||||
/* start cache dump */
|
||||
if (dctx->view->view->cachedb != NULL)
|
||||
dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
|
||||
if (dctx->cache != NULL) {
|
||||
|
||||
fprintf(dctx->fp, ";\n; Cache dump of view '%s'\n;\n",
|
||||
dctx->view->view->name);
|
||||
fprintf(dctx->fp,
|
||||
";\n; Cache dump of view '%s' (cache %s)\n;\n",
|
||||
dctx->view->view->name,
|
||||
dns_cache_getname(dctx->view->view->cache));
|
||||
result = dns_master_dumptostreaminc(dctx->mctx,
|
||||
dctx->cache, NULL,
|
||||
style, dctx->fp,
|
||||
|
|
@ -4937,6 +5139,7 @@ ns_server_flushcache(ns_server_t *server, char *args) {
|
|||
isc_boolean_t flushed;
|
||||
isc_boolean_t found;
|
||||
isc_result_t result;
|
||||
ns_cache_t *nsc;
|
||||
|
||||
/* Skip the command name. */
|
||||
ptr = next_token(&args, " \t");
|
||||
|
|
@ -4950,22 +5153,96 @@ ns_server_flushcache(ns_server_t *server, char *args) {
|
|||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
flushed = ISC_TRUE;
|
||||
found = ISC_FALSE;
|
||||
for (view = ISC_LIST_HEAD(server->viewlist);
|
||||
view != NULL;
|
||||
view = ISC_LIST_NEXT(view, link))
|
||||
{
|
||||
if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Flushing a cache is tricky when caches are shared by multiple views.
|
||||
* We first identify which caches should be flushed in the local cache
|
||||
* list, flush these caches, and then update other views that refer to
|
||||
* the flushed cache DB.
|
||||
*/
|
||||
if (viewname != NULL) {
|
||||
/*
|
||||
* Mark caches that need to be flushed. This is an O(#view^2)
|
||||
* operation in the very worst case, but should be normally
|
||||
* much more lightweight because only a few (most typically just
|
||||
* one) views will match.
|
||||
*/
|
||||
for (view = ISC_LIST_HEAD(server->viewlist);
|
||||
view != NULL;
|
||||
view = ISC_LIST_NEXT(view, link))
|
||||
{
|
||||
if (strcasecmp(viewname, view->name) != 0)
|
||||
continue;
|
||||
found = ISC_TRUE;
|
||||
for (nsc = ISC_LIST_HEAD(server->cachelist);
|
||||
nsc != NULL;
|
||||
nsc = ISC_LIST_NEXT(nsc, link)) {
|
||||
if (nsc->cache == view->cache)
|
||||
break;
|
||||
}
|
||||
INSIST(nsc != NULL);
|
||||
nsc->needflush = ISC_TRUE;
|
||||
}
|
||||
} else
|
||||
found = ISC_TRUE;
|
||||
result = dns_view_flushcache(view);
|
||||
|
||||
/* Perform flush */
|
||||
for (nsc = ISC_LIST_HEAD(server->cachelist);
|
||||
nsc != NULL;
|
||||
nsc = ISC_LIST_NEXT(nsc, link)) {
|
||||
if (viewname != NULL && !nsc->needflush)
|
||||
continue;
|
||||
nsc->needflush = ISC_TRUE;
|
||||
result = dns_view_flushcache2(nsc->primaryview, ISC_FALSE);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
flushed = ISC_FALSE;
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
|
||||
"flushing cache in view '%s' failed: %s",
|
||||
view->name, isc_result_totext(result));
|
||||
nsc->primaryview->name,
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix up views that share a flushed cache: let the views update the
|
||||
* cache DB they're referring to. This could also be an expensive
|
||||
* operation, but should typically be marginal: the inner loop is only
|
||||
* necessary for views that share a cache, and if there are many such
|
||||
* views the number of shared cache should normally be small.
|
||||
* A worst case is that we have n views and n/2 caches, each shared by
|
||||
* two views. Then this will be a O(n^2/4) operation.
|
||||
*/
|
||||
for (view = ISC_LIST_HEAD(server->viewlist);
|
||||
view != NULL;
|
||||
view = ISC_LIST_NEXT(view, link))
|
||||
{
|
||||
if (!dns_view_iscacheshared(view))
|
||||
continue;
|
||||
for (nsc = ISC_LIST_HEAD(server->cachelist);
|
||||
nsc != NULL;
|
||||
nsc = ISC_LIST_NEXT(nsc, link)) {
|
||||
if (!nsc->needflush || nsc->cache != view->cache)
|
||||
continue;
|
||||
result = dns_view_flushcache2(view, ISC_TRUE);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
flushed = ISC_FALSE;
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
NS_LOGMODULE_SERVER, ISC_LOG_ERROR,
|
||||
"fixing cache in view '%s' "
|
||||
"failed: %s", view->name,
|
||||
isc_result_totext(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup the cache list. */
|
||||
for (nsc = ISC_LIST_HEAD(server->cachelist);
|
||||
nsc != NULL;
|
||||
nsc = ISC_LIST_NEXT(nsc, link)) {
|
||||
nsc->needflush = ISC_FALSE;
|
||||
}
|
||||
|
||||
if (flushed && found) {
|
||||
if (viewname != NULL)
|
||||
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
|
||||
|
|
@ -5034,6 +5311,11 @@ ns_server_flushname(ns_server_t *server, char *args) {
|
|||
if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
|
||||
continue;
|
||||
found = ISC_TRUE;
|
||||
/*
|
||||
* It's a little inefficient to try flushing name for all views
|
||||
* if some of the views share a single cache. But since the
|
||||
* operation is lightweight we prefer simplicity here.
|
||||
*/
|
||||
result = dns_view_flushname(view, name);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
flushed = ISC_FALSE;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: statschannel.c,v 1.15 2008/12/18 02:23:27 marka Exp $ */
|
||||
/* $Id: statschannel.c,v 1.16 2009/01/09 22:24:36 jinmei Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include <isc/socket.h>
|
||||
#include <isc/task.h>
|
||||
|
||||
#include <dns/cache.h>
|
||||
#include <dns/db.h>
|
||||
#include <dns/opcode.h>
|
||||
#include <dns/rdataclass.h>
|
||||
|
|
@ -635,7 +636,7 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
|
|||
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "bind"));
|
||||
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "statistics"));
|
||||
TRY0(xmlTextWriterWriteAttribute(writer, ISC_XMLCHAR "version",
|
||||
ISC_XMLCHAR "2.0"));
|
||||
ISC_XMLCHAR "2.1"));
|
||||
|
||||
/* Set common fields for statistics dump */
|
||||
dumparg.type = statsformat_xml;
|
||||
|
|
@ -674,11 +675,15 @@ generatexml(ns_server_t *server, int *buflen, xmlChar **buf) {
|
|||
|
||||
cachestats = dns_db_getrrsetstats(view->cachedb);
|
||||
if (cachestats != NULL) {
|
||||
xmlTextWriterStartElement(writer,
|
||||
ISC_XMLCHAR "cache");
|
||||
TRY0(xmlTextWriterStartElement(writer,
|
||||
ISC_XMLCHAR "cache"));
|
||||
TRY0(xmlTextWriterWriteAttribute(writer,
|
||||
ISC_XMLCHAR "name",
|
||||
ISC_XMLCHAR
|
||||
dns_cache_getname(view->cache)));
|
||||
dns_rdatasetstats_dump(cachestats, rdatasetstats_dump,
|
||||
&dumparg, 0);
|
||||
xmlTextWriterEndElement(writer); /* cache */
|
||||
TRY0(xmlTextWriterEndElement(writer)); /* cache */
|
||||
}
|
||||
|
||||
xmlTextWriterEndElement(writer); /* view */
|
||||
|
|
@ -1220,7 +1225,15 @@ ns_stats_dump(ns_server_t *server, FILE *fp) {
|
|||
if (strcmp(view->name, "_default") == 0)
|
||||
fprintf(fp, "[View: default]\n");
|
||||
else
|
||||
fprintf(fp, "[View: %s]\n", view->name);
|
||||
fprintf(fp, "[View: %s (Cache: %s)]\n", view->name,
|
||||
dns_cache_getname(view->cache));
|
||||
if (dns_view_iscacheshared(view)) {
|
||||
/*
|
||||
* Avoid dumping redundant statistics when the cache is
|
||||
* shared.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
dns_rdatasetstats_dump(cachestats, rdatasetstats_dump, &dumparg,
|
||||
0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
- PERFORMANCE OF THIS SOFTWARE.
|
||||
-->
|
||||
|
||||
<!-- File: $Id: Bv9ARM-book.xml,v 1.385 2009/01/08 14:19:05 jreed Exp $ -->
|
||||
<!-- File: $Id: Bv9ARM-book.xml,v 1.386 2009/01/09 22:24:36 jinmei Exp $ -->
|
||||
<book xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<title>BIND 9 Administrator Reference Manual</title>
|
||||
|
||||
|
|
@ -4706,6 +4706,7 @@ category notify { null; };
|
|||
</para>
|
||||
|
||||
<programlisting><command>options</command> {
|
||||
<optional> attach-cache <replaceable>cache_name</replaceable>; </optional>
|
||||
<optional> version <replaceable>version_string</replaceable>; </optional>
|
||||
<optional> hostname <replaceable>hostname_string</replaceable>; </optional>
|
||||
<optional> server-id <replaceable>server_id_string</replaceable>; </optional>
|
||||
|
|
@ -4888,6 +4889,102 @@ category notify { null; };
|
|||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>attach-cache</command></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Allows multiple views to share a single cache
|
||||
database.
|
||||
Each view has its own cache database by default, but
|
||||
if multiple views have the same operational policy
|
||||
for name resolution and caching, those views can
|
||||
share a single cache to save memory and possibly
|
||||
improve resolution efficiency by using this option.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <command>attach-cache</command> option
|
||||
may also be specified in <command>view</command>
|
||||
statements, in which case it overrides the
|
||||
global <command>attach-cache</command> option.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <replaceable>cache_name</replaceable> specifies
|
||||
the cache to be shared.
|
||||
When the <command>named</command> server configures
|
||||
views which are supposed to share a cache, it
|
||||
creates a cache with the specified name for the
|
||||
first view of these sharing views.
|
||||
The rest of the views will simply refer to the
|
||||
already created cache.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
One common configuration to share a cache would be to
|
||||
allow all views to share a single cache.
|
||||
This can be done by specifying
|
||||
the <command>attach-cache</command> as a global
|
||||
option with an arbitrary name.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Another possible operation is to allow a subset of
|
||||
all views to share a cache while the others to
|
||||
retain their own caches.
|
||||
For example, if there are three views A, B, and C,
|
||||
and only A and B should share a cache, specify the
|
||||
<command>attach-cache</command> option as a view A (or
|
||||
B)'s option, referring to the other view name:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
view "A" {
|
||||
// this view has its own cache
|
||||
...
|
||||
};
|
||||
view "B" {
|
||||
// this view refers to A's cache
|
||||
attach-cache "A";
|
||||
};
|
||||
view "C" {
|
||||
// this view has its own cache
|
||||
...
|
||||
};
|
||||
</programlisting>
|
||||
|
||||
<para>
|
||||
Views that share a cache must have the same policy
|
||||
on configurable parameters that may affect caching.
|
||||
The current implementation requires the following
|
||||
configurable options be consistent among these
|
||||
views:
|
||||
<command>check-names</command>,
|
||||
<command>cleaning-interval</command>,
|
||||
<command>dnssec-accept-expired</command>,
|
||||
<command>dnssec-validation</command>,
|
||||
<command>max-cache-ttl</command>,
|
||||
<command>max-ncache-ttl</command>,
|
||||
<command>max-cache-size</command>, and
|
||||
<command>zero-no-soa-ttl</command>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that there may be other parameters that may
|
||||
cause confusion if they are inconsistent for
|
||||
different views that share a single cache.
|
||||
For example, if these views define different sets of
|
||||
forwarders that can return different answers for the
|
||||
same question, sharing the answer does not make
|
||||
sense or could even be harmful.
|
||||
It is administrator's responsibility to ensure
|
||||
configuration differences in different views do
|
||||
not cause disruption with a shared cache.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><command>directory</command></term>
|
||||
<listitem>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: cache.c,v 1.80 2008/09/24 02:46:22 marka Exp $ */
|
||||
/* $Id: cache.c,v 1.81 2009/01/09 22:24:36 jinmei Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
|
@ -122,6 +122,7 @@ struct dns_cache {
|
|||
isc_mutex_t lock;
|
||||
isc_mutex_t filelock;
|
||||
isc_mem_t *mctx;
|
||||
char *name;
|
||||
|
||||
/* Locked by 'lock'. */
|
||||
int references;
|
||||
|
|
@ -132,6 +133,7 @@ struct dns_cache {
|
|||
char *db_type;
|
||||
int db_argc;
|
||||
char **db_argv;
|
||||
isc_uint32_t size;
|
||||
|
||||
/* Locked by 'filelock'. */
|
||||
char *filename;
|
||||
|
|
@ -170,6 +172,16 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *db_type, unsigned int db_argc, char **db_argv,
|
||||
dns_cache_t **cachep)
|
||||
{
|
||||
return (dns_cache_create2(mctx, taskmgr, timermgr, rdclass, "",
|
||||
db_type, db_argc, db_argv, cachep));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *cachename, const char *db_type,
|
||||
unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_cache_t *cache;
|
||||
|
|
@ -178,6 +190,7 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
REQUIRE(cachep != NULL);
|
||||
REQUIRE(*cachep == NULL);
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(cachename != NULL);
|
||||
|
||||
cache = isc_mem_get(mctx, sizeof(*cache));
|
||||
if (cache == NULL)
|
||||
|
|
@ -186,6 +199,15 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
cache->mctx = NULL;
|
||||
isc_mem_attach(mctx, &cache->mctx);
|
||||
|
||||
cache->name = NULL;
|
||||
if (cachename != NULL) {
|
||||
cache->name = isc_mem_strdup(mctx, cachename);
|
||||
if (cache->name == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup_mem;
|
||||
}
|
||||
}
|
||||
|
||||
result = isc_mutex_init(&cache->lock);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_mem;
|
||||
|
|
@ -266,6 +288,8 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
cleanup_lock:
|
||||
DESTROYLOCK(&cache->lock);
|
||||
cleanup_mem:
|
||||
if (cache->name != NULL)
|
||||
isc_mem_free(mctx, cache->name);
|
||||
isc_mem_put(mctx, cache, sizeof(*cache));
|
||||
isc_mem_detach(&mctx);
|
||||
return (result);
|
||||
|
|
@ -314,6 +338,9 @@ cache_free(dns_cache_t *cache) {
|
|||
if (cache->db_type != NULL)
|
||||
isc_mem_free(cache->mctx, cache->db_type);
|
||||
|
||||
if (cache->name != NULL)
|
||||
isc_mem_free(cache->mctx, cache->name);
|
||||
|
||||
DESTROYLOCK(&cache->lock);
|
||||
DESTROYLOCK(&cache->filelock);
|
||||
cache->magic = 0;
|
||||
|
|
@ -484,6 +511,26 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int t) {
|
|||
UNLOCK(&cache->lock);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
dns_cache_getcleaninginterval(dns_cache_t *cache) {
|
||||
unsigned int t;
|
||||
|
||||
REQUIRE(VALID_CACHE(cache));
|
||||
|
||||
LOCK(&cache->lock);
|
||||
t = cache->cleaner.cleaning_interval;
|
||||
UNLOCK(&cache->lock);
|
||||
|
||||
return (t);
|
||||
}
|
||||
|
||||
const char *
|
||||
dns_cache_getname(dns_cache_t *cache) {
|
||||
REQUIRE(VALID_CACHE(cache));
|
||||
|
||||
return (cache->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the cache cleaner object at *cleaner.
|
||||
* Space for the object must be allocated by the caller.
|
||||
|
|
@ -510,6 +557,7 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
|
|||
cleaner->cleaning_timer = NULL;
|
||||
cleaner->resched_event = NULL;
|
||||
cleaner->overmem_event = NULL;
|
||||
cleaner->cleaning_interval = 0; /* Initially turned off. */
|
||||
|
||||
result = dns_db_createiterator(cleaner->cache->db, ISC_FALSE,
|
||||
&cleaner->iterator);
|
||||
|
|
@ -538,7 +586,6 @@ cache_cleaner_init(dns_cache_t *cache, isc_taskmgr_t *taskmgr,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
cleaner->cleaning_interval = 0; /* Initially turned off. */
|
||||
result = isc_timer_create(timermgr, isc_timertype_inactive,
|
||||
NULL, NULL, cleaner->task,
|
||||
cleaning_timer_action, cleaner,
|
||||
|
|
@ -940,6 +987,10 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
|
|||
if (size != 0 && size < DNS_CACHE_MINSIZE)
|
||||
size = DNS_CACHE_MINSIZE;
|
||||
|
||||
LOCK(&cache->lock);
|
||||
cache->size = size;
|
||||
UNLOCK(&cache->lock);
|
||||
|
||||
hiwater = size - (size >> 3); /* Approximately 7/8ths. */
|
||||
lowater = size - (size >> 2); /* Approximately 3/4ths. */
|
||||
|
||||
|
|
@ -963,6 +1014,19 @@ dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size) {
|
|||
isc_mem_setwater(cache->mctx, water, cache, hiwater, lowater);
|
||||
}
|
||||
|
||||
isc_uint32_t
|
||||
dns_cache_getcachesize(dns_cache_t *cache) {
|
||||
isc_uint32_t size;
|
||||
|
||||
REQUIRE(VALID_CACHE(cache));
|
||||
|
||||
LOCK(&cache->lock);
|
||||
size = cache->size;
|
||||
UNLOCK(&cache->lock);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*
|
||||
* The cleaner task is shutting down; do the necessary cleanup.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: cache.h,v 1.26 2007/06/19 23:47:16 tbox Exp $ */
|
||||
/* $Id: cache.h,v 1.27 2009/01/09 22:24:37 jinmei Exp $ */
|
||||
|
||||
#ifndef DNS_CACHE_H
|
||||
#define DNS_CACHE_H 1
|
||||
|
|
@ -65,8 +65,15 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *db_type, unsigned int db_argc, char **db_argv,
|
||||
dns_cache_t **cachep);
|
||||
isc_result_t
|
||||
dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *cachename, const char *db_type,
|
||||
unsigned int db_argc, char **db_argv, dns_cache_t **cachep);
|
||||
/*%<
|
||||
* Create a new DNS cache.
|
||||
* Create a new DNS cache. dns_cache_create2() will create a named cache.
|
||||
* dns_cache_create() is a backward compatible version that internally specifies
|
||||
* an empty name.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
|
|
@ -76,6 +83,8 @@ dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
|||
* manager, or both are NULL. If NULL, no periodic cleaning of the
|
||||
* cache will take place.
|
||||
*
|
||||
*\li 'cachename' is a valid string. This must not be NULL.
|
||||
*
|
||||
*\li 'cachep' is a valid pointer, and *cachep == NULL
|
||||
*
|
||||
* Ensures:
|
||||
|
|
@ -217,12 +226,36 @@ dns_cache_setcleaninginterval(dns_cache_t *cache, unsigned int interval);
|
|||
* Set the periodic cache cleaning interval to 'interval' seconds.
|
||||
*/
|
||||
|
||||
unsigned int
|
||||
dns_cache_getcleaninginterval(dns_cache_t *cache);
|
||||
/*%<
|
||||
* Get the periodic cache cleaning interval to 'interval' seconds.
|
||||
*/
|
||||
|
||||
isc_uint32_t
|
||||
dns_cache_getcachesize(dns_cache_t *cache);
|
||||
/*%<
|
||||
* Get the maximum cache size.
|
||||
*/
|
||||
|
||||
const char *
|
||||
dns_cache_getname(dns_cache_t *cache);
|
||||
/*%<
|
||||
* Get the cache name.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_cache_setcachesize(dns_cache_t *cache, isc_uint32_t size);
|
||||
/*%<
|
||||
* Set the maximum cache size. 0 means unlimited.
|
||||
*/
|
||||
|
||||
isc_uint32_t
|
||||
dns_cache_getcachesize(dns_cache_t *cache);
|
||||
/*%<
|
||||
* Get the maximum cache size.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_cache_flush(dns_cache_t *cache);
|
||||
/*%<
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: view.h,v 1.113 2009/01/05 23:47:53 tbox Exp $ */
|
||||
/* $Id: view.h,v 1.114 2009/01/09 22:24:37 jinmei Exp $ */
|
||||
|
||||
#ifndef DNS_VIEW_H
|
||||
#define DNS_VIEW_H 1
|
||||
|
|
@ -102,6 +102,7 @@ struct dns_view {
|
|||
isc_event_t reqevent;
|
||||
dns_stats_t * resstats;
|
||||
dns_stats_t * resquerystats;
|
||||
isc_boolean_t cacheshared;
|
||||
|
||||
/* Configurable data. */
|
||||
dns_tsig_keyring_t * statickeys;
|
||||
|
|
@ -308,8 +309,12 @@ dns_view_createresolver(dns_view_t *view,
|
|||
|
||||
void
|
||||
dns_view_setcache(dns_view_t *view, dns_cache_t *cache);
|
||||
void
|
||||
dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared);
|
||||
/*%<
|
||||
* Set the view's cache database.
|
||||
* Set the view's cache database. If 'shared' is true, this means the cache
|
||||
* is created by another view and is shared with that view. dns_view_setcache()
|
||||
* is a backward compatible version equivalent to setcache2(..., ISC_FALSE).
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
|
|
@ -726,8 +731,14 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp);
|
|||
|
||||
isc_result_t
|
||||
dns_view_flushcache(dns_view_t *view);
|
||||
isc_result_t
|
||||
dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly);
|
||||
/*%<
|
||||
* Flush the view's cache (and ADB).
|
||||
* Flush the view's cache (and ADB). If 'fixuponly' is true, it only updates
|
||||
* the internal reference to the cache DB with omitting actual flush operation.
|
||||
* 'fixuponly' is intended to be used for a view that shares a cache with
|
||||
* a different view. dns_view_flushcache() is a backward compatible version
|
||||
* that always sets fixuponly to false.
|
||||
*
|
||||
* Requires:
|
||||
* 'view' is valid.
|
||||
|
|
@ -876,4 +887,17 @@ dns_view_getresquerystats(dns_view_t *view, dns_stats_t **statsp);
|
|||
*\li 'statsp' != NULL && '*statsp' != NULL
|
||||
*/
|
||||
|
||||
isc_boolean_t
|
||||
dns_view_iscacheshared(dns_view_t *view);
|
||||
/*%<
|
||||
* Check if the view shares the cache created by another view.
|
||||
*
|
||||
* Requires:
|
||||
* \li 'view' is valid.
|
||||
*
|
||||
* Returns:
|
||||
*\li #ISC_TRUE if the cache is shared.
|
||||
*\li #ISC_FALSE othewise.
|
||||
*/
|
||||
|
||||
#endif /* DNS_VIEW_H */
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: view.c,v 1.150 2008/06/17 03:14:20 marka Exp $ */
|
||||
/* $Id: view.c,v 1.151 2009/01/09 22:24:36 jinmei Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
|
@ -154,6 +154,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|||
view->rootexclude = NULL;
|
||||
view->resstats = NULL;
|
||||
view->resquerystats = NULL;
|
||||
view->cacheshared = ISC_FALSE;
|
||||
|
||||
/*
|
||||
* Initialize configuration data with default values.
|
||||
|
|
@ -626,9 +627,15 @@ dns_view_createresolver(dns_view_t *view,
|
|||
|
||||
void
|
||||
dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
|
||||
dns_view_setcache2(view, cache, ISC_FALSE);
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_setcache2(dns_view_t *view, dns_cache_t *cache, isc_boolean_t shared) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
REQUIRE(!view->frozen);
|
||||
|
||||
view->cacheshared = shared;
|
||||
if (view->cache != NULL) {
|
||||
if (view->acache != NULL)
|
||||
dns_acache_putdb(view->acache, view->cachedb);
|
||||
|
|
@ -643,6 +650,13 @@ dns_view_setcache(dns_view_t *view, dns_cache_t *cache) {
|
|||
dns_acache_setdb(view->acache, view->cachedb);
|
||||
}
|
||||
|
||||
isc_boolean_t
|
||||
dns_view_iscacheshared(dns_view_t *view) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
return (view->cacheshared);
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_sethints(dns_view_t *view, dns_db_t *hints) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
|
@ -1278,15 +1292,22 @@ dns_view_dumpdbtostream(dns_view_t *view, FILE *fp) {
|
|||
|
||||
isc_result_t
|
||||
dns_view_flushcache(dns_view_t *view) {
|
||||
return (dns_view_flushcache2(view, ISC_FALSE));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_view_flushcache2(dns_view_t *view, isc_boolean_t fixuponly) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
if (view->cachedb == NULL)
|
||||
return (ISC_R_SUCCESS);
|
||||
result = dns_cache_flush(view->cache);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
if (!fixuponly) {
|
||||
result = dns_cache_flush(view->cache);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
return (result);
|
||||
}
|
||||
if (view->acache != NULL)
|
||||
dns_acache_putdb(view->acache, view->cachedb);
|
||||
dns_db_detach(&view->cachedb);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: namedconf.c,v 1.92 2008/09/27 23:35:31 jinmei Exp $ */
|
||||
/* $Id: namedconf.c,v 1.93 2009/01/09 22:24:37 jinmei Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
|
|
@ -797,6 +797,7 @@ view_clauses[] = {
|
|||
{ "allow-recursion-on", &cfg_type_bracketed_aml, 0 },
|
||||
{ "allow-v6-synthesis", &cfg_type_bracketed_aml,
|
||||
CFG_CLAUSEFLAG_OBSOLETE },
|
||||
{ "attach-cache", &cfg_type_astring, 0 },
|
||||
{ "auth-nxdomain", &cfg_type_boolean, CFG_CLAUSEFLAG_NEWDEFAULT },
|
||||
{ "cache-file", &cfg_type_qstring, 0 },
|
||||
{ "check-names", &cfg_type_checknames, CFG_CLAUSEFLAG_MULTI },
|
||||
|
|
|
|||
Loading…
Reference in a new issue