fixup! Introduction of cfgmgr

This commit is contained in:
Colin Vidal
2025-02-24 10:33:02 +01:00
parent 5c072afe1a
commit da16cba48a
3 changed files with 1154 additions and 734 deletions
+262 -251
View File
@@ -24,8 +24,6 @@
#include <isccfg/cfgmgr.h>
#define RANDOM isc_random_uniform(UINT32_MAX);
/*
* See MDB_MAXKEYSIZE documentation, but not accessible as defined in
* internal implementation. Having key with longer size won't work
@@ -50,10 +48,9 @@ typedef struct {
bool readonly;
} context_t;
static isc_mem_t *mctx = NULL;
static const char *dbpath = NULL;
static MDB_env *env = NULL;
static thread_local context_t ctx =
static isc_mem_t *isc__cfgmgr_mctx = NULL;
static MDB_env *isc__cfgmgr_env = NULL;
static thread_local context_t isc__cfgmgr_ctx =
(context_t){ .openedclauses = ISC_LIST_INITIALIZER,
.prefix = NULL,
.buffer = NULL,
@@ -62,13 +59,13 @@ static thread_local context_t ctx =
.readonly = false };
static unsigned long
parseid(const char *dbkey) {
isc__cfgmgr_parseid(const char *dbkey) {
unsigned long id = 0;
size_t idstarts;
size_t idends;
size_t keylen;
REQUIRE(ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(dbkey != NULL);
/*
@@ -76,8 +73,8 @@ parseid(const char *dbkey) {
* prefix is "foo" then the key will be "foo.1235..." so the
* start of the id (character 1) is at character index 4
*/
idstarts = strlen(ctx.buffer);
INSIST(idstarts > 0 && ctx.buffer[idstarts - 1] == '.');
idstarts = strlen(isc__cfgmgr_ctx.buffer);
INSIST(idstarts > 0 && isc__cfgmgr_ctx.buffer[idstarts - 1] == '.');
idends = idstarts;
/*
@@ -101,33 +98,36 @@ parseid(const char *dbkey) {
}
isc_result_t
cfgmgr_init(isc_mem_t *mctx_, const char *dbpath_) {
isc_cfgmgr_init(isc_mem_t *mctx, const char *dbpath) {
int result = ISC_R_SUCCESS;
char dbname[BUFLEN];
char dblockname[BUFLEN];
uint32_t random;
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses));
REQUIRE(ctx.prefix == NULL);
REQUIRE(ctx.buffer == NULL);
REQUIRE(ctx.cursor == NULL);
REQUIRE(ctx.txn == NULL);
REQUIRE(dbpath == NULL);
REQUIRE(mctx == NULL);
REQUIRE(env == NULL);
REQUIRE(mctx_ != NULL);
REQUIRE(dbpath_ != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses));
REQUIRE(isc__cfgmgr_ctx.prefix == NULL);
REQUIRE(isc__cfgmgr_ctx.buffer == NULL);
REQUIRE(isc__cfgmgr_ctx.cursor == NULL);
REQUIRE(isc__cfgmgr_ctx.txn == NULL);
REQUIRE(isc__cfgmgr_mctx == NULL);
REQUIRE(isc__cfgmgr_env == NULL);
REQUIRE(mctx != NULL);
isc_mem_attach(mctx_, &mctx);
INSIST(mctx != NULL);
isc_mem_attach(mctx, &isc__cfgmgr_mctx);
INSIST(isc__cfgmgr_mctx != NULL);
dbpath = dbpath_;
result = mdb_env_create(&env);
result = mdb_env_create(&isc__cfgmgr_env);
if (result != 0) {
result = ISC_R_FAILURE;
goto cleanup;
}
INSIST(isc__cfgmgr_env != NULL);
random = isc_random32();
REQUIRE(snprintf(dbname, BUFLEN, "%s-%u", dbpath, random) < BUFLEN);
REQUIRE(snprintf(dblockname, BUFLEN, "%s-%u-lock", dbpath, random) <
BUFLEN);
/*
* Using MDB_NOSYNC as it avoids force disk flush after a
* transaction. It's quicker and in our case we don't need it
@@ -135,11 +135,8 @@ cfgmgr_init(isc_mem_t *mctx_, const char *dbpath_) {
* corruption doesn't matter: as soon as the process is dead,
* the disk data is dead as well)
*/
random = RANDOM();
REQUIRE(snprintf(dbname, BUFLEN, "%s-%u", dbpath, random) < BUFLEN);
REQUIRE(snprintf(dblockname, BUFLEN, "%s-%u-lock", dbpath, random) <
BUFLEN);
result = mdb_env_open(env, dbname, MDB_NOSYNC | MDB_NOSUBDIR, 0600);
result = mdb_env_open(isc__cfgmgr_env, dbname,
MDB_NOSYNC | MDB_NOSUBDIR, 0600);
if (result != 0) {
result = ISC_R_FAILURE;
goto cleanup;
@@ -148,13 +145,12 @@ cfgmgr_init(isc_mem_t *mctx_, const char *dbpath_) {
remove(dbname);
remove(dblockname);
ENSURE(env != NULL);
goto out;
cleanup:
if (env != NULL) {
mdb_env_close(env);
env = NULL;
if (isc__cfgmgr_env != NULL) {
mdb_env_close(isc__cfgmgr_env);
isc__cfgmgr_env = NULL;
}
out:
@@ -162,7 +158,7 @@ out:
}
void
cfgmgr_deinit(void) {
isc_cfgmgr_deinit(void) {
/*
* Well, I'm on the fence about those context checks... It's
* good to have, but because they thread specific, it doesn't
@@ -173,54 +169,57 @@ cfgmgr_deinit(void) {
* an extra clue, because destroying the context will assert
* anyway, as some memory would not be released yet).
*/
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses));
REQUIRE(ctx.prefix == NULL);
REQUIRE(ctx.buffer == NULL);
REQUIRE(ctx.cursor == NULL);
REQUIRE(ctx.txn == NULL);
REQUIRE(mctx != NULL);
REQUIRE(env != NULL);
mdb_env_close(env);
env = NULL;
dbpath = NULL;
isc_mem_detach(&mctx);
INSIST(mctx == NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses));
REQUIRE(isc__cfgmgr_ctx.prefix == NULL);
REQUIRE(isc__cfgmgr_ctx.buffer == NULL);
REQUIRE(isc__cfgmgr_ctx.cursor == NULL);
REQUIRE(isc__cfgmgr_ctx.txn == NULL);
REQUIRE(isc__cfgmgr_mctx != NULL);
REQUIRE(isc__cfgmgr_env != NULL);
mdb_env_close(isc__cfgmgr_env);
isc__cfgmgr_env = NULL;
isc_mem_detach(&isc__cfgmgr_mctx);
INSIST(isc__cfgmgr_mctx == NULL);
}
static void
buildkey(const char *name, bool trailingdot) {
isc__cfgmgr_buildkey(const char *name, bool trailingdot) {
size_t written;
const char *prefix = ISC_LIST_EMPTY(ctx.openedclauses) ? ""
: ctx.prefix;
const char *prefix = ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses)
? ""
: isc__cfgmgr_ctx.prefix;
const char *dot = trailingdot ? "." : "";
REQUIRE(ctx.buffer != NULL);
written = snprintf(ctx.buffer, BUFLEN, "%s%s%s", prefix, name, dot);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
written = snprintf(isc__cfgmgr_ctx.buffer, BUFLEN, "%s%s%s", prefix,
name, dot);
INSIST(written <= BUFLEN);
}
static isc_result_t
open_findclause(const char *name, unsigned long *id) {
isc__cfgmgr_findclause(const char *name, unsigned long *id) {
isc_result_t result = ISC_R_SUCCESS;
MDB_val dbkey;
size_t dotpos = 0;
REQUIRE(name != NULL);
REQUIRE(ctx.buffer != NULL);
REQUIRE(ctx.txn != NULL);
REQUIRE(ctx.cursor != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
buildkey(name, true);
dotpos = strlen(ctx.buffer) - 1;
dbkey = (MDB_val){ .mv_size = strlen(ctx.buffer) + 1,
.mv_data = (char *)ctx.buffer };
isc__cfgmgr_buildkey(name, true);
dotpos = strlen(isc__cfgmgr_ctx.buffer) - 1;
dbkey = (MDB_val){ .mv_size = strlen(isc__cfgmgr_ctx.buffer) + 1,
.mv_data = (char *)isc__cfgmgr_ctx.buffer };
/*
* Let's use LMDB prefix search because the first clause
* key/val won't just have the "name.id" prefix, but also the
* id and the first property name (so "name.id.prop").
*/
if (mdb_cursor_get(ctx.cursor, &dbkey, NULL, MDB_SET_RANGE) != 0) {
if (mdb_cursor_get(isc__cfgmgr_ctx.cursor, &dbkey, NULL,
MDB_SET_RANGE) != 0)
{
result = ISC_R_NOTFOUND;
goto out;
}
@@ -238,120 +237,123 @@ open_findclause(const char *name, unsigned long *id) {
/*
* We found the clause. Let's extract its ID
*/
*id = parseid(dbkey.mv_data);
*id = isc__cfgmgr_parseid(dbkey.mv_data);
out:
return result;
}
static void
updateprefix(void) {
isc__cfgmgr_updateprefix(void) {
size_t written = 0;
REQUIRE(ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
if (ISC_LIST_EMPTY(ctx.openedclauses)) {
if (ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses)) {
return;
}
for (openedclause_t *clause = ISC_LIST_TAIL(ctx.openedclauses);
for (openedclause_t *clause =
ISC_LIST_TAIL(isc__cfgmgr_ctx.openedclauses);
clause != NULL; clause = ISC_LIST_PREV(clause, link))
{
written += snprintf(ctx.prefix + written, BUFLEN - written,
"%s.%zu.", clause->name, clause->id);
written += snprintf(isc__cfgmgr_ctx.prefix + written,
BUFLEN - written, "%s.%zu.", clause->name,
clause->id);
INSIST(written <= BUFLEN);
}
}
static void
pushclause(const char *name, unsigned long id) {
openedclause_t *clause = isc_mem_get(mctx, sizeof(*clause));
isc__cfgmgr_pushclause(const char *name, unsigned long id) {
openedclause_t *clause = isc_mem_get(isc__cfgmgr_mctx, sizeof(*clause));
*clause = (openedclause_t){
.name = isc_mem_allocate(mctx, strlen(name) + 1),
.name = isc_mem_allocate(isc__cfgmgr_mctx, strlen(name) + 1),
.id = id,
.link = ISC_LINK_INITIALIZER,
};
strcpy(clause->name, name);
ENSURE(clause->id > 0);
ISC_LIST_PREPEND(ctx.openedclauses, clause, link);
updateprefix();
ISC_LIST_PREPEND(isc__cfgmgr_ctx.openedclauses, clause, link);
isc__cfgmgr_updateprefix();
}
static void
freectx(void) {
REQUIRE(ctx.buffer != NULL && ctx.prefix != NULL);
isc__cfgmgr_freectx(void) {
REQUIRE(isc__cfgmgr_ctx.buffer != NULL &&
isc__cfgmgr_ctx.prefix != NULL);
isc_mem_free(mctx, ctx.buffer);
ctx.buffer = NULL;
isc_mem_free(mctx, ctx.prefix);
ctx.prefix = NULL;
ctx.txn = NULL;
ctx.cursor = NULL;
isc_mem_free(isc__cfgmgr_mctx, isc__cfgmgr_ctx.buffer);
isc_mem_free(isc__cfgmgr_mctx, isc__cfgmgr_ctx.prefix);
isc__cfgmgr_ctx.txn = NULL;
isc__cfgmgr_ctx.cursor = NULL;
}
static isc_result_t
starttransaction(bool readonly) {
isc_result_t result = ISC_R_SUCCESS;
isc__cfgmgr_starttransaction(bool readonly) {
MDB_dbi dbi;
REQUIRE(env != NULL);
REQUIRE(ctx.prefix == NULL);
REQUIRE(ctx.buffer == NULL);
REQUIRE(ctx.txn == NULL);
REQUIRE(ctx.cursor == NULL);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(isc__cfgmgr_ctx.prefix == NULL);
REQUIRE(isc__cfgmgr_ctx.buffer == NULL);
REQUIRE(isc__cfgmgr_ctx.txn == NULL);
REQUIRE(isc__cfgmgr_ctx.cursor == NULL);
if (mdb_txn_begin(env, NULL, readonly ? MDB_RDONLY : 0, &ctx.txn) != 0)
if (mdb_txn_begin(isc__cfgmgr_env, NULL, readonly ? MDB_RDONLY : 0,
&isc__cfgmgr_ctx.txn) != 0)
{
result = ISC_R_FAILURE;
goto cleanup;
goto failure;
}
INSIST(ctx.txn != NULL);
INSIST(isc__cfgmgr_ctx.txn != NULL);
if (mdb_dbi_open(ctx.txn, NULL, MDB_CREATE | MDB_DUPSORT, &dbi) != 0) {
result = ISC_R_FAILURE;
goto cleanup;
if (mdb_dbi_open(isc__cfgmgr_ctx.txn, NULL, MDB_CREATE | MDB_DUPSORT,
&dbi) != 0)
{
goto failure;
}
if (mdb_cursor_open(ctx.txn, dbi, &ctx.cursor) != 0) {
result = ISC_R_FAILURE;
goto cleanup;
if (mdb_cursor_open(isc__cfgmgr_ctx.txn, dbi,
&isc__cfgmgr_ctx.cursor) != 0)
{
goto failure;
}
INSIST(ctx.cursor != NULL);
ctx.readonly = readonly;
ctx.buffer = isc_mem_allocate(mctx, BUFLEN);
ctx.prefix = isc_mem_allocate(mctx, BUFLEN);
goto out;
INSIST(isc__cfgmgr_ctx.cursor != NULL);
isc__cfgmgr_ctx.readonly = readonly;
isc__cfgmgr_ctx.buffer = isc_mem_allocate(isc__cfgmgr_mctx, BUFLEN);
isc__cfgmgr_ctx.prefix = isc_mem_allocate(isc__cfgmgr_mctx, BUFLEN);
cleanup:
if (ctx.txn) {
mdb_txn_abort(ctx.txn);
freectx();
return ISC_R_SUCCESS;
failure:
if (isc__cfgmgr_ctx.txn) {
mdb_txn_abort(isc__cfgmgr_ctx.txn);
isc__cfgmgr_freectx();
}
ENSURE(ctx.buffer == NULL && ctx.prefix == NULL);
ENSURE(isc__cfgmgr_ctx.buffer == NULL &&
isc__cfgmgr_ctx.prefix == NULL);
out:
return result;
return ISC_R_FAILURE;
}
static isc_result_t
open_toplevel(const char *name, bool readonly) {
isc__cfgmgr_opentoplevel(const char *name, bool readonly) {
isc_result_t result = ISC_R_SUCCESS;
unsigned long id = 0;
REQUIRE(env != NULL);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(name != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses));
REQUIRE(ctx.prefix == NULL);
REQUIRE(ctx.buffer == NULL);
REQUIRE(ctx.txn == NULL);
REQUIRE(ctx.cursor == NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses));
REQUIRE(isc__cfgmgr_ctx.prefix == NULL);
REQUIRE(isc__cfgmgr_ctx.buffer == NULL);
REQUIRE(isc__cfgmgr_ctx.txn == NULL);
REQUIRE(isc__cfgmgr_ctx.cursor == NULL);
/*
* We're opening a clause at top-level, so let's start a
* transaction
*/
result = starttransaction(readonly);
result = isc__cfgmgr_starttransaction(readonly);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@@ -359,7 +361,7 @@ open_toplevel(const char *name, bool readonly) {
/*
* Now let's try to find the clause...
*/
result = open_findclause(name, &id);
result = isc__cfgmgr_findclause(name, &id);
if (result != ISC_R_SUCCESS) {
goto cleanup;
}
@@ -368,13 +370,13 @@ open_toplevel(const char *name, bool readonly) {
* The clause is found, let's enqueue the clause in
* context. the clause is now opened
*/
pushclause(name, id);
isc__cfgmgr_pushclause(name, id);
goto out;
cleanup:
if (ctx.txn) {
mdb_txn_abort(ctx.txn);
freectx();
if (isc__cfgmgr_ctx.txn) {
mdb_txn_abort(isc__cfgmgr_ctx.txn);
isc__cfgmgr_freectx();
}
out:
@@ -382,95 +384,92 @@ out:
}
static isc_result_t
open_nested(const char *name) {
isc__cfgmgr_opennested(const char *name) {
isc_result_t result = ISC_R_SUCCESS;
unsigned long id = 0;
REQUIRE(env != NULL);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(name != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses) == false);
REQUIRE(ctx.prefix != NULL);
REQUIRE(ctx.buffer != NULL);
REQUIRE(ctx.txn != NULL);
REQUIRE(ctx.cursor != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
result = open_findclause(name, &id);
result = isc__cfgmgr_findclause(name, &id);
if (result != ISC_R_SUCCESS) {
goto out;
}
pushclause(name, id);
isc__cfgmgr_pushclause(name, id);
out:
return result;
}
isc_result_t
cfgmgr_openrw(const char *name) {
return open_toplevel(name, false);
isc_cfgmgr_openrw(const char *name) {
return isc__cfgmgr_opentoplevel(name, false);
}
isc_result_t
cfgmgr_open(const char *name) {
return ISC_LIST_EMPTY(ctx.openedclauses) ? open_toplevel(name, true)
: open_nested(name);
isc_cfgmgr_open(const char *name) {
if (ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses)) {
return isc__cfgmgr_opentoplevel(name, true);
}
return isc__cfgmgr_opennested(name);
}
static void
popclause(void) {
REQUIRE(env != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
openedclause_t *clause = ISC_LIST_HEAD(ctx.openedclauses);
ISC_LIST_UNLINK(ctx.openedclauses, clause, link);
isc_mem_free(mctx, clause->name);
isc_mem_put(mctx, clause, sizeof(*clause));
updateprefix();
openedclause_t *clause = ISC_LIST_HEAD(isc__cfgmgr_ctx.openedclauses);
ISC_LIST_UNLINK(isc__cfgmgr_ctx.openedclauses, clause, link);
isc_mem_free(isc__cfgmgr_mctx, clause->name);
isc_mem_put(isc__cfgmgr_mctx, clause, sizeof(*clause));
isc__cfgmgr_updateprefix();
}
isc_result_t
cfgmgr_close(void) {
isc_cfgmgr_close(void) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(env != NULL);
if (ISC_LIST_EMPTY(ctx.openedclauses)) {
REQUIRE(ctx.prefix == NULL);
REQUIRE(ctx.buffer == NULL);
REQUIRE(ctx.txn == NULL);
REQUIRE(ctx.cursor == NULL);
result = ISC_R_NOTBOUND;
goto out;
}
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
popclause();
if (ISC_LIST_EMPTY(ctx.openedclauses)) {
mdb_cursor_close(ctx.cursor);
if (mdb_txn_commit(ctx.txn) != 0) {
if (ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses)) {
mdb_cursor_close(isc__cfgmgr_ctx.cursor);
if (mdb_txn_commit(isc__cfgmgr_ctx.txn) != 0) {
result = ISC_R_FAILURE;
}
freectx();
isc__cfgmgr_freectx();
}
out:
return result;
}
isc_result_t
cfgmgr_delclause(void) {
isc_cfgmgr_delclause(void) {
MDB_val dbkey;
REQUIRE(env != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses) == false);
REQUIRE(ctx.prefix != NULL);
REQUIRE(ctx.buffer != NULL);
REQUIRE(ctx.txn != NULL);
REQUIRE(ctx.cursor != NULL);
REQUIRE(ctx.readonly == false);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
REQUIRE(isc__cfgmgr_ctx.readonly == false);
dbkey = (MDB_val){ .mv_size = strlen(ctx.prefix) + 1,
.mv_data = ctx.prefix };
dbkey = (MDB_val){ .mv_size = strlen(isc__cfgmgr_ctx.prefix) + 1,
.mv_data = isc__cfgmgr_ctx.prefix };
do {
/*
* even though the key is modified by mdb_cursor_get
@@ -479,13 +478,14 @@ cfgmgr_delclause(void) {
* to the next one with the same prefix as soon it
* gets deleted
*/
int mdbres = mdb_cursor_get(ctx.cursor, &dbkey, NULL,
MDB_SET_RANGE);
int mdbres = mdb_cursor_get(isc__cfgmgr_ctx.cursor, &dbkey,
NULL, MDB_SET_RANGE);
if (mdbres == MDB_NOTFOUND) {
break;
}
if (strncmp(ctx.prefix, dbkey.mv_data, strlen(ctx.prefix)) != 0)
if (strncmp(isc__cfgmgr_ctx.prefix, dbkey.mv_data,
strlen(isc__cfgmgr_ctx.prefix)) != 0)
{
break;
}
@@ -495,62 +495,64 @@ cfgmgr_delclause(void) {
* avoid extra iterations if there are lists in the
* clause
*/
REQUIRE(mdb_cursor_del(ctx.cursor, MDB_NODUPDATA) == 0);
REQUIRE(mdb_cursor_del(isc__cfgmgr_ctx.cursor, MDB_NODUPDATA) ==
0);
} while (1);
return cfgmgr_close();
return isc_cfgmgr_close();
}
isc_result_t
cfgmgr_newclause(const char *name) {
isc_cfgmgr_newclause(const char *name) {
isc_result_t result = ISC_R_SUCCESS;
REQUIRE(name != NULL);
REQUIRE(env != NULL);
REQUIRE(isc__cfgmgr_env != NULL);
if (ctx.txn == NULL || ctx.cursor == NULL) {
result = starttransaction(false);
if (isc__cfgmgr_ctx.txn == NULL || isc__cfgmgr_ctx.cursor == NULL) {
result = isc__cfgmgr_starttransaction(false);
}
if (result == ISC_R_SUCCESS) {
INSIST(ctx.txn != NULL);
INSIST(ctx.buffer != NULL);
INSIST(ctx.cursor != NULL);
INSIST(ctx.readonly == false);
pushclause(name, RANDOM());
INSIST(ctx.prefix != NULL);
INSIST(isc__cfgmgr_ctx.txn != NULL);
INSIST(isc__cfgmgr_ctx.buffer != NULL);
INSIST(isc__cfgmgr_ctx.cursor != NULL);
INSIST(isc__cfgmgr_ctx.readonly == false);
isc__cfgmgr_pushclause(name, isc_random32());
INSIST(isc__cfgmgr_ctx.prefix != NULL);
}
return result;
}
isc_result_t
cfgmgr_nextclause(void) {
isc_cfgmgr_nextclause(void) {
isc_result_t result = ISC_R_SUCCESS;
MDB_val dbkey;
unsigned long id;
size_t idstarts = 0;
size_t written = 0;
REQUIRE(env != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses) == false);
REQUIRE(ctx.prefix != NULL);
REQUIRE(ctx.buffer != NULL);
REQUIRE(ctx.txn != NULL);
REQUIRE(ctx.cursor != NULL);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
/*
* Let's pick the very next id (even if doesn't exists) of the
* current clause
*/
id = ISC_LIST_HEAD(ctx.openedclauses)->id + 1;
id = ISC_LIST_HEAD(isc__cfgmgr_ctx.openedclauses)->id + 1;
/*
* Variant of updateprefix, but this time we put a incremented
* key for the currently opened clause. We also keep track of
* when the current clause id starts.
*/
for (openedclause_t *clause = ISC_LIST_TAIL(ctx.openedclauses);
for (openedclause_t *clause =
ISC_LIST_TAIL(isc__cfgmgr_ctx.openedclauses);
clause != NULL; clause = ISC_LIST_PREV(clause, link))
{
bool last = ISC_LIST_PREV(clause, link) == NULL;
@@ -558,21 +560,23 @@ cfgmgr_nextclause(void) {
if (last) {
idstarts = written + strlen(clause->name) + 1;
}
written += snprintf(ctx.buffer + written, BUFLEN - written,
"%s.%zu.", clause->name,
written += snprintf(isc__cfgmgr_ctx.buffer + written,
BUFLEN - written, "%s.%zu.", clause->name,
last ? id : clause->id);
INSIST(written <= BUFLEN);
}
INSIST(idstarts > 0);
dbkey = (MDB_val){ .mv_size = strlen(ctx.buffer) + 1,
.mv_data = ctx.buffer };
dbkey = (MDB_val){ .mv_size = strlen(isc__cfgmgr_ctx.buffer) + 1,
.mv_data = isc__cfgmgr_ctx.buffer };
/*
* Looking for similar prefix name but with a bigger
* id. Thanks for LMDB sort and MDB_SET_RANGE, we'll bump to
* the first key/val of the next clause of the same type
*/
if (mdb_cursor_get(ctx.cursor, &dbkey, NULL, MDB_SET_RANGE) != 0) {
if (mdb_cursor_get(isc__cfgmgr_ctx.cursor, &dbkey, NULL,
MDB_SET_RANGE) != 0)
{
result = ISC_R_NOMORE;
goto out;
}
@@ -581,7 +585,7 @@ cfgmgr_nextclause(void) {
* Let's check if next found clause is same name
*/
REQUIRE(idstarts < BUFLEN);
if (strncmp(ctx.buffer, dbkey.mv_data, idstarts) != 0) {
if (strncmp(isc__cfgmgr_ctx.buffer, dbkey.mv_data, idstarts) != 0) {
result = ISC_R_NOMORE;
goto out;
}
@@ -592,96 +596,103 @@ cfgmgr_nextclause(void) {
* new clause, let's simply replace the id and update the
* prefix.
*/
ctx.buffer[idstarts] = 0;
ISC_LIST_HEAD(ctx.openedclauses)->id = parseid(dbkey.mv_data);
updateprefix();
isc__cfgmgr_ctx.buffer[idstarts] = 0;
ISC_LIST_HEAD(isc__cfgmgr_ctx.openedclauses)->id =
isc__cfgmgr_parseid(dbkey.mv_data);
isc__cfgmgr_updateprefix();
out:
return result;
}
static isc_result_t
getval(const char *name, cfgmgr_val_t *value) {
isc__cfgmgr_getval(const char *name, isc_cfgmgr_val_t *value) {
isc_result_t result = ISC_R_SUCCESS;
MDB_val dbkey;
MDB_val dbval;
const int opt = name == NULL ? MDB_NEXT_DUP : MDB_SET;
REQUIRE(env != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses) == false);
REQUIRE(ctx.prefix != NULL);
REQUIRE(ctx.buffer != NULL);
REQUIRE(ctx.txn != NULL);
REQUIRE(ctx.cursor != NULL);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
REQUIRE(value != NULL);
if (name != NULL) {
buildkey(name, false);
isc__cfgmgr_buildkey(name, false);
}
dbkey = (MDB_val){ .mv_size = name == NULL ? 0 : strlen(ctx.buffer) + 1,
.mv_data = name == NULL ? NULL : ctx.buffer };
if (mdb_cursor_get(ctx.cursor, &dbkey, &dbval, opt) != 0) {
dbkey = (MDB_val){
.mv_size = name == NULL ? 0
: strlen(isc__cfgmgr_ctx.buffer) + 1,
.mv_data = name == NULL ? NULL : isc__cfgmgr_ctx.buffer
};
if (mdb_cursor_get(isc__cfgmgr_ctx.cursor, &dbkey, &dbval, opt) != 0) {
result = opt == MDB_NEXT_DUP ? ISC_R_NOMORE : ISC_R_NOTFOUND;
goto out;
}
memcpy(value, dbval.mv_data, sizeof(*value));
if (value->type == STRING) {
value->data.string = ((char *)dbval.mv_data) +
sizeof(value->type);
if (value->type == ISC_CFGMGR_STRING) {
value->string = ((char *)dbval.mv_data) + sizeof(value->type);
}
INSIST(value->type != ISC_CFGMGR_UNKNOWN);
out:
return result;
}
isc_result_t
cfgmgr_getval(const char *name, cfgmgr_val_t *value) {
return getval(name, value);
isc_cfgmgr_getval(const char *name, isc_cfgmgr_val_t *value) {
return isc__cfgmgr_getval(name, value);
}
isc_result_t
cfgmgr_getnextlistval(cfgmgr_val_t *value) {
return getval(NULL, value);
isc_cfgmgr_getnextlistval(isc_cfgmgr_val_t *value) {
return isc__cfgmgr_getval(NULL, value);
}
static isc_result_t
setval(const char *name, const cfgmgr_val_t *value, bool list) {
isc__cfgmgr_setval(const char *name, const isc_cfgmgr_val_t *value, bool list) {
isc_result_t result = ISC_R_SUCCESS;
MDB_val dbkey;
MDB_val dbval;
REQUIRE(env != NULL);
REQUIRE(ISC_LIST_EMPTY(ctx.openedclauses) == false);
REQUIRE(ctx.prefix != NULL);
REQUIRE(ctx.buffer != NULL);
REQUIRE(ctx.txn != NULL);
REQUIRE(ctx.cursor != NULL);
REQUIRE(ctx.readonly == false);
REQUIRE(isc__cfgmgr_env != NULL);
REQUIRE(ISC_LIST_EMPTY(isc__cfgmgr_ctx.openedclauses) == false);
REQUIRE(isc__cfgmgr_ctx.prefix != NULL);
REQUIRE(isc__cfgmgr_ctx.buffer != NULL);
REQUIRE(isc__cfgmgr_ctx.txn != NULL);
REQUIRE(isc__cfgmgr_ctx.cursor != NULL);
REQUIRE(isc__cfgmgr_ctx.readonly == false);
REQUIRE(name != NULL);
REQUIRE(value != NULL || (value == NULL && list == false));
REQUIRE((value != NULL && value->type != ISC_CFGMGR_UNKNOWN) ||
(value == NULL && list == false));
buildkey(name, false);
dbkey = (MDB_val){ .mv_size = strlen(ctx.buffer) + 1,
.mv_data = ctx.buffer };
isc__cfgmgr_buildkey(name, false);
dbkey = (MDB_val){ .mv_size = strlen(isc__cfgmgr_ctx.buffer) + 1,
.mv_data = isc__cfgmgr_ctx.buffer };
if (value == NULL) {
if (mdb_cursor_get(ctx.cursor, &dbkey, NULL, MDB_SET) ==
MDB_NOTFOUND)
if (mdb_cursor_get(isc__cfgmgr_ctx.cursor, &dbkey, NULL,
MDB_SET) == MDB_NOTFOUND)
{
result = ISC_R_NOTFOUND;
goto out;
}
REQUIRE(mdb_cursor_del(ctx.cursor, MDB_NODUPDATA) == 0);
REQUIRE(mdb_cursor_del(isc__cfgmgr_ctx.cursor, MDB_NODUPDATA) ==
0);
goto out;
}
if (value->type == STRING) {
dbval.mv_size = sizeof(*value) + strlen(value->data.string) + 1;
dbval.mv_data = isc_mem_allocate(mctx, dbval.mv_size);
if (value->type == ISC_CFGMGR_STRING) {
dbval.mv_size = sizeof(*value) + strlen(value->string) + 1;
dbval.mv_data = isc_mem_allocate(isc__cfgmgr_mctx,
dbval.mv_size);
memcpy(dbval.mv_data, value, sizeof(value->type));
strcpy(((char *)dbval.mv_data) + sizeof(value->type),
value->data.string);
value->string);
} else {
dbval = (MDB_val){ .mv_size = sizeof(*value),
/*
@@ -698,16 +709,16 @@ setval(const char *name, const cfgmgr_val_t *value, bool list) {
* value copy ahead just in case is likely more
* expensive than an extra lookup
*/
if (mdb_cursor_get(ctx.cursor, &dbkey, NULL, MDB_SET) !=
MDB_NOTFOUND)
if (mdb_cursor_get(isc__cfgmgr_ctx.cursor, &dbkey, NULL,
MDB_SET) != MDB_NOTFOUND)
{
REQUIRE(mdb_cursor_del(ctx.cursor, 0) == 0);
REQUIRE(mdb_cursor_del(isc__cfgmgr_ctx.cursor, 0) == 0);
}
}
REQUIRE(mdb_cursor_put(ctx.cursor, &dbkey, &dbval, 0) == 0);
if (value->type == STRING) {
isc_mem_free(mctx, dbval.mv_data);
REQUIRE(mdb_cursor_put(isc__cfgmgr_ctx.cursor, &dbkey, &dbval, 0) == 0);
if (value->type == ISC_CFGMGR_STRING) {
isc_mem_free(isc__cfgmgr_mctx, dbval.mv_data);
}
out:
@@ -715,11 +726,11 @@ out:
}
isc_result_t
cfgmgr_setval(const char *name, const cfgmgr_val_t *value) {
return setval(name, value, false);
isc_cfgmgr_setval(const char *name, const isc_cfgmgr_val_t *value) {
return isc__cfgmgr_setval(name, value, false);
}
isc_result_t
cfgmgr_setnextlistval(const char *name, const cfgmgr_val_t *value) {
return setval(name, value, true);
isc_cfgmgr_setnextlistval(const char *name, const isc_cfgmgr_val_t *value) {
return isc__cfgmgr_setval(name, value, true);
}
+48 -39
View File
@@ -19,7 +19,14 @@
/*
* Supported data types for read/write operations from/to cfgmgr.
*/
typedef enum { STRING = 0, BOOL, NONE, SOCKADDR, UINT32 } cfgmgr_type_t;
typedef enum {
ISC_CFGMGR_UNKNOWN = 0,
ISC_CFGMGR_STRING,
ISC_CFGMGR_BOOLEAN,
ISC_CFGMGR_NONE,
ISC_CFGMGR_SOCKADDR,
ISC_CFGMGR_UINT32
} isc_cfgmgr_type_t;
/*
* Generic value holding the actual value and type value for
@@ -28,14 +35,14 @@ typedef enum { STRING = 0, BOOL, NONE, SOCKADDR, UINT32 } cfgmgr_type_t;
* cfgmgr_type_t::NONE doesn't have associated value,
*/
typedef struct {
cfgmgr_type_t type;
isc_cfgmgr_type_t type;
union {
const char *string;
bool boolean;
isc_sockaddr_t sockaddr;
uint32_t uint32;
} data;
} cfgmgr_val_t;
};
} isc_cfgmgr_val_t;
/*
* Get the property "name" in the opened clause into the caller
@@ -46,7 +53,7 @@ typedef struct {
* head.
*/
isc_result_t
cfgmgr_getval(const char *name, cfgmgr_val_t *value);
isc_cfgmgr_getval(const char *name, isc_cfgmgr_val_t *value);
/*
* Write "value" into the property "name" in the opened clause and
@@ -58,30 +65,31 @@ cfgmgr_getval(const char *name, cfgmgr_val_t *value);
* clause (and its parent, if nested) is closed.
*/
isc_result_t
cfgmgr_setval(const char *name, const cfgmgr_val_t *value);
isc_cfgmgr_setval(const char *name, const isc_cfgmgr_val_t *value);
/*
* Same as cfgmgr_getval but applies for elements after the head of a
* list property. The head is read using cfgmgr_getval as any other
* value, then subsequents calls to cfgmgr_getnextlistval will get the
* next elements in the list. When the end of the list is reached,
* ISC_R_NOMORE is returned. Calls to cfgmgr_getnextlistval name has
* to be made in immediate sequence (without intermediate
* cfgmgr_{set,get}val calls) to retrieve each list element.
* Same as isc_cfgmgr_getval but applies for elements after the head
* of a list property. The head is read using isc_cfgmgr_getval as any
* other value, then subsequents calls to isc_cfgmgr_getnextlistval
* will get the next elements in the list. When the end of the list is
* reached, ISC_R_NOMORE is returned. Calls to
* isc_cfgmgr_getnextlistval name has to be made in immediate sequence
* (without intermediate isc_cfgmgr_{set,get}val calls) to retrieve
* each list element.
*/
isc_result_t
cfgmgr_getnextlistval(cfgmgr_val_t *value);
isc_cfgmgr_getnextlistval(isc_cfgmgr_val_t *value);
/*
* Same as cfgmgr_setval but applies for a list property. Writes by
* appending "*value" at the end of the list property "name" in the
* Same as isc_cfgmgr_setval but applies for a list property. Writes
* by appending "*value" at the end of the list property "name" in the
* opened clause and returns ISC_R_SUCCESS. If "name" property wasn't
* existing before (or wasn't a list) it's overriden. It is not
* possible to delete individual list element, only the whole list can
* be removed using cfgmgr_setval.
* be removed using isc_cfgmgr_setval.
*/
isc_result_t
cfgmgr_setnextlistval(const char *name, const cfgmgr_val_t *value);
isc_cfgmgr_setnextlistval(const char *name, const isc_cfgmgr_val_t *value);
/*
* If the opened clause is a repeatable clause (i.e. view, acl, etc.),
@@ -90,13 +98,13 @@ cfgmgr_setnextlistval(const char *name, const cfgmgr_val_t *value);
* of the same type, ISC_R_NOMORE is returned.
*/
isc_result_t
cfgmgr_nextclause(void);
isc_cfgmgr_nextclause(void);
/*
* If used at top-level, create and open as read-write a new clause
* "name". If used inside an opened parent clause, then the parent (or
* parent or the parent, recursively) clause must have been opened
* read-write (so using cfgmgr_openrw or cfgmgr_newclause).
* read-write (so using isc_cfgmgr_openrw or isc_cfgmgr_newclause).
*
* Returns ISC_R_SUCCESS or ISC_R_FAILURE if there is no transaction
* and it fails creating one. Note that in order to have the new
@@ -104,7 +112,7 @@ cfgmgr_nextclause(void);
* be set to that clause.
*/
isc_result_t
cfgmgr_newclause(const char *name);
isc_cfgmgr_newclause(const char *name);
/*
* Delete and close the opened clause. (And thus all its properties,
@@ -113,19 +121,20 @@ cfgmgr_newclause(const char *name);
* opened. Returns ISC_R_SUCCESS.
*/
isc_result_t
cfgmgr_delclause(void);
isc_cfgmgr_delclause(void);
/*
* Close the currently opened clause and returns ISC_R_SUCCESS. If the
* closed clause was nested, the currently opened clause is now the
* parent clause. Otherwise, no close is opened. If no clause was
* opened when the function was called, ISC_R_NOTBOUND is
* returned. Closing the top-level clause will applies all
* modifications done inside the clause. If something is going wrong,
* ISC_R_FAILURE is returned, and all modification made are discarded.
* parent clause. If top-level clause was opened with
* isc_cfgmgr_openrw or isc_cfgmgr_newclause, closing the top-level
* clause will applies all modifications done inside the clause (and
* inside the nested clauses). If something is going wrong while
* writing the modifications ISC_R_FAILURE is returned and all
* modification made are discarded.
*/
isc_result_t
cfgmgr_close(void);
isc_cfgmgr_close(void);
/*
* Open the top-level clause "name" for reading and writing and
@@ -134,10 +143,10 @@ cfgmgr_close(void);
* returns ISC_R_FAILURE.
*
* This call will block if another thread has already a clause opened
* for reading and writting. Use cfgmgr_openro for reading only.
* for reading and writting. Use isc_cfgmgr_openro for reading only.
*/
isc_result_t
cfgmgr_openrw(const char *name);
isc_cfgmgr_openrw(const char *name);
/*
* Open the clause "name" and returns ISC_R_SUCCES or ISC_R_NOTFOUND
@@ -151,22 +160,22 @@ cfgmgr_openrw(const char *name);
* access than the already opened clause.
*/
isc_result_t
cfgmgr_open(const char *name);
isc_cfgmgr_open(const char *name);
/*
* Initialize cfgmgr. Must be called before any other function. It is
* possible to re-initialize cfgmgr only after calling cfgmgr_deinit
* (this drops all the data written in cfgmgr). Returns ISC_R_SUCCESS
* or ISC_R_FAILURE if there is an issue initializing the internal
* database.
* possible to re-initialize cfgmgr only after calling
* isc_cfgmgr_deinit (this drops all the data written in
* cfgmgr). Returns ISC_R_SUCCESS or ISC_R_FAILURE if there is an
* issue initializing the internal database.
*/
isc_result_t
cfgmgr_init(isc_mem_t *mctx_, const char *dbpath_);
isc_cfgmgr_init(isc_mem_t *mctx, const char *dbpath);
/*
* Destroy all cfgmgr data and free memory. Must be called only after
* cfgmgr_init and no function must be called after that one (except
* cfgmgr_init to re-initialize cfgmgr again).
* isc_cfgmgr_init and no function must be called after that one
* (except isc_cfgmgr_init to re-initialize cfgmgr again).
*/
void
cfgmgr_deinit(void);
isc_cfgmgr_deinit(void);
+844 -444
View File
File diff suppressed because it is too large Load Diff