/* Reopen cache */
struct kr_cdb_opts opts = {
- (conf && strlen(conf)) ? conf : ".",
- cache_size
+ .is_cache = true,
+ .path = (conf && strlen(conf)) ? conf : ".",
+ .maxsize = cache_size,
};
int ret = kr_cache_open(&engine->resolver.cache, api, &opts, engine->pool);
if (ret != 0) {
goto cleanup;
}
+ /* Starting everything succeeded, so commit rule DB changes. */
+ kr_rules_commit(true);
+
/* Run the event loop */
ret = run_worker(loop, &engine, fork_id == 0, the_args);
cleanup:/* Cleanup. */
engine_deinit(&engine);
worker_deinit();
+ kr_rules_commit(false);
kr_rules_deinit();
if (loop != NULL) {
uv_loop_close(loop);
return kr_error(EINVAL);
}
if (cache->api->commit) {
- return cache_op(cache, commit);
+ return cache_op(cache, commit, true);
}
return kr_ok();
}
int (*count)(kr_cdb_pt db, struct kr_cdb_stats *stat);
int (*clear)(kr_cdb_pt db, struct kr_cdb_stats *stat);
- /** Run after a row of operations to release transaction/lock if needed. */
- int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+ /** Run after a row of operations to release transaction/lock if needed.
+ * \param accept true=commit / false=abort
+ * \return error code - accepting RW transactions can fail with LMDB.
+ */
+ int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat, bool accept);
/* Data access */
return (kr_cdb_pt)env;
}
-static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats);
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept);
+static void txn_abort(struct lmdb_env *env);
/** @brief Convert LMDB error code. */
static int lmdb_error(int error)
* It's much lighter than reopen_env(). */
static int refresh_mapsize(struct lmdb_env *env)
{
- int ret = cdb_commit(env2db(env), NULL);
+ int ret = cdb_commit(env2db(env), NULL, true);
if (!ret) ret = lmdb_error(mdb_env_set_mapsize(env->env, 0));
if (ret) return ret;
return kr_ok();
}
-static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats)
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept)
{
struct lmdb_env *env = db2env(db);
+ if (!accept) {
+ txn_abort(env);
+ return kr_ok();
+ }
+
int ret = kr_ok();
if (env->txn.rw) {
if (stats) stats->commit++;
return kr_error(EINVAL);
if (env->txn.ro_curs_active)
goto success;
- /* Only in a read-only txn; TODO: it's a bit messy/coupled */
+ /* Only in a read-only txn; TODO: it's a bit messy/coupled
+ * At least for rules we don't do the auto-commit feature. */
if (env->txn.rw) {
- int ret = cdb_commit(env2db(env), stats);
+ if (!env->is_cache) return kr_error(EINPROGRESS);
+ int ret = cdb_commit(env2db(env), stats, true);
if (ret) return ret;
}
MDB_txn *txn = NULL;
/* Get rid of any transactions. */
txn_free_ro(env);
- cdb_commit(env2db(env), stats);
+ cdb_commit(env2db(env), stats, env->is_cache);
mdb_env_sync(env->env, 1);
stats->close++;
int ret = txn_get(env, &txn, false);
if (ret == kr_ok()) {
ret = lmdb_error(mdb_drop(txn, env->dbi, 0));
- if (ret == kr_ok()) {
- ret = cdb_commit(db, stats);
+ if (ret == kr_ok() && env->is_cache) {
+ ret = cdb_commit(db, stats, true);
}
if (ret == kr_ok()) {
return ret;
/* We are about to switch to a different file, so end all txns, to be sure. */
txn_free_ro(env);
- (void) cdb_commit(db, stats);
+ (void) cdb_commit(db, stats, env->is_cache);
const char *path = NULL;
int ret = mdb_env_get_path(env->env, &path);
knot_db_val_t key = { .data = key_rs, .len = sizeof(key_rs) };
knot_db_val_t rulesets = { .data = &RULESET_DEFAULT, .len = strlen(RULESET_DEFAULT) + 1 };
ret = ruledb_op(write, &key, &rulesets, 1);
- if (ret == 0) ret = ruledb_op(commit);
if (ret == 0) return kr_ok();
failure:
free(the_rules);
the_rules = NULL;
}
+int kr_rules_commit(bool accept)
+{
+ if (!the_rules) return kr_error(EINVAL);
+ return ruledb_op(commit, accept);
+}
+
static bool kr_rule_consume_tags(knot_db_val_t *val, const struct kr_request *req)
{
kr_rule_tags_t tags;
+ rdataset_dematerialize_size(sig_rds);
knot_db_val_t val = { .data = NULL, .len = to_alloc };
int ret = ruledb_op(write, &key, &val, 1);
- CHECK_RET(ret);
+ if (ret) {
+ // ENOSPC seems to be the only expectable error.
+ kr_assert(ret == kr_error(ENOSPC));
+ return kr_error(ret);
+ }
// Write all the data.
memcpy(val.data, &tags, sizeof(tags));
rdataset_dematerialize(&rrs->rrs, val.data);
val.data += rr_ssize;
rdataset_dematerialize(sig_rds, val.data);
-
- return ruledb_op(commit);
+ return kr_ok();
}
int kr_rule_local_data_del(const knot_rrset_t *rrs, kr_rule_tags_t tags)
{
kr_require(the_rules);
uint8_t key_data[KEY_MAXLEN];
knot_db_val_t key = local_data_key(rrs, key_data, RULESET_DEFAULT);
- int ret = ruledb_op(remove, &key, 1);
- if (ret != 1)
- return ret;
- ret = ruledb_op(commit);
- return ret == 0 ? 1 : ret;
+ return ruledb_op(remove, &key, 1);
}
/** Empty or NXDOMAIN or NODATA. Returning kr_error(EAGAIN) means the rule didn't match. */
if (has_ttl)
val.len += sizeof(ttl);
int ret = ruledb_op(write, &key, &val, 1);
- CHECK_RET(ret);
+ if (ret) {
+ // ENOSPC seems to be the only expectable error.
+ kr_assert(ret == kr_error(ENOSPC));
+ return kr_error(ret);
+ }
memcpy(val.data, &tags, sizeof(tags));
val.data += sizeof(tags);
memcpy(val.data, &ztype, sizeof(ztype));
memcpy(val.data, &ttl, sizeof(ttl));
val.data += sizeof(ttl);
}
-
- return ruledb_op(commit);
+ return kr_ok();
}
int kr_rule_local_data_emptyzone(const knot_dname_t *apex, kr_rule_tags_t tags)
.data = (void *)/*const-cast*/action,
.len = strlen(action),
};
- int ret = ruledb_op(write, &key, &val, 1);
- return ret < 0 ? ret : ruledb_op(commit);
+ return ruledb_op(write, &key, &val, 1);
}
int kr_view_select_action(const struct kr_request *req, knot_db_val_t *selected)
KR_EXPORT
void kr_rules_deinit(void);
+/** Commit or abort changes done to the rule DB so far. */
+KR_EXPORT
+int kr_rules_commit(bool accept);
+
/** Try answering the query from local data; WIP: otherwise determine data source overrides.
*
* \return kr_error() on errors, >0 if answered, 0 otherwise (also when forwarding)
/* APIs to modify the rule DB.
*
* FIXME:
- * - what about transactions in this API?
* - a way to read/modify a rule?
*/
memcpy(val.data, &a, sizeof(a));
val.data += sizeof(a);
}
-
- return ruledb_op(commit);
+ return kr_ok();
}
.data = &state };
int ret = cache->api->write(db, stats, &key, &value, 1);
- cache->api->commit(db, stats);
+ cache->api->commit(db, stats, true);
free(key.data);
return ret;