Commit bfb9686b authored by Libor Peltan's avatar Libor Peltan Committed by Petr Špaček

kr_cache_gc: initial commit

parent 85aaddf7
/* Copyright (C) 2017 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/>.
*/
/*!
* \brief Simple write-once allocation-optimal dynamic array.
*
* Include it into your .c file
*
* prefix - identifier prefix, e.g. ptr -> struct ptr_dynarray, ptr_dynarray_add(), ...
* ntype - data type to be stored. Let it be a number, pointer or small struct
* initial_capacity - how many data items will be allocated on stac and copied with assignment
*
* prefix_dynarray_add() - add a data item
* prefix_dynarray_fix() - call EVERYTIME the array is copied from some already invalid stack
* prefix_dynarray_free() - call EVERYTIME you dismiss all copies of the array
*
*/
#include <stdlib.h>
#include <assert.h>
#pragma once
#define DYNARRAY_VISIBILITY_STATIC static
#define DYNARRAY_VISIBILITY_PUBLIC
#define DYNARRAY_VISIBILITY_LIBRARY __public__
#define dynarray_declare(prefix, ntype, visibility, initial_capacity) \
typedef struct prefix ## _dynarray { \
ssize_t capacity; \
ssize_t size; \
ntype *(*arr)(struct prefix ## _dynarray *dynarray); \
ntype init[initial_capacity]; \
ntype *_arr; \
} prefix ## _dynarray_t; \
\
visibility ntype *prefix ## _dynarray_arr(prefix ## _dynarray_t *dynarray); \
visibility void prefix ## _dynarray_add(prefix ## _dynarray_t *dynarray, \
ntype const *to_add); \
visibility void prefix ## _dynarray_free(prefix ## _dynarray_t *dynarray);
#define dynarray_foreach(prefix, ntype, ptr, array) \
for (ntype *ptr = prefix ## _dynarray_arr(&(array)); \
ptr < prefix ## _dynarray_arr(&(array)) + (array).size; ptr++)
#define dynarray_define(prefix, ntype, visibility) \
\
static void prefix ## _dynarray_free__(struct prefix ## _dynarray *dynarray) \
{ \
if (dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)) { \
free(dynarray->_arr); \
} \
} \
\
__attribute__((unused)) \
visibility ntype *prefix ## _dynarray_arr(struct prefix ## _dynarray *dynarray) \
{ \
assert(dynarray->size <= dynarray->capacity); \
return (dynarray->capacity <= sizeof(dynarray->init) / sizeof(*dynarray->init) ? \
dynarray->init : dynarray->_arr); \
} \
\
static ntype *prefix ## _dynarray_arr_init__(struct prefix ## _dynarray *dynarray) \
{ \
assert(dynarray->capacity == sizeof(dynarray->init) / sizeof(*dynarray->init)); \
return dynarray->init; \
} \
\
static ntype *prefix ## _dynarray_arr_arr__(struct prefix ## _dynarray *dynarray) \
{ \
assert(dynarray->capacity > sizeof(dynarray->init) / sizeof(*dynarray->init)); \
return dynarray->_arr; \
} \
\
__attribute__((unused)) \
visibility void prefix ## _dynarray_add(struct prefix ## _dynarray *dynarray, \
ntype const *to_add) \
{ \
if (dynarray->capacity < 0) { \
return; \
} \
if (dynarray->capacity == 0) { \
dynarray->capacity = sizeof(dynarray->init) / sizeof(*dynarray->init); \
dynarray->arr = prefix ## _dynarray_arr_init__; \
} \
if (dynarray->size >= dynarray->capacity) { \
ssize_t new_capacity = dynarray->capacity * 2 + 1; \
ntype *new_arr = calloc(new_capacity, sizeof(ntype)); \
if (new_arr == NULL) { \
prefix ## _dynarray_free__(dynarray); \
dynarray->capacity = dynarray->size = -1; \
return; \
} \
if (dynarray->capacity > 0) { \
memcpy(new_arr, prefix ## _dynarray_arr(dynarray), \
dynarray->capacity * sizeof(ntype)); \
} \
prefix ## _dynarray_free__(dynarray); \
dynarray->_arr = new_arr; \
dynarray->capacity = new_capacity; \
dynarray->arr = prefix ## _dynarray_arr_arr__; \
} \
prefix ## _dynarray_arr(dynarray)[dynarray->size++] = *to_add; \
} \
\
__attribute__((unused)) \
visibility void prefix ## _dynarray_free(struct prefix ## _dynarray *dynarray) \
{ \
prefix ## _dynarray_free__(dynarray); \
memset(dynarray, 0, sizeof(*dynarray)); \
}
......@@ -63,6 +63,7 @@ struct entry_apex;
/** Check basic consistency of entry_h for 'E' entries, not looking into ->data.
* (for is_packet the length of data is checked)
*/
KR_EXPORT
struct entry_h * entry_h_consistent(knot_db_val_t data, uint16_t type);
struct entry_apex * entry_apex_consistent(knot_db_val_t val);
......
all: kr_cache_gc
kr_cache_gc: kr_cache_gc.c ../../contrib/dynarray.h ../../lib/defines.h ../../lib/cache/api.h ../../lib/cache/impl.h
gcc -std=gnu99 -o $@ $< -Wl,-Bdynamic -L../../lib -lknot -lkres -I../.. -I../../contrib -I/usr/include/luajit-2.0
// standard includes
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
// libknot includes
#include <libknot/libknot.h>
// resolver includes
#include <contrib/dynarray.h>
#include <lib/cache/api.h>
#include <lib/cache/impl.h>
#include <lib/defines.h>
int64_t now = 1523701784;
static const uint16_t *key_consistent(knot_db_val_t key)
{
const static uint16_t NSEC1 = KNOT_RRTYPE_NSEC;
uint8_t *p = key.data;
while(*p != 0) {
while(*p++ != 0) {
if (p - (uint8_t *)key.data >= key.len) {
return NULL;
}
}
}
if (p - (uint8_t *)key.data >= key.len) {
return NULL;
}
switch (*++p) {
case 'E':
return (p + 2 - (uint8_t *)key.data >= key.len ? NULL : (uint16_t *)(p + 1));
case '1':
return &NSEC1;
default:
return NULL;
}
}
struct libknot_lmdb_env
{
bool shared;
unsigned dbi;
void *env;
knot_mm_t *pool;
};
struct kres_lmdb_env
{
size_t mapsize;
unsigned dbi;
void *env;
// sub-struct txn ommited
};
static knot_db_t *knot_db_t_kres2libknot(const knot_db_t *db)
{
const struct kres_lmdb_env *kres_db = db; // this is struct lmdb_env as in resolver/cdb_lmdb.c
struct libknot_lmdb_env *libknot_db = malloc(sizeof(*libknot_db));
if (libknot_db != NULL) {
libknot_db->shared = false;
libknot_db->pool = NULL;
libknot_db->env = kres_db->env;
libknot_db->dbi = kres_db->dbi;
}
return libknot_db;
}
dynarray_declare(entry, knot_db_val_t, static, 256);
dynarray_define(entry, knot_db_val_t, static);
int main(int argc, char *argv[])
{
if (argc < 2 || argv[1][0] == '-') {
printf("Usage: %s <path/to/kres/cache>\n", argv[0]);
return 0;
}
const char *cache = argv[1];
char cache_data[strlen(cache) + 10];
snprintf(cache_data, sizeof(cache_data), "%s/data.mdb", cache);
struct stat st = { 0 };
if (stat(cache, &st) || !(st.st_mode & S_IFDIR) || stat(cache_data, &st)) {
printf("Error: %s does not exist or is not a LMDB.\n", cache);
return 1;
}
size_t cache_size = st.st_size;
struct kr_cdb_opts opts = { cache, cache_size };
struct kr_cache krc = { 0 };
int ret = kr_cache_open(&krc, NULL, &opts, NULL);
if (ret || krc.db == NULL) {
printf("Error opening Resolver cache (%s).\n", kr_strerror(ret));
return 2;
}
const knot_db_api_t *api = knot_db_lmdb_api();
knot_db_txn_t txn = { 0 };
knot_db_t *db = knot_db_t_kres2libknot(krc.db);
if (db == NULL) {
printf("Out of memory.\n");
ret = KNOT_ENOMEM;
goto fail;
}
ret = api->txn_begin(db, &txn, 0);
if (ret != KNOT_EOK) {
printf("Error starting DB transaction (%s).\n", knot_strerror(ret));
goto fail;
}
knot_db_iter_t *it = NULL;
it = api->iter_begin(&txn, KNOT_DB_FIRST);
if (it == NULL) {
printf("Error iterating DB.\n");
ret = KNOT_ERROR;
goto fail;
}
entry_dynarray_t to_del = { 0 };
while (it != NULL) {
knot_db_val_t key = { 0 }, val = { 0 };
if ((ret = api->iter_key(it, &key)) != KNOT_EOK ||
(ret = api->iter_val(it, &val)) != KNOT_EOK) {
printf("Warning: skipping a key due to error (%s).\n", knot_strerror(ret));
}
const uint16_t *entry_type = ret == KNOT_EOK ? key_consistent(key) : NULL;
if (entry_type == NULL) {
printf("Inconsistent entry.\n");
} else {
char type_s[32] = { 0 };
knot_rrtype_to_string(*entry_type, type_s, sizeof(type_s));
struct entry_h *entry = entry_h_consistent(val, *entry_type);
int64_t over = entry->time + entry->ttl;
over -= now;
printf("%s time=%u ttl=%u rel=%ld\n", type_s, entry->time, entry->ttl, over);
if (over < 0) {
entry_dynarray_add(&to_del, &key);
}
}
it = api->iter_next(it);
}
dynarray_foreach(entry, knot_db_val_t, i, to_del) {
ret = api->del(&txn, i);
if (ret != KNOT_EOK) {
printf("Warning: skipping deleting because of error (%s)\n", knot_strerror(ret));
}
}
entry_dynarray_free(&to_del);
//api->iter_finish(it);
//it = NULL;
ret = api->txn_commit(&txn);
txn.txn = NULL;
fail:
api->iter_finish(it);
if (txn.txn) {
api->txn_abort(&txn);
}
free(db);
kr_cache_close(&krc);
return (ret ? 10 : 0);
}
utils: kr_cache_gc
kr_cache_gc:
make -C utils/kr_cache_gc all
.PHONY: utils kr_cache_gc
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