static void mutt_hcache_dbt_init(DBT * dbt, void *data, size_t len);
static void mutt_hcache_dbt_empty_init(DBT * dbt);
#elif HAVE_LMDB
+enum mdb_txn_mode
+{
+ txn_uninitialized = 0,
+ txn_read = 1 << 0,
+ txn_write = 1 << 1
+};
struct header_cache
{
MDB_env *env;
MDB_dbi db;
char *folder;
unsigned int crc;
+ enum mdb_txn_mode txn_mode;
};
+
+static int mdb_get_r_txn(header_cache_t *h)
+{
+ int rc;
+
+ if (h->txn && (h->txn_mode & (txn_read | txn_write)) > 0)
+ return MDB_SUCCESS;
+
+ if (h->txn)
+ rc = mdb_txn_renew(h->txn);
+ else
+ rc = mdb_txn_begin(h->env, NULL, MDB_RDONLY, &h->txn);
+
+ if (rc == MDB_SUCCESS)
+ h->txn_mode = txn_read;
+
+ return rc;
+}
+
+static int mdb_get_w_txn(header_cache_t *h)
+{
+ int rc;
+
+ if (h->txn && (h->txn_mode == txn_write))
+ return MDB_SUCCESS;
+
+ if (h->txn)
+ {
+ if (h->txn_mode == txn_read)
+ mdb_txn_reset(h->txn);
+ h->txn = NULL;
+ }
+
+ rc = mdb_txn_begin(h->env, NULL, 0, &h->txn);
+ if (rc == MDB_SUCCESS)
+ h->txn_mode = txn_write;
+
+ return rc;
+}
#endif
typedef union
key.mv_size = ksize;
data.mv_data = NULL;
data.mv_size = 0;
- rc = mdb_txn_renew(h->txn);
+ rc = mdb_get_r_txn(h);
if (rc != MDB_SUCCESS)
{
h->txn = NULL;
rc = mdb_get(h->txn, h->db, &key, &data);
if (rc == MDB_NOTFOUND)
{
- mdb_txn_reset(h->txn);
return NULL;
}
if (rc != MDB_SUCCESS)
{
fprintf(stderr, "mdb_get: %s\n", mdb_strerror(rc));
- mdb_txn_reset(h->txn);
return NULL;
}
/* Caller frees the data we return, so I MUST make a copy of it */
char *d = safe_malloc(data.mv_size);
memcpy(d, data.mv_data, data.mv_size);
- mdb_txn_reset(h->txn);
return d;
#elif HAVE_LMDB
MDB_val key;
MDB_val databuf;
- MDB_txn *txn;
size_t folderlen;
int rc;
#endif
key.mv_size = ksize;
databuf.mv_data = data;
databuf.mv_size = dlen;
- rc = mdb_txn_begin(h->env, NULL, 0, &txn);
+ rc = mdb_get_w_txn(h);
if (rc != MDB_SUCCESS)
{
fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
return rc;
}
- rc = mdb_put(txn, h->db, &key, &databuf, 0);
+ rc = mdb_put(h->txn, h->db, &key, &databuf, 0);
if (rc != MDB_SUCCESS)
{
fprintf(stderr, "mdb_put: %s\n", mdb_strerror(rc));
- mdb_txn_abort(txn);
+ mdb_txn_abort(h->txn);
+ h->txn_mode = txn_uninitialized;
+ h->txn = NULL;
return rc;
}
- rc = mdb_txn_commit(txn);
return rc;
#else
strncpy(path, h->folder, sizeof (path));
goto fail_env;
}
- rc = mdb_txn_begin(h->env, NULL, MDB_RDONLY, &h->txn);
+ rc = mdb_get_r_txn(h);
if (rc != MDB_SUCCESS)
{
fprintf(stderr, "hcache_open_lmdb: mdb_txn_begin: %s", mdb_strerror(rc));
}
mdb_txn_reset(h->txn);
+ h->txn_mode = txn_uninitialized;
return 0;
fail_dbi:
mdb_txn_abort(h->txn);
+ h->txn_mode = txn_uninitialized;
h->txn = NULL;
fail_env:
if (!h)
return;
+ if (h->txn && h->txn_mode == txn_write)
+ {
+ mdb_txn_commit(h->txn);
+ h->txn_mode = txn_uninitialized;
+ h->txn = NULL;
+ }
+
mdb_env_close(h->env);
FREE (&h->folder);
FREE (&h);
size_t(*keylen) (const char *fn))
{
MDB_val key;
- MDB_txn *txn;
int rc;
if (!h)
key.mv_data = (char *)filename;
key.mv_size = strlen(filename);
- rc = mdb_txn_begin(h->env, NULL, 0, &txn);
+ rc = mdb_get_w_txn(h);
if (rc != MDB_SUCCESS)
{
fprintf(stderr, "txn_begin: %s\n", mdb_strerror(rc));
return rc;
}
- rc = mdb_del(txn, h->db, &key, NULL);
+ rc = mdb_del(h->txn, h->db, &key, NULL);
if (rc != MDB_SUCCESS)
{
if (rc != MDB_NOTFOUND)
{
fprintf(stderr, "mdb_del: %s\n", mdb_strerror(rc));
+ mdb_txn_abort(h->txn);
+ h->txn_mode = txn_uninitialized;
+ h->txn = NULL;
}
- mdb_txn_abort(txn);
return rc;
}
- mdb_txn_commit(txn);
return rc;
}
#endif