Commit 94e685ef authored by Jan Kadlec's avatar Jan Kadlec
Browse files

Merge branch 'persistent-timers-fixes' into '1.6'

fixes: persistent timers

See merge request !294
parents a281f0aa c1f19f7e
......@@ -42,7 +42,7 @@ struct namedb_api {
/* Context operations */
knot_namedb_t *(*init)(const char *config, mm_ctx_t *mm);
int (*init)(const char *config, knot_namedb_t **db, mm_ctx_t *mm);
void (*deinit)(knot_namedb_t *db);
/* Transactions */
......
......@@ -18,12 +18,14 @@
#include <lmdb.h>
#include <sys/stat.h>
#include <unistd.h>
#include "common/namedb/namedb_lmdb.h"
#include "libknot/errcode.h"
#define LMDB_DIR_MODE 0770
#define LMDB_FILE_MODE 0660
#define LMDB_DIR_MODE 0770
#define LMDB_FILE_MODE 0660
#define LMDB_MAPSIZE (100 * 1024 * 1024)
struct lmdb_env
{
......@@ -42,11 +44,43 @@ static int create_env_dir(const char *path)
return KNOT_EOK;
}
/*!
* \brief Convert error code returned by LMDB to Knot DNS error code.
*
* LMDB defines own error codes but uses additional ones from libc. All LMDB
* specific error codes are translated to KNOT_DATABASE_ERROR.
*/
static int lmdb_error_to_knot(int error)
{
if (error == MDB_SUCCESS) {
return KNOT_EOK;
}
if (MDB_KEYEXIST <= error && error <= MDB_LAST_ERRCODE) {
return KNOT_DATABASE_ERROR;
}
return knot_errno_to_error(error);
}
static int dbase_open(struct lmdb_env *env, const char *path)
{
int ret = mdb_env_create(&env->env);
if (ret != 0) {
return ret;
return lmdb_error_to_knot(ret);
}
long page_size = sysconf(_SC_PAGESIZE);
if (page_size <= 0) {
mdb_env_close(env->env);
return KNOT_EINVAL;
}
size_t map_size = (LMDB_MAPSIZE / page_size) * page_size;
ret = mdb_env_set_mapsize(env->env, map_size);
if (ret != 0) {
mdb_env_close(env->env);
return lmdb_error_to_knot(ret);
}
ret = create_env_dir(path);
......@@ -58,27 +92,27 @@ static int dbase_open(struct lmdb_env *env, const char *path)
ret = mdb_env_open(env->env, path, 0, LMDB_FILE_MODE);
if (ret != 0) {
mdb_env_close(env->env);
return ret;
return lmdb_error_to_knot(ret);
}
MDB_txn *txn = NULL;
ret = mdb_txn_begin(env->env, NULL, 0, &txn);
if (ret != 0) {
mdb_env_close(env->env);
return ret;
return lmdb_error_to_knot(ret);
}
ret = mdb_open(txn, NULL, 0, &env->dbi);
if (ret != 0) {
mdb_txn_abort(txn);
mdb_env_close(env->env);
return ret;
return lmdb_error_to_knot(ret);
}
ret = mdb_txn_commit(txn);
if (ret != 0) {
mdb_env_close(env->env);
return ret;
return lmdb_error_to_knot(ret);
}
return 0;
......@@ -90,22 +124,24 @@ static void dbase_close(struct lmdb_env *env)
mdb_env_close(env->env);
}
static knot_namedb_t *init(const char *config, mm_ctx_t *mm)
static int init(const char *config, knot_namedb_t **db_ptr, mm_ctx_t *mm)
{
struct lmdb_env *env = mm_alloc(mm, sizeof(struct lmdb_env));
if (env == NULL) {
return NULL;
return KNOT_ENOMEM;
}
memset(env, 0, sizeof(struct lmdb_env));
int ret = dbase_open(env, config);
if (ret != 0) {
mm_free(mm, env);
return NULL;
return ret;
}
env->pool = mm;
return env;
*db_ptr = env;
return KNOT_EOK;
}
static void deinit(knot_namedb_t *db)
......@@ -131,7 +167,7 @@ static int txn_begin(knot_namedb_t *db, knot_txn_t *txn, unsigned flags)
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 lmdb_error_to_knot(ret);
}
return KNOT_EOK;
......@@ -141,7 +177,7 @@ static int txn_commit(knot_txn_t *txn)
{
int ret = mdb_txn_commit((MDB_txn *)txn->txn);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
return KNOT_EOK;
......@@ -159,7 +195,7 @@ static int count(knot_txn_t *txn)
MDB_stat stat;
int ret = mdb_stat(txn->txn, env->dbi, &stat);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
return stat.ms_entries;
......@@ -171,13 +207,12 @@ static int find(knot_txn_t *txn, knot_val_t *key, knot_val_t *val, unsigned flag
MDB_val db_key = { key->len, key->data };
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;
return lmdb_error_to_knot(ret);
}
}
......@@ -193,7 +228,7 @@ static int insert(knot_txn_t *txn, knot_val_t *key, knot_val_t *val, unsigned fl
MDB_cursor *cursor = NULL;
int ret = mdb_cursor_open(txn->txn, env->dbi, &cursor);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
MDB_val db_key = { key->len, key->data };
......@@ -206,7 +241,7 @@ static int insert(knot_txn_t *txn, knot_val_t *key, knot_val_t *val, unsigned fl
// Insert new item
ret = mdb_put(txn->txn, env->dbi, &db_key, &data, 0);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
return KNOT_EOK;
......@@ -218,7 +253,7 @@ static int insert(knot_txn_t *txn, knot_val_t *key, knot_val_t *val, unsigned fl
ret = mdb_cursor_put(cursor, &db_key, &data, MDB_CURRENT);
mdb_cursor_close(cursor);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
return KNOT_EOK;
......@@ -232,7 +267,7 @@ static int del(knot_txn_t *txn, knot_val_t *key)
int ret = mdb_del(txn->txn, env->dbi, &db_key, &data);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
return KNOT_EOK;
......@@ -277,7 +312,7 @@ static int iter_key(knot_iter_t *iter, knot_val_t *key)
MDB_val mdb_key, mdb_val;
int ret = mdb_cursor_get(cursor, &mdb_key, &mdb_val, MDB_GET_CURRENT);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
key->data = mdb_key.mv_data;
......@@ -292,7 +327,7 @@ static int iter_val(knot_iter_t *iter, knot_val_t *val)
MDB_val mdb_key, mdb_val;
int ret = mdb_cursor_get(cursor, &mdb_key, &mdb_val, MDB_GET_CURRENT);
if (ret != 0) {
return KNOT_ERROR;
return lmdb_error_to_knot(ret);
}
val->data = mdb_val.mv_data;
......@@ -310,9 +345,9 @@ static void iter_finish(knot_iter_t *iter)
mdb_cursor_close(cursor);
}
struct namedb_api *namedb_lmdb_api(void)
const struct namedb_api *namedb_lmdb_api(void)
{
static struct namedb_api api = {
static const struct namedb_api api = {
"lmdb",
init, deinit,
txn_begin, txn_commit, txn_abort,
......@@ -327,7 +362,7 @@ struct namedb_api *namedb_lmdb_api(void)
#include <stdlib.h>
struct namedb_api *namedb_lmdb_api(void)
const struct namedb_api *namedb_lmdb_api(void)
{
return NULL;
}
......
......@@ -18,4 +18,4 @@
#include "common/namedb/namedb.h"
struct namedb_api *namedb_lmdb_api(void);
const struct namedb_api *namedb_lmdb_api(void);
......@@ -18,9 +18,20 @@
#include "common-knot/hattrie/hat-trie.h"
#include "libknot/errcode.h"
static knot_namedb_t *init(const char *handle, mm_ctx_t *mm)
static int init(const char *config, knot_namedb_t **db, mm_ctx_t *mm)
{
return hattrie_create_n(TRIE_BUCKET_SIZE, mm);
if (config != NULL || db == NULL) {
return KNOT_EINVAL;
}
hattrie_t *trie = hattrie_create_n(TRIE_BUCKET_SIZE, mm);
if (!trie) {
return KNOT_ENOMEM;
}
*db = trie;
return KNOT_EOK;
}
static void deinit(knot_namedb_t *db)
......@@ -126,9 +137,9 @@ static void iter_finish(knot_iter_t *iter)
hattrie_iter_free((hattrie_iter_t *)iter);
}
struct namedb_api *namedb_trie_api(void)
const struct namedb_api *namedb_trie_api(void)
{
static struct namedb_api api = {
static const struct namedb_api api = {
"hattrie",
init, deinit,
txn_begin, txn_commit, txn_abort,
......
......@@ -18,4 +18,4 @@
#include "common/namedb/namedb.h"
struct namedb_api *namedb_trie_api(void);
const struct namedb_api *namedb_trie_api(void);
......@@ -33,7 +33,6 @@
#include "knot/knot.h"
#include "knot/ctl/remote.h"
#include "knot/nameserver/internet.h"
#include "knot/zone/timers.h"
/*
* Defaults.
......@@ -725,10 +724,6 @@ 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->timers_db);
conf->timers_db = NULL;
}
void conf_free(conf_t *conf)
......@@ -781,12 +776,6 @@ int conf_open(const char* path)
return ret;
}
/* Open zone timers db. */
nconf->timers_db = open_timers_db(nconf->storage);
if (nconf->timers_db == NULL) {
log_warning("cannot open timers db");
}
/* Replace current config. */
conf_t **current_config = &s_config;
conf_t *oldconf = rcu_xchg_pointer(current_config, nconf);
......@@ -810,7 +799,6 @@ int conf_open(const char* path)
/* Free old config. */
conf_free(oldconf);
}
return KNOT_EOK;
}
......
......@@ -38,7 +38,6 @@
#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"
......@@ -269,11 +268,6 @@ typedef struct conf_t {
struct query_plan *query_plan;
list_t query_modules;
/*
* Zone timers db
*/
knot_namedb_t *timers_db;
/*
* Remote control interface.
*/
......
......@@ -100,7 +100,7 @@ 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()->timers_db, zone);
int ret = zone_events_write_persistent(zone);
if (ret != KNOT_EOK) {
return NS_PROC_FAIL;
}
......
......@@ -28,6 +28,7 @@
#include "knot/server/tcp-handler.h"
#include "knot/conf/conf.h"
#include "knot/worker/pool.h"
#include "knot/zone/timers.h"
#include "knot/zone/zonedb-load.h"
#include "libknot/dname.h"
#include "libknot/dnssec/crypto.h"
......@@ -329,6 +330,9 @@ void server_deinit(server_t *server)
/* Free remaining events. */
evsched_deinit(&server->sched);
/* Close persistent timers database. */
close_timers_db(server->timers_db);
/* Clear the structure. */
memset(server, 0, sizeof(server_t));
}
......@@ -578,7 +582,19 @@ int server_reconfigure(const struct conf_t *conf, void *data)
return ret;
}
int server_update_zones(const struct conf_t *conf, void *data)
static void reopen_timers_database(const conf_t *conf, server_t *server)
{
close_timers_db(server->timers_db);
server->timers_db = NULL;
int ret = open_timers_db(conf->storage, &server->timers_db);
if (ret != KNOT_EOK && ret != KNOT_ENOTSUP) {
log_warning("cannot open persistent timers DB (%s)",
knot_strerror(ret));
}
}
int server_update_zones(const conf_t *conf, void *data)
{
server_t *server = (server_t *)data;
......@@ -593,6 +609,7 @@ int server_update_zones(const struct conf_t *conf, void *data)
worker_pool_wait(server->workers);
/* Reload zone database and free old zones. */
reopen_timers_database(conf, server);
int ret = zonedb_reload(conf, server);
/* Trim extra heap. */
......
......@@ -32,6 +32,7 @@
#include "common-knot/evsched.h"
#include "common-knot/lists.h"
#include "common-knot/fdset.h"
#include "common/namedb/namedb.h"
#include "knot/server/dthreads.h"
#include "knot/server/net.h"
#include "knot/server/rrl.h"
......@@ -93,7 +94,9 @@ typedef struct server_t {
/*! \brief Server state tracking. */
volatile unsigned state;
knot_zonedb_t *zone_db; /*!< Zone database. */
/*! \brief Zone database. */
knot_zonedb_t *zone_db;
knot_namedb_t *timers_db;
/*! \brief I/O handlers. */
unsigned tu_size;
......
......@@ -18,12 +18,14 @@
#include <time.h>
#include "common-knot/evsched.h"
#include "common/namedb/namedb.h"
#include "knot/server/server.h"
#include "knot/worker/pool.h"
#include "knot/zone/zone.h"
#include "knot/zone/events/events.h"
#include "knot/zone/events/handlers.h"
#include "knot/zone/events/replan.h"
#include "knot/zone/timers.h"
/* ------------------------- internal timers -------------------------------- */
......@@ -232,7 +234,8 @@ int zone_events_init(zone_t *zone)
return KNOT_EOK;
}
int zone_events_setup(zone_t *zone, worker_pool_t *workers, evsched_t *scheduler)
int zone_events_setup(struct zone_t *zone, worker_pool_t *workers,
evsched_t *scheduler, knot_namedb_t *timers_db)
{
if (!zone || !workers || !scheduler) {
return KNOT_EINVAL;
......@@ -246,6 +249,7 @@ int zone_events_setup(zone_t *zone, worker_pool_t *workers, evsched_t *scheduler
zone->events.event = event;
zone->events.pool = workers;
zone->events.timers_db = timers_db;
return KNOT_EOK;
}
......@@ -409,3 +413,16 @@ void zone_events_replan_ddns(struct zone_t *zone, const struct zone_t *old_zone)
replan_update(zone, (zone_t *)old_zone);
}
}
int zone_events_write_persistent(zone_t *zone)
{
if (!zone) {
return KNOT_EINVAL;
}
if (zone->events.timers_db == NULL) {
return KNOT_EOK;
}
return write_zone_timers(zone->events.timers_db, zone);
}
......@@ -20,6 +20,7 @@
#include <stdbool.h>
#include "common-knot/evsched.h"
#include "common/namedb/namedb.h"
#include "knot/worker/pool.h"
/* Timer special values. */
......@@ -51,6 +52,7 @@ typedef struct zone_events {
event_t *event; //!< Scheduler event.
worker_pool_t *pool; //!< Server worker pool.
knot_namedb_t *timers_db; //!< Persistent zone timers database.
task_t task; //!< Event execution context.
time_t time[ZONE_EVENT_COUNT]; //!< Event execution times.
......@@ -74,11 +76,12 @@ int zone_events_init(struct zone_t *zone);
* \param zone Zone to setup.
* \param workers Worker thread pool.
* \param scheduler Event scheduler.
* \param timers_db Persistent timers database. Can be NULL.
*
* \return KNOT_E*
*/
int zone_events_setup(struct zone_t *zone, worker_pool_t *workers,
evsched_t *scheduler);
evsched_t *scheduler, knot_namedb_t *timers_db);
/*!
* \brief Deinitialize zone events.
......@@ -185,3 +188,10 @@ void zone_events_update(struct zone_t *zone, struct zone_t *old_zone);
* \param old_zone Zone with old config.
*/
void zone_events_replan_ddns(struct zone_t *zone, const struct zone_t *old_zone);
/*!
* \brief Write persistent timers to timers database.
*
* \return KNOT_E*
*/
int zone_events_write_persistent(struct zone_t *zone);
......@@ -276,7 +276,7 @@ int event_reload(zone_t *zone)
log_zone_info(zone->name, "loaded, serial %u -> %u",
old_serial, current_serial);
return write_zone_timers(conf()->timers_db, zone);
return zone_events_write_persistent(zone);
fail:
zone_contents_deep_free(&contents);
......@@ -321,7 +321,7 @@ int event_refresh(zone_t *zone)
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
}
return write_zone_timers(conf()->timers_db, zone);
return zone_events_write_persistent(zone);
}
int event_xfer(zone_t *zone)
......
......@@ -56,6 +56,12 @@ static bool event_persistent(size_t event)
return event_id_to_key[event] != 0;
}
/*! \brief Clear array of timers. */
static void clear_timers(time_t *timers)
{
memset(timers, 0, ZONE_EVENT_COUNT * sizeof(time_t));
}
/*! \brief Stores timers for persistent events. */
static int store_timers(knot_txn_t *txn, zone_t *zone)
{
......@@ -87,21 +93,20 @@ static int store_timers(knot_txn_t *txn, zone_t *zone)
static int read_timers(knot_txn_t *txn, const zone_t *zone, time_t *timers)
{
const struct namedb_api *db_api = namedb_lmdb_api();
assert(db_api);
knot_val_t key = { .len = knot_dname_size(zone->name), .data = zone->name };
knot_val_t val;
int ret = db_api->find(txn, &key, &val, 0);
if (ret != KNOT_EOK) {
if (ret == KNOT_ENOENT) {
// New zone, no entry in db.
memset(timers, 0, ZONE_EVENT_COUNT * sizeof(time_t));
return KNOT_EOK;
}
if (ret != KNOT_EOK && ret != KNOT_ENOENT) {
return ret;
}
// Set unknown/unset event timers to 0.
memset(timers, 0, ZONE_EVENT_COUNT * sizeof(time_t));
clear_timers(timers);
if (ret == KNOT_ENOENT) {
return KNOT_EOK;
}
const size_t stored_event_count = val.len / EVENT_KEY_PAIR_SIZE;
size_t offset = 0;
......@@ -120,40 +125,50 @@ static int read_timers(knot_txn_t *txn, const zone_t *zone, time_t *timers)
/* -------- API ------------------------------------------------------------- */
knot_namedb_t *open_timers_db(const char *storage)
int open_timers_db(const char *storage, knot_namedb_t **db_ptr)
{
#ifndef HAVE_LMDB
// No-op if we don't have lmdb, all other operations will no-op as well then
return NULL;
#else
if (!storage || !db_ptr) {
return KNOT_EINVAL;
}
const struct namedb_api *api = namedb_lmdb_api();
if (!api) {
return KNOT_ENOTSUP;
}
char *path = sprintf_alloc("%s/timers", storage);
if (!path) {
return NULL;
return KNOT_ENOMEM;
}
knot_namedb_t *db = namedb_lmdb_api()->init(path, NULL);
int ret = api->init(path, db_ptr, NULL);
free(path);
return db;
#endif
return ret;
}
void close_timers_db(knot_namedb_t *timer_db)
{
if (timer_db) {
namedb_lmdb_api()->deinit(timer_db);
if (!timer_db) {
return;
}
const struct namedb_api *db_api = namedb_lmdb_api();
assert(db_api);
db_api->deinit(timer_db);
}