The author is the same as KyotoCabinet, so the API is pretty similar
and it was fairly easy to add.
The only difference is with compression. KyotoCabinet allowed a
generic "c" parameter to enable compression. Tkrzw seems to require
specifying a specific implementation, and those implementations are
enabled during the configuration and build of tkrzw.
Since mutt doesn't know what's available, I've not enabled
OPTHCACHECOMPRESS support.
---
INSTALL | 2 +-
configure.ac | 35 +++++++++++++++++++++-
hcache.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 120 insertions(+), 2 deletions(-)
diff --git a/INSTALL b/INSTALL
index 445adb3f..bacd21c3 100644
--- a/INSTALL
+++ b/INSTALL
@@ -137,7 +137,7 @@ options are:
--enable-hcache
Enable header caching support. If no backend library is
specified via a --with option (e.g. --with-kyotocabinet), Mutt
- will scan in the order: kyotocabinet, tokyocabinet, lmdb,
+ will scan in the order: tkrzw, kyotocabinet, tokyocabinet, lmdb,
qdbm, gdbm, bdb. To skip scanning one or more of these
libraries, use the corresponding --without option.
diff --git a/configure.ac b/configure.ac
index 397e2086..074f002e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1014,6 +1014,7 @@ dnl -- start cache --
db_found=no
db_requested=auto
AC_ARG_ENABLE(hcache, AS_HELP_STRING([--enable-hcache],[Enable header
caching]))
+AC_ARG_WITH(tkrzw, AS_HELP_STRING([--with-tkrzw@<:@=DIR@:>@],[Use tkrzw hcache
backend]))
AC_ARG_WITH(kyotocabinet,
AS_HELP_STRING([--with-kyotocabinet@<:@=DIR@:>@],[Use kyotocabinet hcache
backend]))
AC_ARG_WITH(tokyocabinet,
AS_HELP_STRING([--with-tokyocabinet@<:@=DIR@:>@],[Use tokyocabinet hcache
backend]))
AC_ARG_WITH(lmdb, AS_HELP_STRING([--with-lmdb@<:@=DIR@:>@],[Use lmdb hcache
backend]))
@@ -1032,6 +1033,15 @@ then
need_md5="yes"
+ if test -n "$with_tkrzw" && test "$with_tkrzw" != "no"
+ then
+ if test "$db_requested" != "auto"
+ then
+ AC_MSG_ERROR([more than one header cache engine requested.])
+ else
+ db_requested=tkrzw
+ fi
+ fi
if test -n "$with_kyotocabinet" && test "$with_kyotocabinet" != "no"
then
if test "$db_requested" != "auto"
@@ -1087,6 +1097,29 @@ then
fi
fi
+ dnl -- Tkrzw --
+ if test x$with_tkrzw != xno && test $db_found = no \
+ && test "$db_requested" = auto -o "$db_requested" = tkrzw
+ then
+ if test -n "$with_tkrzw" && test "$with_tkrzw" != "yes"
+ then
+ CPPFLAGS="$CPPFLAGS -I$with_tkrzw/include"
+ LDFLAGS="$LDFLAGS -L$with_tkrzw/lib"
+ fi
+
+ AC_CHECK_HEADER(tkrzw_langc.h,
+ AC_CHECK_LIB(tkrzw, tkrzw_dbm_open,
+ [MUTTLIBS="$MUTTLIBS -ltkrzw"
+ AC_DEFINE(HAVE_TKRZW, 1, [Tkrzw Support])
+ db_found=tkrzw],
+ [CPPFLAGS="$OLDCPPFLAGS"
+ LDFLAGS="$OLDLDFLAGS"]))
+ if test "$db_requested" != auto && test "$db_found" != "$db_requested"
+ then
+ AC_MSG_ERROR([Tkrzw could not be used. Check config.log for details.])
+ fi
+ fi
+
dnl -- Kyoto Cabinet --
if test x$with_kyotocabinet != xno && test $db_found = no \
&& test "$db_requested" = auto -o "$db_requested" = kc
@@ -1259,7 +1292,7 @@ then
if test $db_found = no
then
- AC_MSG_ERROR([You need Kyoto Cabinet, Tokyo Cabinet, LMDB, QDBM, GDBM,
or BDB for hcache])
+ AC_MSG_ERROR([You need Tkrzw, Kyoto Cabinet, Tokyo Cabinet, LMDB,
QDBM, GDBM, or BDB for hcache])
fi
fi
dnl -- end cache --
diff --git a/hcache.c b/hcache.c
index d006055e..dc52aba0 100644
--- a/hcache.c
+++ b/hcache.c
@@ -30,6 +30,8 @@
#include <tcbdb.h>
#elif HAVE_KC
#include <kclangc.h>
+#elif HAVE_TKRZW
+#include <tkrzw_langc.h>
#elif HAVE_GDBM
#include <gdbm.h>
#elif HAVE_DB4
@@ -77,6 +79,13 @@ struct header_cache
char *folder;
unsigned int crc;
};
+#elif HAVE_TKRZW
+struct header_cache
+{
+ TkrzwDBM *db;
+ char *folder;
+ unsigned int crc;
+};
#elif HAVE_GDBM
struct header_cache
{
@@ -841,6 +850,8 @@ mutt_hcache_fetch_raw(header_cache_t *h, const char
*filename,
rv = tcbdbget(h->db, mutt_b2s(path), ksize, &sp);
#elif HAVE_KC
rv = kcdbget(h->db, mutt_b2s(path), ksize, &sp);
+#elif HAVE_TKRZW
+ rv = tkrzw_dbm_get(h->db, mutt_b2s(path), ksize, NULL);
#elif HAVE_GDBM
key.dptr = path->data;
key.dsize = ksize;
@@ -940,6 +951,8 @@ mutt_hcache_store_raw(header_cache_t *h, const char
*filename, void *data,
rv = tcbdbput(h->db, mutt_b2s(path), ksize, data, dlen);
#elif HAVE_KC
rv = kcdbset(h->db, mutt_b2s(path), ksize, data, dlen);
+#elif HAVE_TKRZW
+ rv = tkrzw_dbm_set(h->db, mutt_b2s(path), ksize, data, dlen, true);
#elif HAVE_GDBM
key.dptr = path->data;
key.dsize = ksize;
@@ -1179,6 +1192,69 @@ mutt_hcache_delete(header_cache_t *h, const char
*filename,
return rc;
}
+#elif HAVE_TKRZW
+static int
+hcache_open_tkrzw(struct header_cache *h, const char *path)
+{
+ int rc = -1;
+
+/* Options are discussed at:
+ * https://dbmx.net/tkrzw/api/classtkrzw_1_1PolyDBM.html
+ * in the OpenAdvanced method call.
+ *
+ * Unfortunately the "compression" option requires specifying a specific
library,
+ * and mutt has no way of knowing which libraries tkrzw was built with, so we
ignore
+ * OPTHCACHECOMPRESS.
+ */
+ h->db = tkrzw_dbm_open(path, true, "dbm=TreeDBM");
+ if (!h->db)
+ {
+ muttdbg(2, "tkrzw_dbm_open failed for %s: %s (%d)", path,
+ tkrzw_get_last_status_message(), tkrzw_get_last_status_code());
+ goto cleanup;
+ }
+
+ rc = 0;
+
+cleanup:
+ return rc;
+}
+
+void
+mutt_hcache_close(header_cache_t *h)
+{
+ if (!h)
+ return;
+
+ if (!tkrzw_dbm_close(h->db))
+ muttdbg(2, "tkrzw_dbm_close failed for %s: %s (ecode %d)", h->folder,
+ tkrzw_get_last_status_message(), tkrzw_get_last_status_code());
+ FREE(&h->folder);
+ FREE(&h);
+}
+
+int
+mutt_hcache_delete(header_cache_t *h, const char *filename,
+ size_t (*keylen)(const char *fn))
+{
+ BUFFER *path = NULL;
+ int ksize, rc;
+
+ if (!h)
+ return -1;
+
+ path = mutt_buffer_pool_get();
+ mutt_buffer_strcpy(path, h->folder);
+ mutt_buffer_addstr(path, filename);
+
+ ksize = strlen(h->folder) + keylen(filename);
+
+ rc = tkrzw_dbm_remove(h->db, mutt_b2s(path), ksize);
+
+ mutt_buffer_pool_release(&path);
+ return rc;
+}
+
#elif HAVE_GDBM
static int
hcache_open_gdbm(struct header_cache *h, const char *path)
@@ -1478,6 +1554,8 @@ mutt_hcache_open(const char *path, const char *folder,
hcache_namer_t namer)
hcache_open= hcache_open_tc;
#elif HAVE_KC
hcache_open= hcache_open_kc;
+#elif HAVE_TKRZW
+ hcache_open = hcache_open_tkrzw;
#elif HAVE_GDBM
hcache_open = hcache_open_gdbm;
#elif HAVE_DB4
@@ -1603,4 +1681,11 @@ const char *mutt_hcache_backend(void)
snprintf(backend, sizeof(backend), "kyotocabinet %s", KCVERSION);
return backend;
}
+#elif HAVE_TKRZW
+const char *mutt_hcache_backend(void)
+{
+ static char backend[SHORT_STRING];
+ snprintf(backend, sizeof(backend), "tkrzw %s", TKRZW_LIBRARY_VERSION);
+ return backend;
+}
#endif
--
2.55.0