From: Pietro Cerutti Date: Mon, 19 Sep 2016 15:29:24 +0000 (+0000) Subject: Optimize LMDB's hcache backend. X-Git-Tag: neomutt-20161002~17 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7e5380cd4c40d119ff83b2cf5f51f2cdb8a95ab3;p=neomutt Optimize LMDB's hcache backend. Thanks to Clemens Lang for his help with the fix. See: https://dev.mutt.org/trac/ticket/3691 Closes: #77 --- diff --git a/doc/manual.xml.head b/doc/manual.xml.head index fcf518891..9f9b85816 100644 --- a/doc/manual.xml.head +++ b/doc/manual.xml.head @@ -11005,6 +11005,7 @@ bind index <esc>L limit-current-thread Pietro Cerutti gahr@gahr.ch Jan-Piet Mens jp@mens.de + Clemens Lang neverpanic@gmail.com diff --git a/hcache.c b/hcache.c index b42e12ed0..870e05417 100644 --- a/hcache.c +++ b/hcache.c @@ -96,6 +96,12 @@ struct header_cache 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; @@ -103,7 +109,47 @@ struct header_cache 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 @@ -799,7 +845,7 @@ mutt_hcache_fetch_raw (header_cache_t *h, const char *filename, 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; @@ -809,20 +855,17 @@ mutt_hcache_fetch_raw (header_cache_t *h, const char *filename, 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; @@ -898,7 +941,6 @@ mutt_hcache_store_raw (header_cache_t* h, const char* filename, void* data, #elif HAVE_LMDB MDB_val key; MDB_val databuf; - MDB_txn *txn; size_t folderlen; int rc; #endif @@ -929,20 +971,21 @@ mutt_hcache_store_raw (header_cache_t* h, const char* filename, void* data, 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)); @@ -1342,7 +1385,7 @@ hcache_open_lmdb (struct header_cache* h, const char* 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)); @@ -1357,10 +1400,12 @@ hcache_open_lmdb (struct header_cache* h, const char* path) } 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: @@ -1374,6 +1419,13 @@ mutt_hcache_close(header_cache_t *h) 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); @@ -1384,7 +1436,6 @@ mutt_hcache_delete(header_cache_t *h, const char *filename, size_t(*keylen) (const char *fn)) { MDB_val key; - MDB_txn *txn; int rc; if (!h) @@ -1395,24 +1446,25 @@ mutt_hcache_delete(header_cache_t *h, const char *filename, 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