]> granicus.if.org Git - neomutt/commitdiff
feature: Add Kyoto Cabinet header cache
authorClemens Lang <neverpanic@gmail.com>
Sat, 17 Sep 2016 21:46:19 +0000 (23:46 +0200)
committerRichard Russon <rich@flatcap.org>
Fri, 23 Sep 2016 16:03:42 +0000 (17:03 +0100)
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 <neverpanic@gmail.com>
configure.ac
hcache.c
init.h
mutt.h

index 7277b72ce80eba6b3a3ff4e040d51f220db5a881..53a797260a24f44e7f7a839868bf16a510f81c60 100644 (file)
@@ -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
index de278ce843debeac83b6279735de42444d26eacd..b42e12ed05ab19e00338defefb3e2a6c9696f46c 100644 (file)
--- a/hcache.c
+++ b/hcache.c
@@ -28,6 +28,8 @@
 #include <villa.h>
 #elif HAVE_TC
 #include <tcbdb.h>
+#elif HAVE_KC
+#include <kclangc.h>
 #elif HAVE_GDBM
 #include <gdbm.h>
 #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 78823fffbd31db4977d2a23e476496f17ea5cdba..4584473163ab4329ad391749ffb330872cd10489 100644 (file)
--- 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 29926bf791a7f7fed1d9b94582a0a5b954ea2fe1..63f8c4c0d4b7826907b72439ca8ba284b1a3ab7a 100644 (file)
--- 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