Commit e68c3a0a authored by Marek Vavrusa's avatar Marek Vavrusa

lib: cache api v2, removed dep on libknot db.h

this change introduces new API for cache backends,
that is a subset of knot_db_api_t from libknot
with several cache-specific operations

major changes are:
* merged 'cachectl' module into 'cache' as it is
  99% default-on and it simplifies things
* not transaction oriented, transactions may be
  reused and cached for higher performance
* scatter/gather API, this is important for
  latency and performance of non-local backends
  like Redis
* faster and reliable cache clearing
* cache-specific operations (prefix scan, ...) in
  the API not hacked in
* simpler code for both backends and caller
parent 96bbc909
...@@ -24,7 +24,7 @@ env: ...@@ -24,7 +24,7 @@ env:
global: global:
- PKG_CONFIG_PATH="${HOME}/.local/lib/pkgconfig" - PKG_CONFIG_PATH="${HOME}/.local/lib/pkgconfig"
- PATH="${HOME}/.local/bin:/usr/local/bin:${PATH}" - PATH="${HOME}/.local/bin:/usr/local/bin:${PATH}"
- CFLAGS="-O2 -g -fno-omit-frame-pointer -DMP_FREELIST_SIZE=0" - CFLAGS="-O2 -g -fno-omit-frame-pointer -DDEBUG"
- LD_LIBRARY_PATH="${HOME}/.local/lib" - LD_LIBRARY_PATH="${HOME}/.local/lib"
- DYLD_LIBRARY_PATH="${HOME}/.local/lib" - DYLD_LIBRARY_PATH="${HOME}/.local/lib"
- MALLOC_CHECK_=3 - MALLOC_CHECK_=3
......
...@@ -23,7 +23,7 @@ INSTALL := install ...@@ -23,7 +23,7 @@ INSTALL := install
# Flags # Flags
BUILD_LDFLAGS += $(LDFLAGS) BUILD_LDFLAGS += $(LDFLAGS)
BUILD_CFLAGS := $(CFLAGS) -std=c99 -D_GNU_SOURCE -Wno-unused -Wtype-limits -Wformat -Wformat-security -Wall -I$(abspath .) -I$(abspath lib/generic) -I$(abspath contrib) BUILD_CFLAGS := $(CFLAGS) -std=c99 -D_GNU_SOURCE -Wno-unused -Wtype-limits -Wformat -Wformat-security -Wall -I$(abspath .) -I$(abspath lib/generic) -I$(abspath contrib) -I$(abspath contrib/lmdb)
BUILD_CFLAGS += -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR).$(PATCH)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\"" -DETCDIR="\"$(ETCDIR)\"" BUILD_CFLAGS += -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR).$(PATCH)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\"" -DETCDIR="\"$(ETCDIR)\""
ifeq (,$(findstring -O,$(CFLAGS))) ifeq (,$(findstring -O,$(CFLAGS)))
BUILD_CFLAGS += -O2 BUILD_CFLAGS += -O2
......
...@@ -8,4 +8,13 @@ contrib_SOURCES := \ ...@@ -8,4 +8,13 @@ contrib_SOURCES := \
contrib/base32hex.c contrib/base32hex.c
contrib_CFLAGS := -fPIC contrib_CFLAGS := -fPIC
contrib_TARGET := $(abspath contrib)/contrib$(AREXT) contrib_TARGET := $(abspath contrib)/contrib$(AREXT)
$(eval $(call make_static,contrib,contrib))
# Use built-in LMDB if not found
ifneq ($(HAS_lmdb), yes)
contrib_SOURCES += contrib/lmdb/mdb.c \
contrib/lmdb/midl.c
contrib_CFLAGS += -pthread
contrib_LIBS += -pthread
endif
$(eval $(call make_static,contrib,contrib))
\ No newline at end of file
...@@ -169,7 +169,7 @@ Configuration example ...@@ -169,7 +169,7 @@ Configuration example
-- interfaces -- interfaces
net = { '127.0.0.1', '::1' } net = { '127.0.0.1', '::1' }
-- load some modules -- load some modules
modules = { 'policy', 'cachectl' } modules = { 'policy' }
-- 10MB cache -- 10MB cache
cache.size = 10*MB cache.size = 10*MB
...@@ -198,7 +198,6 @@ the modules use as the :ref:`input configuration <mod-properties>`. ...@@ -198,7 +198,6 @@ the modules use as the :ref:`input configuration <mod-properties>`.
.. code-block:: lua .. code-block:: lua
modules = { modules = {
cachectl = true,
hints = '/etc/hosts' hints = '/etc/hosts'
} }
...@@ -274,7 +273,7 @@ Here's an example of an anonymous function with :func:`event.recurrent()`: ...@@ -274,7 +273,7 @@ Here's an example of an anonymous function with :func:`event.recurrent()`:
-- every 5 minutes -- every 5 minutes
event.recurrent(5 * minute, function() event.recurrent(5 * minute, function()
cachectl.prune() cache.prune()
end) end)
Note that each scheduled event is identified by a number valid for the duration of the event, Note that each scheduled event is identified by a number valid for the duration of the event,
...@@ -288,7 +287,7 @@ as a parameter, but it's not very useful as you don't have any *non-global* way ...@@ -288,7 +287,7 @@ as a parameter, but it's not very useful as you don't have any *non-global* way
local i = 0 local i = 0
-- pruning function -- pruning function
return function(e) return function(e)
cachectl.prune() cache.prune()
-- cancel event on 5th attempt -- cancel event on 5th attempt
i = i + 1 i = i + 1
if i == 5 then if i == 5 then
...@@ -609,7 +608,6 @@ The daemon provides an interface for dynamic loading of :ref:`daemon modules <mo ...@@ -609,7 +608,6 @@ The daemon provides an interface for dynamic loading of :ref:`daemon modules <mo
.. code-block:: lua .. code-block:: lua
modules = { 'cachectl' }
modules = { modules = {
hints = {file = '/etc/hosts'} hints = {file = '/etc/hosts'}
} }
...@@ -618,7 +616,6 @@ The daemon provides an interface for dynamic loading of :ref:`daemon modules <mo ...@@ -618,7 +616,6 @@ The daemon provides an interface for dynamic loading of :ref:`daemon modules <mo
.. code-block:: lua .. code-block:: lua
modules.load('cachectl')
modules.load('hints') modules.load('hints')
hints.config({file = '/etc/hosts'}) hints.config({file = '/etc/hosts'})
...@@ -716,7 +713,7 @@ daemons or manipulated from other processes, making for example synchronised loa ...@@ -716,7 +713,7 @@ daemons or manipulated from other processes, making for example synchronised loa
Close the cache. Close the cache.
.. note:: This may or may not clear the cache, depending on the used backend. See :func:`cachectl.clear()`. .. note:: This may or may not clear the cache, depending on the used backend. See :func:`cache.clear()`.
.. function:: cache.stats() .. function:: cache.stats()
...@@ -729,6 +726,56 @@ daemons or manipulated from other processes, making for example synchronised loa ...@@ -729,6 +726,56 @@ daemons or manipulated from other processes, making for example synchronised loa
print('Insertions:', cache.stats().insert) print('Insertions:', cache.stats().insert)
.. function:: cache.prune([max_count])
:param number max_count: maximum number of items to be pruned at once (default: 65536)
:return: ``{ pruned: int }``
Prune expired/invalid records.
.. function:: cache.get([domain])
:return: list of matching records in cache
Fetches matching records from cache. The **domain** can either be:
- a domain name (e.g. ``"domain.cz"``)
- a wildcard (e.g. ``"*.domain.cz"``)
The domain name fetches all records matching this name, while the wildcard matches all records at or below that name.
You can also use a special namespace ``"P"`` to purge NODATA/NXDOMAIN matching this name (e.g. ``"domain.cz P"``).
.. note:: This is equivalent to ``cache['domain']`` getter.
Examples:
.. code-block:: lua
-- Query cache for 'domain.cz'
cache['domain.cz']
-- Query cache for all records at/below 'insecure.net'
cache['*.insecure.net']
.. function:: cache.clear([domain])
:return: ``bool``
Purge cache records. If the domain isn't provided, whole cache is purged. See *cache.get()* documentation for subtree matching policy.
Examples:
.. code-block:: lua
-- Clear records at/below 'bad.cz'
cache.clear('*.bad.cz')
-- Clear packet cache
cache.clear('*. P')
-- Clear whole cache
cache.clear()
Timers and events Timers and events
^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <libknot/descriptor.h> #include <libknot/descriptor.h>
#include "lib/cache.h" #include "lib/cache.h"
#include "lib/cdb.h"
#include "daemon/bindings.h" #include "daemon/bindings.h"
#include "daemon/worker.h" #include "daemon/worker.h"
...@@ -349,13 +350,12 @@ int lib_net(lua_State *L) ...@@ -349,13 +350,12 @@ int lib_net(lua_State *L)
static int cache_backends(lua_State *L) static int cache_backends(lua_State *L)
{ {
struct engine *engine = engine_luaget(L); struct engine *engine = engine_luaget(L);
storage_registry_t *registry = &engine->storage_registry;
lua_newtable(L); lua_newtable(L);
for (unsigned i = 0; i < registry->len; ++i) { for (unsigned i = 0; i < engine->backends.len; ++i) {
struct storage_api *storage = &registry->at[i]; const struct kr_cdb_api *api = engine->backends.at[i];
lua_pushboolean(L, storage->api() == engine->resolver.cache.api); lua_pushboolean(L, api == engine->resolver.cache.api);
lua_setfield(L, -2, storage->prefix); lua_setfield(L, -2, api->name);
} }
return 1; return 1;
} }
...@@ -364,20 +364,15 @@ static int cache_backends(lua_State *L) ...@@ -364,20 +364,15 @@ static int cache_backends(lua_State *L)
static int cache_count(lua_State *L) static int cache_count(lua_State *L)
{ {
struct engine *engine = engine_luaget(L); struct engine *engine = engine_luaget(L);
const knot_db_api_t *storage = engine->resolver.cache.api; const struct kr_cdb_api *api = engine->resolver.cache.api;
/* Fetch item count */
struct kr_cache_txn txn;
int ret = kr_cache_txn_begin(&engine->resolver.cache, &txn, KNOT_DB_RDONLY);
if (ret != 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
/* First key is a version counter, omit it. */ /* First key is a version counter, omit it. */
lua_pushinteger(L, storage->count(&txn.t) - 1); struct kr_cache *cache = &engine->resolver.cache;
kr_cache_txn_abort(&txn); if (kr_cache_is_open(cache)) {
return 1; lua_pushinteger(L, api->count(cache->db) - 1);
return 1;
}
return 0;
} }
/** Return cache statistics. */ /** Return cache statistics. */
...@@ -394,27 +389,22 @@ static int cache_stats(lua_State *L) ...@@ -394,27 +389,22 @@ static int cache_stats(lua_State *L)
lua_setfield(L, -2, "insert"); lua_setfield(L, -2, "insert");
lua_pushnumber(L, cache->stats.delete); lua_pushnumber(L, cache->stats.delete);
lua_setfield(L, -2, "delete"); lua_setfield(L, -2, "delete");
lua_pushnumber(L, cache->stats.txn_read);
lua_setfield(L, -2, "txn_read");
lua_pushnumber(L, cache->stats.txn_write);
lua_setfield(L, -2, "txn_write");
return 1; return 1;
} }
static struct storage_api *cache_select_storage(struct engine *engine, const char **conf) static const struct kr_cdb_api *cache_select(struct engine *engine, const char **conf)
{ {
/* Return default backend */ /* Return default backend */
storage_registry_t *registry = &engine->storage_registry; if (*conf == NULL || !strstr(*conf, "://")) {
if (!*conf || !strstr(*conf, "://")) { return engine->backends.at[0];
return &registry->at[0];
} }
/* Find storage backend from config prefix */ /* Find storage backend from config prefix */
for (unsigned i = 0; i < registry->len; ++i) { for (unsigned i = 0; i < engine->backends.len; ++i) {
struct storage_api *storage = &registry->at[i]; const struct kr_cdb_api *api = engine->backends.at[i];
if (strncmp(*conf, storage->prefix, strlen(storage->prefix)) == 0) { if (strncmp(*conf, api->name, strlen(api->name)) == 0) {
*conf += strlen(storage->prefix); *conf += strlen(api->name) + strlen("://");
return storage; return api;
} }
} }
...@@ -436,8 +426,8 @@ static int cache_open(lua_State *L) ...@@ -436,8 +426,8 @@ static int cache_open(lua_State *L)
unsigned cache_size = lua_tonumber(L, 1); unsigned cache_size = lua_tonumber(L, 1);
const char *conf = n > 1 ? lua_tostring(L, 2) : NULL; const char *conf = n > 1 ? lua_tostring(L, 2) : NULL;
const char *uri = conf; const char *uri = conf;
struct storage_api *storage = cache_select_storage(engine, &conf); const struct kr_cdb_api *api = cache_select(engine, &conf);
if (!storage) { if (!api) {
format_error(L, "unsupported cache backend"); format_error(L, "unsupported cache backend");
lua_error(L); lua_error(L);
} }
...@@ -446,9 +436,11 @@ static int cache_open(lua_State *L) ...@@ -446,9 +436,11 @@ static int cache_open(lua_State *L)
kr_cache_close(&engine->resolver.cache); kr_cache_close(&engine->resolver.cache);
/* Reopen cache */ /* Reopen cache */
void *storage_opts = storage->opts_create(conf, cache_size); struct kr_cdb_opts opts = {
int ret = kr_cache_open(&engine->resolver.cache, storage->api(), storage_opts, engine->pool); (conf && strlen(conf)) ? conf : ".",
free(storage_opts); cache_size
};
int ret = kr_cache_open(&engine->resolver.cache, api, &opts, engine->pool);
if (ret != 0) { if (ret != 0) {
format_error(L, "can't open cache"); format_error(L, "can't open cache");
lua_error(L); lua_error(L);
...@@ -481,6 +473,190 @@ static int cache_close(lua_State *L) ...@@ -481,6 +473,190 @@ static int cache_close(lua_State *L)
return 1; return 1;
} }
/** @internal Prefix walk. */
static int cache_prefixed(struct kr_cache *cache, const char *args, knot_db_val_t *results, int maxresults)
{
/* Decode parameters */
uint8_t namespace = 'R';
char *extra = (char *)strchr(args, ' ');
if (extra != NULL) {
extra[0] = '\0';
namespace = extra[1];
}
/* Convert to domain name */
uint8_t buf[KNOT_DNAME_MAXLEN];
if (!knot_dname_from_str(buf, args, sizeof(buf))) {
return kr_error(EINVAL);
}
/* Start prefix search */
return kr_cache_match(cache, namespace, buf, results, maxresults);
}
/** @internal Delete iterated key. */
static int cache_remove_prefix(struct kr_cache *cache, const char *args)
{
/* Check if we can remove */
if (!cache || !cache->api || !cache->api->remove) {
return kr_error(ENOSYS);
}
static knot_db_val_t result_set[1000];
int ret = cache_prefixed(cache, args, result_set, 1000);
if (ret < 0) {
return ret;
}
/* Duplicate result set as we're going to remove it
* which will invalidate result set. */
for (int i = 0; i < ret; ++i) {
void *dst = malloc(result_set[i].len);
if (!dst) {
return kr_error(ENOMEM);
}
memcpy(dst, result_set[i].data, result_set[i].len);
result_set[i].data = dst;
}
cache->api->remove(cache->db, result_set, ret);
/* Free keys */
for (int i = 0; i < ret; ++i) {
free(result_set[i].data);
}
return ret;
}
/** Prune expired/invalid records. */
static int cache_prune(lua_State *L)
{
/* Check parameters */
int prune_max = UINT16_MAX;
int n = lua_gettop(L);
if (n >= 1 && lua_isnumber(L, 1)) {
prune_max = lua_tointeger(L, 1);
}
struct engine *engine = engine_luaget(L);
struct kr_cache *cache = &engine->resolver.cache;
/* Check if API supports pruning. */
int ret = kr_error(ENOSYS);
if (cache->api->prune) {
ret = cache->api->prune(cache->db, prune_max);
}
/* Commit and format result. */
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
lua_pushinteger(L, ret);
return 1;
}
/** Clear all records. */
static int cache_clear(lua_State *L)
{
/* Check parameters */
const char *args = NULL;
int n = lua_gettop(L);
if (n >= 1 && lua_isstring(L, 1)) {
args = lua_tostring(L, 1);
}
/* Clear a sub-tree in cache. */
struct engine *engine = engine_luaget(L);
struct kr_cache *cache = &engine->resolver.cache;
if (args && strlen(args) > 0) {
int ret = cache_remove_prefix(cache, args);
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
lua_pushinteger(L, ret);
return 1;
}
/* Clear cache. */
int ret = kr_cache_clear(cache);
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
/* Clear reputation tables */
lru_deinit(engine->resolver.cache_rtt);
lru_deinit(engine->resolver.cache_rep);
lru_init(engine->resolver.cache_rtt, LRU_RTT_SIZE);
lru_init(engine->resolver.cache_rep, LRU_REP_SIZE);
lua_pushboolean(L, true);
return 1;
}
/** @internal Dump cache key into table on Lua stack. */
static void cache_dump_key(lua_State *L, knot_db_val_t *key)
{
char buf[KNOT_DNAME_MAXLEN];
/* Extract type */
uint16_t type = 0;
const char *endp = (const char *)key->data + key->len - sizeof(uint16_t);
memcpy(&type, endp, sizeof(uint16_t));
endp -= 1;
/* Extract domain name */
char *dst = buf;
const char *scan = endp - 1;
while (scan > (const char *)key->data) {
if (*scan == '\0') {
const size_t lblen = endp - scan - 1;
memcpy(dst, scan + 1, lblen);
dst += lblen;
*dst++ = '.';
endp = scan;
}
--scan;
}
memcpy(dst, scan + 1, endp - scan);
/* If name typemap doesn't exist yet, create it */
lua_getfield(L, -1, buf);
if (lua_isnil(L, -1)) {
lua_pop(L, 1);
lua_newtable(L);
}
/* Append to typemap */
char type_buf[16] = { '\0' };
knot_rrtype_to_string(type, type_buf, sizeof(type_buf));
lua_pushboolean(L, true);
lua_setfield(L, -2, type_buf);
/* Set name typemap */
lua_setfield(L, -2, buf);
}
/** Query cached records. */
static int cache_get(lua_State *L)
{
/* Check parameters */
int n = lua_gettop(L);
if (n < 1 || !lua_isstring(L, 1)) {
format_error(L, "expected 'cache.get(string key)'");
lua_error(L);
}
/* Clear a sub-tree in cache. */
struct engine *engine = engine_luaget(L);
struct kr_cache *cache = &engine->resolver.cache;
const char *args = lua_tostring(L, 1);
/* Retrieve set of keys */
static knot_db_val_t result_set[100];
int ret = cache_prefixed(cache, args, result_set, 100);
if (ret < 0) {
format_error(L, kr_strerror(ret));
lua_error(L);
}
/* Format output */
lua_newtable(L);
for (int i = 0; i < ret; ++i) {
cache_dump_key(L, &result_set[i]);
}
return 1;
}
int lib_cache(lua_State *L) int lib_cache(lua_State *L)
{ {
static const luaL_Reg lib[] = { static const luaL_Reg lib[] = {
...@@ -489,6 +665,9 @@ int lib_cache(lua_State *L) ...@@ -489,6 +665,9 @@ int lib_cache(lua_State *L)
{ "stats", cache_stats }, { "stats", cache_stats },
{ "open", cache_open }, { "open", cache_open },
{ "close", cache_close }, { "close", cache_close },
{ "prune", cache_prune },
{ "clear", cache_clear },
{ "get", cache_get },
{ NULL, NULL } { NULL, NULL }
}; };
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#include <unistd.h> #include <unistd.h>
#include <grp.h> #include <grp.h>
#include <pwd.h> #include <pwd.h>
/* #include <libknot/internal/namedb/knot_db_trie.h> @todo Not supported (doesn't keep value copy) */
#include <libknot/db/db_lmdb.h>
#include <zscanner/scanner.h> #include <zscanner/scanner.h>
#include "daemon/engine.h" #include "daemon/engine.h"
...@@ -31,6 +29,7 @@ ...@@ -31,6 +29,7 @@
#include "lib/nsrep.h" #include "lib/nsrep.h"
#include "lib/cache.h" #include "lib/cache.h"
#include "lib/defines.h" #include "lib/defines.h"
#include "lib/cdb_lmdb.h"
#include "lib/dnssec/ta.h" #include "lib/dnssec/ta.h"
/** @internal Compatibility wrapper for Lua < 5.2 */ /** @internal Compatibility wrapper for Lua < 5.2 */
...@@ -370,19 +369,6 @@ static int l_trampoline(lua_State *L) ...@@ -370,19 +369,6 @@ static int l_trampoline(lua_State *L)
* Engine API. * Engine API.
*/ */
/** @internal Make lmdb options. */
void *knot_db_lmdb_mkopts(const char *conf, size_t maxsize)
{
struct knot_db_lmdb_opts *opts = malloc(sizeof(*opts));
if (opts) {
memset(opts, 0, sizeof(*opts));
opts->path = (conf && strlen(conf)) ? conf : ".";
opts->mapsize = maxsize;
opts->flags.env = 0x80000 | 0x100000; /* MDB_WRITEMAP|MDB_MAPASYNC */
}
return opts;
}
static int init_resolver(struct engine *engine) static int init_resolver(struct engine *engine)
{ {
/* Open resolution context */ /* Open resolution context */
...@@ -415,12 +401,7 @@ static int init_resolver(struct engine *engine) ...@@ -415,12 +401,7 @@ static int init_resolver(struct engine *engine)
engine_register(engine, "rrcache", NULL, NULL); engine_register(engine, "rrcache", NULL, NULL);
engine_register(engine, "pktcache", NULL, NULL); engine_register(engine, "pktcache", NULL, NULL);
/* Initialize storage backends */ return array_push(engine->backends, kr_cdb_lmdb());
struct storage_api lmdb = {
"lmdb://", knot_db_lmdb_api, knot_db_lmdb_mkopts
};
return array_push(engine->storage_registry, lmdb);
} }
static int init_state(struct engine *engine) static int init_state(struct engine *engine)
...@@ -538,7 +519,7 @@ void engine_deinit(struct engine *engine) ...@@ -538,7 +519,7 @@ void engine_deinit(struct engine *engine)
/* Free data structures */ /* Free data structures */
array_clear(engine->modules); array_clear(engine->modules);
array_clear(engine->storage_registry); array_clear(engine->backends);
kr_ta_clear(&engine->resolver.trust_anchors); kr_ta_clear(&engine->resolver.trust_anchors);
kr_ta_clear(&engine->resolver.negative_anchors); kr_ta_clear(&engine->resolver.negative_anchors);
} }
......
...@@ -45,22 +45,11 @@ struct lua_State; ...@@ -45,22 +45,11 @@ struct lua_State;
#include "lib/resolve.h" #include "lib/resolve.h"
#include "daemon/network.h" #include "daemon/network.h"
/** Cache storage backend. */
struct storage_api {
const char *prefix; /**< Storage prefix, e.g. 'lmdb://' */
const knot_db_api_t *(*api)(void); /**< Storage API implementation */
void *(*opts_create)(const char *, size_t); /**< Storage options factory */
};
/** @cond internal Array of cache backend options. */
typedef array_t(struct storage_api) storage_registry_t;
/* @endcond */
struct engine { struct engine {
struct kr_context resolver; struct kr_context resolver;
struct network net; struct network net;
module_array_t modules; module_array_t modules;
storage_registry_t storage_registry; array_t(const struct kr_cdb_api *) backends;
knot_mm_t *pool; knot_mm_t *pool;
uv_timer_t *updater; uv_timer_t *updater;
struct lua_State *L; struct lua_State *L;
......
...@@ -72,7 +72,7 @@ setmetatable(modules, { ...@@ -72,7 +72,7 @@ setmetatable(modules, {
modules.load(k) modules.load(k)
k = string.match(k, '%w+') k = string.match(k, '%w+')
local mod = _G[k] local mod = _G[k]
local config = rawget(mod, 'config') local config = mod and rawget(mod, 'config')
if mod ~= nil and config ~= nil then if mod ~= nil and config ~= nil then
if k ~= v then config(v) if k ~= v then config(v)
else config() else config()
...@@ -83,8 +83,16 @@ setmetatable(modules, { ...@@ -83,8 +83,16 @@ setmetatable(modules, {
}) })
-- Syntactic sugar for cache -- Syntactic sugar for cache
-- `#cache -> cache.count()`
-- `cache[x] -> cache.get(x)`
-- `cache.{size|storage} = value` -- `cache.{size|storage} = value`
setmetatable(cache, { setmetatable(cache, {
__len = function (t)
return t.count()
end,
__index = function (t, k)
return rawget(t, k) or (rawget(t, 'current_size') and t.get(k))
end,
__newindex = function (t,k,v) __newindex = function (t,k,v)
-- Defaults -- Defaults
local storage = rawget(t, 'current_storage') local storage = rawget(t, 'current_storage')
......
...@@ -17,7 +17,6 @@ Knot DNS Resolver modules ...@@ -17,7 +17,6 @@ Knot DNS Resolver modules
.. include:: ../modules/kmemcached/README.rst .. include:: ../modules/kmemcached/README.rst
.. include:: ../modules/redis/README.rst .. include:: ../modules/redis/README.rst
.. include:: ../modules/ketcd/README.rst .. include:: ../modules/ketcd/README.rst
.. include:: ../modules/cachectl/README.rst
.. include:: ../modules/tinyweb/README.rst .. include:: ../modules/tinyweb/README.rst
.. include:: ../modules/dns64/README.rst .. include:: ../modules/dns64/README.rst
.. include:: ../modules/renumber/README.rst .. include:: ../modules/renumber/README.rst
...@@ -21,7 +21,6 @@ cache.size = 100 * GB ...@@ -21,7 +21,6 @@ cache.size = 100 * GB
-- Load Useful modules -- Load Useful modules
modules = { modules = {
'policy', -- Block queries to local zones/bad sites 'policy', -- Block queries to local zones/bad sites
'cachectl', -- Cache control interface
'hints', -- Load /etc/hosts and allow custom root hints 'hints', -- Load /etc/hosts and allow custom root hints
'stats', -- Track internal statistics 'stats', -- Track internal statistics
graphite = { -- Send statistics to local InfluxDB graphite = { -- Send statistics to local InfluxDB
......
...@@ -19,7 +19,6 @@ cache.size = 4 * GB ...@@ -19,7 +19,6 @@ cache.size = 4 * GB
modules = { modules = {
'policy', -- Block queries to local zones/bad sites 'policy', -- Block queries to local zones/bad sites
'view', -- Views for certain clients 'view', -- Views for certain clients
'cachectl', -- Cache control interface
'hints', -- Load /etc/hosts and allow custom root hints