knot_db_val_t val = { .len = storage_size, .data = NULL };
int ret = cache_op(cache, write, &key, &val, 1);
if (ret || !val.data || !val.len) {
+ /* Clear cache if overfull. It's nontrivial to do better with LMDB.
+ * LATER: some garbage-collection mechanism. */
+ if (ret == kr_error(ENOSPC)) {
+ ret = kr_cache_clear(cache);
+ const char *msg = "[cache] clearing because overfull, ret = %d\n";
+ if (ret) {
+ kr_log_error(msg, ret);
+ } else {
+ kr_log_info(msg, ret);
+ ret = kr_error(ENOSPC);
+ }
+ return ret;
+ }
assert(ret); /* otherwise "succeeding" but `val` is bad */
VERBOSE_MSG(qry, "=> failed backend write, ret = %d\n", ret);
return kr_error(ret ? ret : ENOSPC);
/** @brief Convert LMDB error code. */
static int lmdb_error(int error)
{
+ /* _BAD_TXN may happen with overfull DB,
+ * even during mdb_get with a single fork :-/ */
+ if (error == MDB_BAD_TXN) {
+ kr_log_info("[cache] MDB_BAD_TXN, probably overfull\n");
+ error = ENOSPC;
+ }
switch (error) {
case MDB_SUCCESS:
return kr_ok();
case MDB_NOTFOUND:
return kr_error(ENOENT);
-
case ENOSPC:
case MDB_MAP_FULL:
case MDB_TXN_FULL:
- case MDB_BAD_TXN:
- /* _BAD_TXN in practice happens with overfull DB,
- * even during mdb_get with a single fork :-/ */
return kr_error(ENOSPC);
-
default:
kr_log_error("[cache] LMDB error: %s\n", mdb_strerror(error));
assert(false);