From: Clemens Lang Date: Sat, 17 Sep 2016 21:46:19 +0000 (+0200) Subject: feature: Add Kyoto Cabinet header cache X-Git-Tag: neomutt-20161002~18^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=944435025d5939aa7c568e54a9a1a9b2e8e09c1a;p=neomutt feature: Add Kyoto Cabinet header cache Tokyo Cabinet's website now "strongly recommends" using Kyoto Cabinet instead of Tokyo Cabinet because it claims to be superior. Add Kyoto Cabinet as an option. In some preliminary testing, the performance seems to be on-par with Tokyo Cabinet, but not better. Kyoto Cabinet seems to need a little more space, but the difference is probably not significant. Signed-off-by: Clemens Lang --- diff --git a/configure.ac b/configure.ac index 7277b72ce..53a797260 100644 --- a/configure.ac +++ b/configure.ac @@ -903,6 +903,7 @@ db_requested=auto hcache_db_used=no AC_ARG_ENABLE(hcache, AS_HELP_STRING([--enable-hcache],[Enable header caching])) AC_ARG_WITH(tokyocabinet, AS_HELP_STRING([--without-tokyocabinet],[Don't use tokyocabinet even if it is available])) +AC_ARG_WITH(kyotocabinet, AS_HELP_STRING([--without-kyotocabinet],[Don't use kyotocabinet even if it is available])) AC_ARG_WITH(qdbm, AS_HELP_STRING([--without-qdbm],[Don't use qdbm even if it is available])) AC_ARG_WITH(gdbm, AS_HELP_STRING([--without-gdbm],[Don't use gdbm even if it is available])) AC_ARG_WITH(bdb, AS_HELP_STRING([--with-bdb@<:@=DIR@:>@],[Use BerkeleyDB4 if gdbm is not available])) @@ -924,6 +925,15 @@ then then db_requested=TokyoCabinet fi + if test -n "$with_kyotocabinet" && test "$with_kyotocabinet" != "no" + then + if test "$db_requested" != "auto" + then + AC_MSG_ERROR([more than one header cache engine requested.]) + else + db_requested=KyotoCabinet + fi + fi if test -n "$with_qdbm" && test "$with_qdbm" != "no" then if test "$db_requested" != "auto" @@ -984,6 +994,29 @@ then fi fi + dnl -- Kyoto Cabinet -- + if test "$with_kyotocabinet" != "no" \ + && test "$db_requested" = auto -o "$db_requested" = KyotoCabinet + then + if test -n "$with_kyotocabinet" && test "$with_kyotocabinet" != "yes" + then + CPPFLAGS="$CPPFLAGS -I$with_kyotocabinet/include" + LDFLAGS="$LDFLAGS -L$with_kyotocabinet/lib" + fi + + AC_CHECK_HEADER(kclangc.h, + AC_CHECK_LIB(kyotocabinet, kcdbopen, + [MUTTLIBS="$MUTTLIBS -lkyotocabinet" + AC_DEFINE(HAVE_KC, 1, [Kyoto Cabinet Support]) + db_found=KyotoCabinet], + [CPPFLAGS="$OLDCPPFLAGS" + LDFLAGS="$OLDLDFLAGS"])) + if test "$db_requested" != auto && test "$db_found" != "$db_requested" + then + AC_MSG_ERROR([Kyoto Cabinet could not be used. Check config.log for details.]) + fi + fi + dnl -- QDBM -- if test "$with_qdbm" != "no" && test $db_found = no \ && test "$db_requested" = auto -o "$db_requested" = QDBM @@ -1134,7 +1167,7 @@ then if test $db_found = no then - AC_MSG_ERROR([You need Tokyo Cabinet, QDBM, GDBM, Berkeley DB4 or LMDB for hcache]) + AC_MSG_ERROR([You need Tokyo Cabinet, Kyoto Cabinet, QDBM, GDBM, Berkeley DB4 or LMDB for hcache]) fi fi hcache_db_used=$db_found diff --git a/hcache.c b/hcache.c index de278ce84..b42e12ed0 100644 --- a/hcache.c +++ b/hcache.c @@ -28,6 +28,8 @@ #include #elif HAVE_TC #include +#elif HAVE_KC +#include #elif HAVE_GDBM #include #elif HAVE_DB4 @@ -66,6 +68,13 @@ struct header_cache char *folder; unsigned int crc; }; +#elif HAVE_KC +struct header_cache +{ + KCDB *db; + char *folder; + unsigned int crc; +}; #elif HAVE_GDBM struct header_cache { @@ -750,6 +759,9 @@ mutt_hcache_fetch_raw (header_cache_t *h, const char *filename, #elif HAVE_TC void *data; int sp; +#elif HAVE_KC + void *data; + size_t sp; #elif HAVE_GDBM datum key; datum data; @@ -827,6 +839,10 @@ mutt_hcache_fetch_raw (header_cache_t *h, const char *filename, #elif HAVE_TC data = tcbdbget(h->db, path, ksize, &sp); + return data; +#elif HAVE_KC + data = kcdbget(h->db, path, ksize, &sp); + return data; #elif HAVE_GDBM key.dptr = path; @@ -938,6 +954,8 @@ mutt_hcache_store_raw (header_cache_t* h, const char* filename, void* data, return vlput(h->db, path, ksize, data, dlen, VL_DOVER); #elif HAVE_TC return tcbdbput(h->db, path, ksize, data, dlen); +#elif HAVE_KC + return kcdbset(h->db, path, ksize, data, dlen); #elif HAVE_GDBM key.dptr = path; key.dsize = ksize; @@ -1073,6 +1091,74 @@ mutt_hcache_delete(header_cache_t *h, const char *filename, return tcbdbout(h->db, path, ksize); } +#elif HAVE_KC +static int +hcache_open_kc (struct header_cache *h, const char *path) +{ + char kcdbpath[_POSIX_PATH_MAX]; + int printfresult; + + printfresult = snprintf(kcdbpath, sizeof(kcdbpath), + "%s#type=kct#opts=%s#rcomp=lex", + path, option(OPTHCACHECOMPRESS) ? "lc" : "l"); + if ((printfresult < 0) || (printfresult >= sizeof(kcdbpath))) + { + return -1; + } + + h->db = kcdbnew(); + if (!h->db) + return -1; + + if (kcdbopen(h->db, kcdbpath, KCOWRITER | KCOCREATE)) + return 0; + else + { +#ifdef DEBUG + int ecode = kcdbecode (h->db); + dprint (2, (debugfile, "kcdbopen failed for %s: %s (ecode %d)\n", kcdbpath, kcdbemsg (h->db), ecode)); +#endif + kcdbdel(h->db); + return -1; + } +} + +void +mutt_hcache_close(header_cache_t *h) +{ + if (!h) + return; + + if (!kcdbclose(h->db)) + { +#ifdef DEBUG + int ecode = kcdbecode (h->db); + dprint (2, (debugfile, "kcdbclose failed for %s: %s (ecode %d)\n", h->folder, kcdbemsg (h->db), ecode)); +#endif + } + kcdbdel(h->db); + FREE(&h->folder); + FREE(&h); +} + +int +mutt_hcache_delete(header_cache_t *h, const char *filename, + size_t(*keylen) (const char *fn)) +{ + char path[_POSIX_PATH_MAX]; + int ksize; + + if (!h) + return -1; + + strncpy(path, h->folder, sizeof (path)); + safe_strcat(path, sizeof (path), filename); + + ksize = strlen(h->folder) + keylen(path + strlen(h->folder)); + + return kcdbremove(h->db, path, ksize); +} + #elif HAVE_GDBM static int hcache_open_gdbm (struct header_cache* h, const char* path) @@ -1341,7 +1427,9 @@ mutt_hcache_open(const char *path, const char *folder, hcache_namer_t namer) #if HAVE_QDBM hcache_open = hcache_open_qdbm; #elif HAVE_TC - hcache_open= hcache_open_tc; + hcache_open = hcache_open_tc; +#elif HAVE_KC + hcache_open = hcache_open_kc; #elif HAVE_GDBM hcache_open = hcache_open_gdbm; #elif HAVE_DB4 @@ -1444,4 +1532,14 @@ const char *mutt_hcache_backend (void) { return "tokyocabinet " _TC_VERSION; } +#elif HAVE_KC +const char *mutt_hcache_backend (void) +{ + /* SHORT_STRING(128) should be more than enough for KCVERSION */ + static char version_cache[SHORT_STRING] = ""; + if (!version_cache[0]) + snprintf(version_cache, sizeof(version_cache), "kyotocabinet %s", KCVERSION); + + return version_cache; +} #endif diff --git a/init.h b/init.h index 78823fffb..458447316 100644 --- a/init.h +++ b/init.h @@ -1058,7 +1058,7 @@ struct option_t MuttVars[] = { ** Header caching can greatly improve speed when opening POP, IMAP ** MH or Maildir folders, see ``$caching'' for details. */ -#if defined(HAVE_QDBM) || defined(HAVE_TC) +#if defined(HAVE_QDBM) || defined(HAVE_TC) || defined(HAVE_KC) { "header_cache_compress", DT_BOOL, R_NONE, OPTHCACHECOMPRESS, 1 }, /* ** .pp diff --git a/mutt.h b/mutt.h index 29926bf79..63f8c4c0d 100644 --- a/mutt.h +++ b/mutt.h @@ -397,7 +397,7 @@ enum OPTFORWQUOTE, #ifdef USE_HCACHE OPTHCACHEVERIFY, -#if defined(HAVE_QDBM) || defined(HAVE_TC) +#if defined(HAVE_QDBM) || defined(HAVE_TC) || defined(HAVE_KC) OPTHCACHECOMPRESS, #endif /* HAVE_QDBM */ #endif