Let's avoid reloading the RO transaction unless necessary.
For example, when normal config reload happens (one kresd at a time),
we most likely do *not* want to reload the rule DB prematurely.
uint32_t packet_ttl(const knot_pkt_t *);
int kr_rules_init(const char *, size_t, _Bool);
int kr_rules_commit(_Bool);
+int kr_rules_reset(void);
int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *);
int kr_view_select_action(const struct kr_request *, knot_db_val_t *);
int kr_rule_tag_add(const char *, kr_rule_tags_t *);
uint32_t packet_ttl(const knot_pkt_t *);
int kr_rules_init(const char *, size_t, _Bool);
int kr_rules_commit(_Bool);
+int kr_rules_reset(void);
int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *);
int kr_view_select_action(const struct kr_request *, knot_db_val_t *);
int kr_rule_tag_add(const char *, kr_rule_tags_t *);
uint32_t packet_ttl(const knot_pkt_t *);
int kr_rules_init(const char *, size_t, _Bool);
int kr_rules_commit(_Bool);
+int kr_rules_reset(void);
int kr_view_insert_action(const char *, const char *, kr_proto_set, const char *);
int kr_view_select_action(const struct kr_request *, knot_db_val_t *);
int kr_rule_tag_add(const char *, kr_rule_tags_t *);
# New policy
kr_rules_init
kr_rules_commit
+ kr_rules_reset
kr_view_insert_action
kr_view_select_action
kr_rule_tag_add
return kr_error(EINVAL);
}
if (cache->api->commit) {
- return cache_op(cache, commit, true);
+ return cache_op(cache, commit, true, true);
}
return kr_ok();
}
int (*clear)(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
+ * \param accept_rw whether the RW transaction should accept changes (commit vs. abort)
+ * \param reset_ro whether the RO transaction should be ended (newest data next time)
* \return error code - accepting RW transactions can fail with LMDB.
*/
- int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat, bool accept);
+ int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat, bool accept_rw, bool reset_ro);
/* Data access */
return (kr_cdb_pt)env;
}
-static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept);
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept_rw, bool reset_ro);
static void txn_abort(struct lmdb_env *env);
/** @brief Convert LMDB error code. */
* It's much lighter than reopen_env(). */
static int refresh_mapsize(struct lmdb_env *env)
{
- int ret = cdb_commit(env2db(env), NULL, true);
+ int ret = cdb_commit(env2db(env), NULL, true, true);
if (!ret) ret = lmdb_error(env, 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, bool accept)
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats, bool accept_rw, bool reset_ro)
{
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++;
- ret = lmdb_error(env, mdb_txn_commit(env->txn.rw));
+ if (accept_rw) {
+ if (stats) stats->commit++;
+ ret = lmdb_error(env, mdb_txn_commit(env->txn.rw));
+ } else {
+ mdb_txn_abort(env->txn.rw);
+ }
env->txn.rw = NULL; /* the transaction got freed even in case of errors */
- } else if (env->txn.ro && env->txn.ro_active) {
+ } else if (reset_ro && env->txn.ro && env->txn.ro_active) {
mdb_txn_reset(env->txn.ro);
env->txn.ro_active = false;
env->txn.ro_curs_active = false;
* At least for rules we don't do the auto-commit feature. */
if (env->txn.rw) {
if (!env->is_cache) return kr_error(EINPROGRESS);
- int ret = cdb_commit(env2db(env), stats, true);
+ int ret = cdb_commit(env2db(env), stats, true, false);
if (ret) return ret;
}
MDB_txn *txn = NULL;
/* Get rid of any transactions. */
txn_free_ro(env);
- cdb_commit(env2db(env), stats, env->is_cache);
+ cdb_commit(env2db(env), stats, env->is_cache, true);
mdb_env_sync(env->env, 1);
stats->close++;
if (ret == kr_ok()) {
ret = lmdb_error(env, mdb_drop(txn, env->dbi, 0));
if (ret == kr_ok() && env->is_cache) {
- ret = cdb_commit(db, stats, true);
+ ret = cdb_commit(db, stats, true, 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, env->is_cache);
+ (void)cdb_commit(db, stats, env->is_cache, true);
const char *path = NULL;
int ret = mdb_env_get_path(env->env, &path);
int kr_rules_commit(bool accept)
{
if (!the_rules) return kr_error(EINVAL);
- return ruledb_op(commit, accept);
+ return ruledb_op(commit, accept, false);
+}
+
+int kr_rules_reset(void)
+{
+ if (!the_rules) return kr_error(EINVAL);
+ return ruledb_op(commit, false, true);
}
static bool kr_rule_consume_tags(knot_db_val_t *val, const struct kr_request *req)
* Normally commit happens only on successfully loading a config file.
* However, an advanced user may get in trouble e.g. if calling resolve() from there,
* causing even an assertion failure. In that case they might want to commit explicitly.
+ *
+ * If only read-only transaction is open, this will NOT reset it to the newest data.
*/
KR_EXPORT
int kr_rules_commit(bool accept);
+/** Reset to the latest version of rules committed in the DB.
+ *
+ * Note that this is not always a good idea. For example, the `forward` rules
+ * now use data from both the DB and lua config, so reloading only the DB
+ * may lead to weird behavior in some cases.
+ * (Modifications will also do this, as you can only modify the latest DB.)
+ */
+KR_EXPORT
+int kr_rules_reset(void);
+
/** 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)
.data = &state };
int ret = cache->api->write(db, stats, &key, &value, 1);
- cache->api->commit(db, stats, true);
+ kr_cache_commit(cache);
free(key.data);
return ret;