Commit 56b72ec7 authored by Jan Kadlec's avatar Jan Kadlec

persistent events: Initial implementation

parent 6b7d946e
Doxyfile
KNOWN_ISSUES
Makefile.am
README
configure.ac
......@@ -73,6 +71,11 @@ src/common/mem.c
src/common/mem.h
src/common/mempool.c
src/common/mempool.h
src/common/namedb/namedb.h
src/common/namedb/namedb_lmdb.c
src/common/namedb/namedb_lmdb.h
src/common/namedb/namedb_trie.c
src/common/namedb/namedb_trie.h
src/dnstap/Makefile.am
src/dnstap/convert.c
src/dnstap/convert.h
......
......@@ -312,6 +312,24 @@ dt_DNSTAP([
])
AM_CONDITIONAL([HAVE_DNSTAP], test "$opt_dnstap" != "no")
dnl Check for lmdb.
AC_ARG_WITH(lmdb,
AC_HELP_STRING([--with-lmdb=[DIR]], [Support for LMDB.]),
with_lmdb=$withval,
with_lmdb=yes
)
if test "$with_lmdb" != "no" ; then
AC_SEARCH_LIBS([mdb_env_open], [lmdb], [with_lmdb=yes], [with_lmdb=no])
if test "$with_lmdb" != "yes" ; then
with_lmdb=no
AC_MSG_WARN([LMDB not found])
else
with_lmdb=yes
AC_DEFINE([HAVE_LMDB], [1], [Define to 1 to enable LMDB.])
fi
fi
AM_CONDITIONAL([HAVE_LMDB], test "$with_lmdb" != "no")
AC_SEARCH_LIBS([pow], [m])
AC_SEARCH_LIBS([pthread_create], [pthread], [], [AC_MSG_ERROR([pthreads not found])])
AC_SEARCH_LIBS([dlopen], [dl])
......
......@@ -112,6 +112,11 @@ libknotcs_la_SOURCES = \
common/mem.h \
common/mempool.c \
common/mempool.h \
common/namedb/namedb.h \
common/namedb/namedb_lmdb.h \
common/namedb/namedb_lmdb.c \
common/namedb/namedb_trie.h \
common/namedb/namedb_trie.c \
common/log.c \
common/log.h
......@@ -306,6 +311,8 @@ libknotd_la_SOURCES = \
knot/zone/node.h \
knot/zone/semantic-check.c \
knot/zone/semantic-check.h \
knot/zone/timers.c \
knot/zone/timers.h \
knot/zone/zone-diff.c \
knot/zone/zone-diff.h \
knot/zone/zone-dump.c \
......
/* Copyright (C) 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "libknot/dname.h"
enum {
NAMEDB_RDONLY = 1 << 0
};
typedef void knot_namedb_t;
typedef void knot_iter_t;
typedef struct knot_val {
void *data;
size_t len;
} knot_val_t;
typedef struct knot_txn {
knot_namedb_t *db;
void *txn;
} knot_txn_t;
struct namedb_api {
/* Context operations */
knot_namedb_t* (*init)(const char *handle, mm_ctx_t *mm);
void (*deinit)(knot_namedb_t *db);
/* Transactions */
int (*txn_begin)(knot_namedb_t *db, knot_txn_t *txn, unsigned flags);
int (*txn_commit)(knot_txn_t *txn);
void (*txn_abort)(knot_txn_t *txn);
/* Data access */
int (*count)(knot_txn_t *txn);
int (*find)(knot_txn_t *txn, const knot_dname_t *key, knot_val_t *val, unsigned op);
int (*insert)(knot_txn_t *txn, const knot_dname_t *key, knot_val_t *val);
int (*del)(knot_txn_t *txn, const knot_dname_t *key);
/* Iteration */
knot_iter_t *(*iter_begin)(knot_txn_t *txn, unsigned flags);
int (*iter_next)(knot_iter_t *iter);
const knot_dname_t *(*iter_key)(knot_iter_t *iter);
int (*iter_val)(knot_iter_t *iter, knot_val_t *val);
int (*iter_finish)(knot_iter_t *iter);
};
#include <lmdb.h>
#include "common/namedb/namedb_lmdb.h"
#include "libknot/errcode.h"
#define NAME_TO_KEY(key) { knot_dname_size(key), (void *)(key) }
struct lmdb_env
{
MDB_dbi dbi;
MDB_env *env;
mm_ctx_t *pool;
};
static int dbase_open(struct lmdb_env *env, const char *handle)
{
int ret = mdb_env_create(&env->env);
if (ret != 0) {
return ret;
}
ret = mdb_env_open(env->env, handle, 0, 0644);
if (ret != 0) {
mdb_env_close(env->env);
return ret;
}
MDB_txn *txn = NULL;
ret = mdb_txn_begin(env->env, NULL, 0, &txn);
if (ret != 0) {
mdb_env_close(env->env);
return ret;
}
ret = mdb_open(txn, NULL, MDB_DUPSORT, &env->dbi);
if (ret != 0) {
mdb_txn_abort(txn);
mdb_env_close(env->env);
return ret;
}
ret = mdb_txn_commit(txn);
if (ret != 0) {
mdb_env_close(env->env);
return ret;
}
return 0;
}
static void dbase_close(struct lmdb_env *env)
{
mdb_close(env->env, env->dbi);
mdb_env_close(env->env);
}
knot_namedb_t* init(const char *handle, mm_ctx_t *mm)
{
struct lmdb_env *env = mm_alloc(mm, sizeof(struct lmdb_env));
if (env == NULL) {
return NULL;
}
memset(env, 0, sizeof(struct lmdb_env));
int ret = dbase_open(env, handle);
if (ret != 0) {
mm_free(mm, env);
return NULL;
}
env->pool = mm;
return env;
}
void deinit(knot_namedb_t *db)
{
struct lmdb_env *env = db;
dbase_close(env);
mm_free(env->pool, env);
}
int txn_begin(knot_namedb_t *db, knot_txn_t *txn, unsigned flags)
{
txn->db = db;
txn->txn = NULL;
unsigned txn_flags = 0;
if (flags & NAMEDB_RDONLY) {
txn_flags |= MDB_RDONLY;
}
struct lmdb_env *env = db;
int ret = mdb_txn_begin(env->env, NULL, txn_flags, (MDB_txn **)&txn->txn);
if (ret != 0) {
return KNOT_ERROR;
}
return KNOT_EOK;
}
int txn_commit(knot_txn_t *txn)
{
int ret = mdb_txn_commit((MDB_txn *)txn->txn);
if (ret != 0) {
return KNOT_ERROR;
}
return KNOT_EOK;
}
void txn_abort(knot_txn_t *txn)
{
mdb_txn_abort((MDB_txn *)txn->txn);
}
int count(knot_txn_t *txn)
{
struct lmdb_env *env = txn->db;
MDB_stat stat;
int ret = mdb_stat(txn->txn, env->dbi, &stat);
if (ret != 0) {
return KNOT_ERROR;
}
return stat.ms_entries;
}
int find(knot_txn_t *txn, const knot_dname_t *key, knot_val_t *val, unsigned op)
{
struct lmdb_env *env = txn->db;
MDB_val db_key = NAME_TO_KEY(key);
MDB_val data = { 0, NULL };
int ret = mdb_get(txn->txn, env->dbi, &db_key, &data);
if (ret != 0) {
if (ret == MDB_NOTFOUND) {
return KNOT_ENOENT;
} else {
return KNOT_ERROR;
}
}
val->data = data.mv_data;
val->len = data.mv_size;
return KNOT_EOK;
}
int insert(knot_txn_t *txn, const knot_dname_t *key, knot_val_t *val)
{
struct lmdb_env *env = txn->db;
MDB_val db_key = NAME_TO_KEY(key);
MDB_val data = { val->len, val->data };
int ret = mdb_put(txn->txn, env->dbi, &db_key, &data, 0);
if (ret != 0) {
return KNOT_ERROR;
}
return KNOT_EOK;
}
int del(knot_txn_t *txn, const knot_dname_t *key)
{
struct lmdb_env *env = txn->db;
MDB_val db_key = NAME_TO_KEY(key);
MDB_val data = { 0, NULL };
int ret = mdb_del(txn->txn, env->dbi, &db_key, &data);
if (ret != 0) {
return KNOT_ERROR;
}
return KNOT_EOK;
}
knot_iter_t *iter_begin(knot_txn_t *txn, unsigned flags)
{
return NULL; /* NOTIMPL */
}
int iter_next(knot_iter_t *iter)
{
return KNOT_ENOTSUP;
}
const knot_dname_t *iter_key(knot_iter_t *iter)
{
return NULL; /* NOTIMPL */
}
int iter_val(knot_iter_t *iter, knot_val_t *val)
{
return KNOT_ENOTSUP;
}
int iter_finish(knot_iter_t *iter)
{
return KNOT_ENOTSUP;
}
struct namedb_api *namedb_lmdb_api(void)
{
static struct namedb_api api = {
init, deinit,
txn_begin, txn_commit, txn_abort,
count, find, insert, del,
iter_begin, iter_next, iter_key, iter_val, iter_finish
};
return &api;
}
#pragma once
#include "common/namedb/namedb.h"
struct namedb_api *namedb_lmdb_api(void);
\ No newline at end of file
#include "common/namedb/namedb_trie.h"
#include "common-knot/hattrie/hat-trie.h"
#include "libknot/errcode.h"
knot_namedb_t* init(const char *handle, mm_ctx_t *mm)
{
return NULL; /* NOTIMPL */
}
void deinit(knot_namedb_t *db)
{
}
int txn_begin(knot_namedb_t *db, knot_txn_t *txn, unsigned flags)
{
return KNOT_ENOTSUP;
}
int txn_commit(knot_txn_t *txn)
{
return KNOT_ENOTSUP;
}
void txn_abort(knot_txn_t *txn)
{
}
int count(knot_txn_t *txn)
{
return KNOT_ENOTSUP;
}
int find(knot_txn_t *txn, const knot_dname_t *key, knot_val_t *val, unsigned op)
{
return KNOT_ENOTSUP;
}
int insert(knot_txn_t *txn, const knot_dname_t *key, knot_val_t *val)
{
return KNOT_ENOTSUP;
}
int del(knot_txn_t *txn, const knot_dname_t *key)
{
return KNOT_ENOTSUP;
}
knot_iter_t *iter_begin(knot_txn_t *txn, unsigned flags)
{
return NULL; /* NOTIMPL */
}
int iter_next(knot_iter_t *iter)
{
return KNOT_ENOTSUP;
}
const knot_dname_t *iter_key(knot_iter_t *iter)
{
return NULL; /* NOTIMPL */
}
int iter_val(knot_iter_t *iter, knot_val_t *val)
{
return KNOT_ENOTSUP;
}
int iter_finish(knot_iter_t *iter)
{
return KNOT_ENOTSUP;
}
struct namedb_api *namedb_trie_api(void)
{
static struct namedb_api api = {
init, deinit,
txn_begin, txn_commit, txn_abort,
count, find, insert, del,
iter_begin, iter_next, iter_key, iter_val, iter_finish
};
return &api;
}
#pragma once
#include "common/namedb/namedb.h"
struct namedb_api *namedb_trie_api(void);
\ No newline at end of file
......@@ -33,6 +33,7 @@
#include "knot/knot.h"
#include "knot/ctl/remote.h"
#include "knot/nameserver/internet.h"
#include "knot/zone/timers.h"
/*
* Defaults.
......@@ -724,6 +725,9 @@ void conf_truncate(conf_t *conf, int unload_hooks)
/* Free remote control iface. */
conf_free_iface(conf->ctl.iface);
/* Close timers db. */
close_timers_db(conf);
}
void conf_free(conf_t *conf)
......@@ -795,6 +799,9 @@ int conf_open(const char* path)
/* Update hooks. */
conf_update_hooks(nconf);
/* Close old timers db. */
close_timers_db(oldconf);
/* Free old config. */
conf_free(oldconf);
......
......@@ -32,12 +32,14 @@
#include <stdbool.h>
#include <urcu.h>
#include <lmdb.h>
#include "libknot/dname.h"
#include "libknot/rrtype/tsig.h"
#include "libknot/dnssec/key.h"
#include "libknot/dnssec/policy.h"
#include "common-knot/lists.h"
#include "common/namedb/namedb.h"
#include "common/log.h"
#include "knot/updates/acl.h"
#include "common-knot/sockaddr.h"
......@@ -268,6 +270,11 @@ typedef struct conf_t {
int serial_policy; /*!< Serial policy when updating zone. */
struct query_plan *query_plan;
list_t query_modules;
/*
* Zone timers db
*/
knot_namedb_t *timers_db;
/*
* Remote control interface.
......
......@@ -32,6 +32,7 @@
#include "libknot/rrtype/soa.h"
#include "libknot/dnssec/random.h"
#include "libknot/packet/wire.h"
#include "knot/zone/timers.h"
#include "knot/dnssec/zone-sign.h"
#include "knot/dnssec/zone-nsec.h"
......@@ -174,7 +175,7 @@ static int remote_zone_refresh(zone_t *zone)
}
zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW);
return KNOT_EOK;
return write_zone_timers(conf(), zone);
}
/*! \brief Zone refresh callback. */
......
......@@ -36,6 +36,7 @@
#include "knot/ctl/process.h"
#include "knot/ctl/remote.h"
#include "knot/conf/conf.h"
#include "knot/zone/timers.h"
#include "knot/server/tcp-handler.h"
/* Signal flags. */
......@@ -324,6 +325,15 @@ int main(int argc, char **argv)
log_info("changed directory to %s", daemon_root);
}
}
/* Open zone timers db. */
int ret = open_timers_db(config);
if (ret != KNOT_EOK) {
server_deinit(&server);
conf_free(conf());
log_close();
return EXIT_FAILURE;
}
/* Register base signal handling. */
struct sigaction emptyset;
......
......@@ -24,6 +24,7 @@
#include "libknot/rrset.h"
#include "libknot/consts.h"
#include "knot/zone/zonedb.h"
#include "knot/zone/timers.h"
#include "libknot/common.h"
#include "libknot/packet/wire.h"
#include "knot/updates/acl.h"
......@@ -99,6 +100,10 @@ int notify_process_query(knot_pkt_t *pkt, struct query_data *qdata)
/* Incoming NOTIFY expires REFRESH timer and renews EXPIRE timer. */
zone_t *zone = (zone_t *)qdata->zone;
zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW);
int ret = write_zone_timers(conf(), zone);
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
return NS_PROC_DONE;
}
......
......@@ -22,6 +22,7 @@
#include "knot/server/tcp-handler.h"
#include "knot/updates/changesets.h"
#include "knot/dnssec/zone-events.h"
#include "knot/zone/timers.h"
#include "knot/zone/zone-load.h"
#include "knot/zone/zonefile.h"
#include "knot/zone/events/events.h"
......@@ -274,7 +275,8 @@ int event_reload(zone_t *zone)
uint32_t current_serial = zone_contents_serial(zone->contents);
log_zone_info(zone->name, "loaded, serial %u -> %u",
old_serial, current_serial);
return KNOT_EOK;
return write_zone_timers(conf(), zone);
fail:
zone_contents_deep_free(&contents);
......@@ -319,7 +321,7 @@ int event_refresh(zone_t *zone)
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
}
return KNOT_EOK;
return write_zone_timers(conf(), zone);
}
int event_xfer(zone_t *zone)
......
......@@ -24,6 +24,7 @@
#include "knot/zone/zone.h"
#include "knot/zone/zonefile.h"
#include "knot/zone/zonedb.h"
#include "knot/zone/timers.h"
#include "knot/server/server.h"
#include "libknot/dname.h"
......@@ -112,30 +113,63 @@ static void log_zone_load_info(const zone_t *zone, const char *zone_name,
log_zone_info(zone->name, "zone %s, serial %u", action, serial);
}
static bool timer_set(const struct timer_storage *timers, const int event_id)
{
for (size_t i = 0; i < PERSISTENT_EVENT_COUNT; ++i) {
if (timers[i].id == event_id) {
return true;
}
}
return false;
}
static time_t get_timer(const struct timer_storage *timers, const int event_id)
{
for (size_t i = 0; i < PERSISTENT_EVENT_COUNT; ++i) {
if (timers[i].id == event_id) {
return timers[i].timer;
}
}
return 0;
}
/*!
* \brief Load or reload the zone.
*
* \param conf Zone configuration.
* \param server Server.
* \param old_zone Already loaded zone (can be NULL).
* \param zone_conf Zone configuration.
* \param server Server.
* \param old_zone Already loaded zone (can be NULL).
*
* \return Error code, KNOT_EOK if successful.
*/
static zone_t *create_zone(conf_zone_t *conf, server_t *server, zone_t *old_zone)
static zone_t *create_zone(conf_zone_t *zone_conf, server_t *server, zone_t *old_zone)
{
assert(conf);
assert(zone_conf);
assert(server);
zone_t *zone = zone_new(conf);
struct timer_storage timers[PERSISTENT_EVENT_COUNT];
memset(timers, 0, sizeof(timers));
zone_t *zone = zone_new(zone_conf);
if (!zone) {
return NULL;
}
if (old_zone) {
zone->contents = old_zone->contents;
} else {
// Get persistent timers
int ret = read_zone_timers(conf(), zone, timers);
if (ret != KNOT_EOK) {
zone->conf = NULL;
zone_free(&zone);
return NULL;
}
}
zone_status_t zstatus = zone_file_status(old_zone, conf);
zone_status_t zstatus = zone_file_status(old_zone, zone_conf);
int result = zone_events_setup(zone, server->workers, &server->sched);
if (result != KNOT_EOK) {
......@@ -145,15 +179,26 @@ static zone_t *create_zone(conf_zone_t *conf, server_t *server, zone_t *old_zone
}
switch (zstatus) {
case ZONE_STATUS_FOUND_NEW:
case ZONE_STATUS_FOUND_NEW: // TIMERS: sort new
case ZONE_STATUS_FOUND_UPDATED:
/* Enqueueing makes the first zone load waitable. */
zone_events_enqueue(zone, ZONE_EVENT_RELOAD);
/* Replan DDNS processing if there are pending updates. */
zone_events_replan_ddns(zone, old_zone);
if (!old_zone) {
/* Reuse timers. */
}
break;
case ZONE_STATUS_BOOSTRAP:
zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW);
case ZONE_STATUS_BOOSTRAP: // TIMERS: sort bootstrap
if (!old_zone && timer_set(timers, ZONE_EVENT_REFRESH)) {
zone_events_schedule(zone, ZONE_EVENT_REFRESH,
get_timer(timers, ZONE_EVENT_REFRESH));
} else {
zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW);
}
break;
case ZONE_STATUS_NOT_FOUND:
break;
......@@ -167,7 +212,7 @@ static zone_t *create_zone(conf_zone_t *conf, server_t *server, zone_t *old_zone
assert(0);
}
log_zone_load_info(zone, conf->name, zstatus);
log_zone_load_info(zone, zone_conf->name, zstatus);
return zone;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment