summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bench/wtperf/wtperf.c5
-rw-r--r--bench/wtperf/wtperf.h3
-rw-r--r--bench/wtperf/wtperf_opt.i2
-rw-r--r--build_posix/Make.base3
-rw-r--r--build_posix/Make.subdirs1
-rw-r--r--build_posix/aclocal/options.m434
-rw-r--r--build_win/wiredtiger_config.h6
-rw-r--r--dist/api_data.py9
-rwxr-xr-xdist/s_export2
-rw-r--r--dist/s_string.ok17
-rw-r--r--dist/s_void9
-rw-r--r--examples/c/ex_all.c33
-rw-r--r--examples/java/com/wiredtiger/examples/ex_all.java29
-rw-r--r--ext/compressors/lz4/lz4_compress.c41
-rw-r--r--ext/compressors/snappy/snappy_compress.c119
-rw-r--r--ext/compressors/zlib/zlib_compress.c291
-rw-r--r--ext/compressors/zstd/Makefile.am11
-rw-r--r--ext/compressors/zstd/zstd_compress.c358
-rw-r--r--src/conn/conn_api.c14
-rw-r--r--src/docs/build-posix.dox6
-rw-r--r--src/docs/compression.dox44
-rw-r--r--src/docs/spell.ok2
-rw-r--r--src/docs/wtperf.dox2
-rw-r--r--src/include/wiredtiger.in16
-rw-r--r--test/format/config.c21
-rw-r--r--test/format/config.h2
-rw-r--r--test/format/format.h3
-rw-r--r--test/format/wts.c5
-rw-r--r--test/suite/test_encrypt01.py1
29 files changed, 905 insertions, 184 deletions
diff --git a/bench/wtperf/wtperf.c b/bench/wtperf/wtperf.c
index a1dc78a5312..8c7f0053388 100644
--- a/bench/wtperf/wtperf.c
+++ b/bench/wtperf/wtperf.c
@@ -2078,6 +2078,11 @@ config_compress(WTPERF *wtperf)
wtperf->compress_ext = ZLIB_EXT;
#endif
wtperf->compress_table = ZLIB_BLK;
+ } else if (strcmp(s, "zstd") == 0) {
+#ifndef HAVE_BUILTIN_EXTENSION_ZSTD
+ wtperf->compress_ext = ZSTD_EXT;
+#endif
+ wtperf->compress_table = ZSTD_BLK;
} else {
fprintf(stderr,
"invalid compression configuration: %s\n", s);
diff --git a/bench/wtperf/wtperf.h b/bench/wtperf/wtperf.h
index afce017d919..81d74e134f6 100644
--- a/bench/wtperf/wtperf.h
+++ b/bench/wtperf/wtperf.h
@@ -54,6 +54,9 @@ typedef struct __truncate_queue_entry TRUNCATE_QUEUE_ENTRY;
#define ZLIB_BLK BLKCMP_PFX "zlib"
#define ZLIB_EXT \
EXT_PFX EXTPATH "zlib/.libs/libwiredtiger_zlib.so" EXT_SFX
+#define ZSTD_BLK BLKCMP_PFX "zstd"
+#define ZSTD_EXT \
+ EXT_PFX EXTPATH "zstd/.libs/libwiredtiger_zstd.so" EXT_SFX
typedef struct {
int64_t threads; /* Thread count */
diff --git a/bench/wtperf/wtperf_opt.i b/bench/wtperf/wtperf_opt.i
index d2d255b38c2..680eb53a90e 100644
--- a/bench/wtperf/wtperf_opt.i
+++ b/bench/wtperf/wtperf_opt.i
@@ -100,7 +100,7 @@ DEF_OPT_AS_BOOL(close_conn, 1, "properly close connection at end of test. "
DEF_OPT_AS_BOOL(compact, 0, "post-populate compact for LSM merging activity")
DEF_OPT_AS_STRING(compression, "none",
"compression extension. Allowed configuration values are: "
- "'none', 'lz4', 'snappy', 'zlib'")
+ "'none', 'lz4', 'snappy', 'zlib', 'zstd'")
DEF_OPT_AS_BOOL(create, 1,
"do population phase; false to use existing database")
DEF_OPT_AS_UINT32(database_count, 1,
diff --git a/build_posix/Make.base b/build_posix/Make.base
index 4efbe3f76c3..5b945aca5e0 100644
--- a/build_posix/Make.base
+++ b/build_posix/Make.base
@@ -77,6 +77,9 @@ endif
if HAVE_BUILTIN_EXTENSION_ZLIB
libwiredtiger_la_LIBADD += ext/compressors/zlib/libwiredtiger_zlib.la
endif
+if HAVE_BUILTIN_EXTENSION_ZSTD
+libwiredtiger_la_LIBADD += ext/compressors/zstd/libwiredtiger_zstd.la
+endif
libwiredtiger_static_la_LIBADD=$(libwiredtiger_la_LIBADD)
libwiredtiger_static_la_SOURCES=$(libwiredtiger_la_SOURCES)
diff --git a/build_posix/Make.subdirs b/build_posix/Make.subdirs
index 0b5175e4196..55941837249 100644
--- a/build_posix/Make.subdirs
+++ b/build_posix/Make.subdirs
@@ -11,6 +11,7 @@ ext/compressors/lz4 LZ4
ext/compressors/nop
ext/compressors/snappy SNAPPY
ext/compressors/zlib ZLIB
+ext/compressors/zstd ZSTD
ext/datasources/helium HAVE_HELIUM
ext/encryptors/nop
ext/encryptors/rotn
diff --git a/build_posix/aclocal/options.m4 b/build_posix/aclocal/options.m4
index 1f6a1690279..7043430a6d6 100644
--- a/build_posix/aclocal/options.m4
+++ b/build_posix/aclocal/options.m4
@@ -19,10 +19,12 @@ AH_TEMPLATE(HAVE_BUILTIN_EXTENSION_SNAPPY,
[Snappy support automatically loaded.])
AH_TEMPLATE(HAVE_BUILTIN_EXTENSION_ZLIB,
[Zlib support automatically loaded.])
+AH_TEMPLATE(HAVE_BUILTIN_EXTENSION_ZSTD,
+ [ZSTD support automatically loaded.])
AC_MSG_CHECKING(if --with-builtins option specified)
AC_ARG_WITH(builtins,
[AS_HELP_STRING([--with-builtins],
- [builtin extension names (lz4, snappy, zlib).])],
+ [builtin extension names (lz4, snappy, zlib, zstd).])],
[with_builtins=$withval],
[with_builtins=])
@@ -36,6 +38,8 @@ for builtin_i in $builtin_list; do
wt_cv_with_builtin_extension_snappy=yes;;
zlib) AC_DEFINE(HAVE_BUILTIN_EXTENSION_ZLIB)
wt_cv_with_builtin_extension_zlib=yes;;
+ zstd) AC_DEFINE(HAVE_BUILTIN_EXTENSION_ZSTD)
+ wt_cv_with_builtin_extension_zstd=yes;;
*) AC_MSG_ERROR([Unknown builtin extension "$builtin_i"]);;
esac
done
@@ -45,6 +49,8 @@ AM_CONDITIONAL([HAVE_BUILTIN_EXTENSION_SNAPPY],
[test "$wt_cv_with_builtin_extension_snappy" = "yes"])
AM_CONDITIONAL([HAVE_BUILTIN_EXTENSION_ZLIB],
[test "$wt_cv_with_builtin_extension_zlib" = "yes"])
+AM_CONDITIONAL([HAVE_BUILTIN_EXTENSION_ZSTD],
+ [test "$wt_cv_with_builtin_extension_zstd" = "yes"])
AC_MSG_RESULT($with_builtins)
AH_TEMPLATE(
@@ -276,4 +282,30 @@ if test "$wt_cv_enable_zlib" = "yes"; then
fi
AM_CONDITIONAL([ZLIB], [test "$wt_cv_enable_zlib" = "yes"])
+AC_MSG_CHECKING(if --enable-zstd option specified)
+AC_ARG_ENABLE(zstd,
+ [AS_HELP_STRING([--enable-zstd],
+ [Build the zstd compressor extension.])], r=$enableval, r=no)
+case "$r" in
+no) if test "$wt_cv_with_builtin_extension_zstd" = "yes"; then
+ wt_cv_enable_zstd=yes
+ else
+ wt_cv_enable_zstd=no
+ fi
+ ;;
+*) if test "$wt_cv_with_builtin_extension_zstd" = "yes"; then
+ AC_MSG_ERROR(
+ [Only one of --enable-zstd --with-builtins=zstd allowed])
+ fi
+ wt_cv_enable_zstd=yes;;
+esac
+AC_MSG_RESULT($wt_cv_enable_zstd)
+if test "$wt_cv_enable_zstd" = "yes"; then
+ AC_CHECK_HEADER(zstd.h,,
+ [AC_MSG_ERROR([--enable-zstd requires zstd.h])])
+ AC_CHECK_LIB(zstd, ZSTD_compress,,
+ [AC_MSG_ERROR([--enable-zstd requires Zstd library])])
+fi
+AM_CONDITIONAL([ZSTD], [test "$wt_cv_enable_zstd" = "yes"])
+
])
diff --git a/build_win/wiredtiger_config.h b/build_win/wiredtiger_config.h
index 83ddc6eb194..78d2784cb70 100644
--- a/build_win/wiredtiger_config.h
+++ b/build_win/wiredtiger_config.h
@@ -19,6 +19,9 @@
/* Zlib support automatically loaded. */
/* #undef HAVE_BUILTIN_EXTENSION_ZLIB */
+/* ZSTD support automatically loaded. */
+/* #undef HAVE_BUILTIN_EXTENSION_ZSTD */
+
/* Define to 1 if you have the `clock_gettime' function. */
/* #undef HAVE_CLOCK_GETTIME */
@@ -70,6 +73,9 @@
/* Define to 1 if you have the `z' library (-lz). */
/* #undef HAVE_LIBZ */
+/* Define to 1 if you have the `zstd' library (-lzstd). */
+/* #undef HAVE_LIBZSTD */
+
/* Define to 1 if you have the <memory.h> header file. */
/* #undef HAVE_MEMORY_H */
diff --git a/dist/api_data.py b/dist/api_data.py
index df3577f56b8..7affc58a217 100644
--- a/dist/api_data.py
+++ b/dist/api_data.py
@@ -136,8 +136,8 @@ file_config = format_meta + [
configure a compressor for file blocks. Permitted values are \c "none"
or custom compression engine name created with
WT_CONNECTION::add_compressor. If WiredTiger has builtin support for
- \c "snappy", \c "lz4" or \c "zlib" compression, these names are also
- available. See @ref compression for more information'''),
+ \c "lz4", \c "snappy", \c "zlib" or \c "zstd" compression, these names
+ are also available. See @ref compression for more information'''),
Config('cache_resident', 'false', r'''
do not ever evict the object's pages from cache. Not compatible with
LSM tables; see @ref tuning_cache_resident for more information''',
@@ -570,8 +570,9 @@ wiredtiger_open_log_configuration = [
configure a compressor for log records. Permitted values are
\c "none" or custom compression engine name created with
WT_CONNECTION::add_compressor. If WiredTiger has builtin support
- for \c "snappy", \c "lz4" or \c "zlib" compression, these names
- are also available. See @ref compression for more information'''),
+ for \c "lz4", \c "snappy", \c "zlib" or \c "zstd" compression,
+ these names are also available. See @ref compression for more
+ information'''),
Config('file_max', '100MB', r'''
the maximum size of log files''',
min='100KB', max='2GB'),
diff --git a/dist/s_export b/dist/s_export
index dc69238b270..b8e42c970f9 100755
--- a/dist/s_export
+++ b/dist/s_export
@@ -26,7 +26,7 @@ check()
sort |
uniq -u |
egrep -v \
- 'zlib_extension_init|lz4_extension_init|snappy_extension_init' > $t
+ 'lz4_extension_init|snappy_extension_init|zlib_extension_init|zstd_extension_init' > $t
test -s $t && {
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
diff --git a/dist/s_string.ok b/dist/s_string.ok
index a80af2f18e1..7cf96aec399 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -60,6 +60,7 @@ COVERITY
CPUs
CRC
CSV
+CStream
CURSORs
CURSTD
CallsCustDate
@@ -69,6 +70,7 @@ Checksum
Checksums
CityHash
CloseHandle
+Collet
Comparator
Config
Coverity
@@ -125,6 +127,7 @@ FORALL
FOREACH
FS
FULLFSYNC
+Facebook
FindClose
FindFirstFile
Fixup
@@ -398,6 +401,12 @@ WriteFile
Wuninitialized
Wunused
XP
+Yann
+ZSTD
+Zlib
+Zlib's
+Zstd
+Zstd's
abcdef
abcdefghijklmnopqrstuvwxyz
addl
@@ -515,6 +524,7 @@ collatorp
comparator
comparep
compat
+compressStream
concat
cond
conf
@@ -534,6 +544,7 @@ cp
cpuid
crc
create's
+createCStream
crypto
cryptobad
csv
@@ -626,6 +637,7 @@ emp
encodings
encryptor
encryptors
+endStream
endian
english
enqueue
@@ -753,6 +765,7 @@ infeasible
inflateInit
infmt
init
+initCStream
initializers
initn
initsize
@@ -854,6 +867,7 @@ majorp
malloc
marshall
marshalled
+maxCLevel
maxcpu
maxdbs
mbll
@@ -1233,4 +1247,7 @@ zalloc
zf
zfree
zlib
+zlib's
+zstd
+zstd's
zu
diff --git a/dist/s_void b/dist/s_void
index f7bfbcc7e8e..e5e9f97c0b7 100644
--- a/dist/s_void
+++ b/dist/s_void
@@ -96,10 +96,13 @@ func_ok()
-e '/int wiredtiger_extension_init$/d' \
-e '/int wiredtiger_extension_terminate$/d' \
-e '/int wiredtiger_pack_close$/d' \
- -e '/int wt_snappy_pre_size$/d' \
- -e '/int wt_snappy_terminate$/d' \
+ -e '/int snappy_pre_size$/d' \
+ -e '/int snappy_terminate$/d' \
-e '/int zlib_error$/d' \
- -e '/int zlib_terminate$/d'
+ -e '/int zlib_terminate$/d' \
+ -e '/int zstd_error$/d' \
+ -e '/int zstd_pre_size$/d' \
+ -e '/int zstd_terminate$/d'
}
# Complain about functions which return an "int" but which don't return except
diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c
index a2042c22bbb..ea646604a76 100644
--- a/examples/c/ex_all.c
+++ b/examples/c/ex_all.c
@@ -611,6 +611,13 @@ session_ops(WT_SESSION *session)
"block_compressor=zlib,key_format=S,value_format=S");
/*! [Create a zlib compressed table] */
ret = session->drop(session, "table:mytable", NULL);
+
+ /*! [Create a zstd compressed table] */
+ ret = session->create(session,
+ "table:mytable",
+ "block_compressor=zstd,key_format=S,value_format=S");
+ /*! [Create a zstd compressed table] */
+ ret = session->drop(session, "table:mytable", NULL);
#endif
/*! [Configure checksums to uncompressed] */
@@ -1108,6 +1115,32 @@ main(void)
if (ret == 0)
(void)conn->close(conn, NULL);
+ /*! [Configure zlib extension with compression level] */
+ ret = wiredtiger_open(home, NULL,
+ "create,"
+ "extensions=[/usr/local/lib/"
+ "libwiredtiger_zlib.so=[config=[compression_level=3]]]", &conn);
+ /*! [Configure zlib extension with compression level] */
+ if (ret == 0)
+ (void)conn->close(conn, NULL);
+
+ /*! [Configure zstd extension] */
+ ret = wiredtiger_open(home, NULL,
+ "create,"
+ "extensions=[/usr/local/lib/libwiredtiger_zstd.so]", &conn);
+ /*! [Configure zstd extension] */
+ if (ret == 0)
+ (void)conn->close(conn, NULL);
+
+ /*! [Configure zstd extension with compression level] */
+ ret = wiredtiger_open(home, NULL,
+ "create,"
+ "extensions=[/usr/local/lib/"
+ "libwiredtiger_zstd.so=[config=[compression_level=9]]]", &conn);
+ /*! [Configure zstd extension with compression level] */
+ if (ret == 0)
+ (void)conn->close(conn, NULL);
+
/*
* This example code gets run, and direct I/O might not be available,
* causing the open to fail. The documentation requires code snippets,
diff --git a/examples/java/com/wiredtiger/examples/ex_all.java b/examples/java/com/wiredtiger/examples/ex_all.java
index 83a37e9a6a5..cf8491aa4f8 100644
--- a/examples/java/com/wiredtiger/examples/ex_all.java
+++ b/examples/java/com/wiredtiger/examples/ex_all.java
@@ -549,6 +549,12 @@ session_ops(Session session)
"block_compressor=zlib,key_format=S,value_format=S");
/*! [Create a zlib compressed table] */
ret = session.drop("table:mytable", null);
+
+ /*! [Create a zstd compressed table] */
+ ret = session.create("table:mytable",
+ "block_compressor=zstd,key_format=S,value_format=S");
+ /*! [Create a zstd compressed table] */
+ ret = session.drop("table:mytable", null);
} // if (false)
/*! [Configure checksums to uncompressed] */
@@ -942,6 +948,29 @@ allExample()
/*! [Configure zlib extension] */
conn.close(null);
+ /*! [Configure zlib extension with compression level] */
+ conn = wiredtiger.open(home,
+ "create," +
+ "extensions=[/usr/local/lib/" +
+ "libwiredtiger_zlib.so=[config=[compression_level=3]]]");
+ /*! [Configure zlib extension with compression level] */
+ conn.close(null);
+
+ /*! [Configure zstd extension] */
+ conn = wiredtiger.open(home,
+ "create," +
+ "extensions=[/usr/local/lib/libwiredtiger_zstd.so]");
+ /*! [Configure zstd extension] */
+ conn.close(null);
+
+ /*! [Configure zstd extension with compression level] */
+ conn = wiredtiger.open(home,
+ "create," +
+ "extensions=[/usr/local/lib/" +
+ "libwiredtiger_zstd.so=[config=[compression_level=9]]]");
+ /*! [Configure zstd extension with compression level] */
+ conn.close(null);
+
/*
* This example code gets run, and direct I/O might not be available,
* causing the open to fail. The documentation requires code snippets,
diff --git a/ext/compressors/lz4/lz4_compress.c b/ext/compressors/lz4/lz4_compress.c
index 35159d0fa76..885701e564b 100644
--- a/ext/compressors/lz4/lz4_compress.c
+++ b/ext/compressors/lz4/lz4_compress.c
@@ -31,10 +31,20 @@
#include <stdlib.h>
#include <string.h>
+/*
+ * We need to include the configuration file to detect whether this extension
+ * is being built into the WiredTiger library; application-loaded compression
+ * functions won't need it.
+ */
#include <wiredtiger_config.h>
+
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
/* Local compressor structure. */
typedef struct {
WT_COMPRESSOR compressor; /* Must come first */
@@ -171,8 +181,6 @@ lz4_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
int decoded;
uint8_t *dst_tmp;
- (void)src_len; /* Unused parameters */
-
wt_api = ((LZ4_COMPRESSOR *)compressor)->wt_api;
/*
@@ -183,6 +191,13 @@ lz4_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
#ifdef WORDS_BIGENDIAN
lz4_prefix_swap(&prefix);
#endif
+ if (prefix.compressed_len + sizeof(LZ4_PREFIX) > src_len) {
+ (void)wt_api->err_printf(wt_api,
+ session,
+ "WT_COMPRESSOR.decompress: stored size exceeds source "
+ "size");
+ return (WT_ERROR);
+ }
/*
* Decompress, starting after the prefix bytes. Use safe decompression:
@@ -267,18 +282,24 @@ lz4_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
size_t *result_lenp, uint32_t *result_slotsp)
{
LZ4_PREFIX prefix;
- int lz4_len;
uint32_t slot;
- int sourceSize, targetDestSize;
+ int lz4_len, sourceSize, targetDestSize;
(void)compressor; /* Unused parameters */
(void)session;
(void)split_pct;
(void)final;
- sourceSize = (int)offsets[slots]; /* Type conversion */
- targetDestSize =
- (int)((dst_len < page_max ? dst_len : page_max) - extra);
+ /*
+ * Set the source and target sizes. The target size is complicated: we
+ * don't want to exceed the smaller of the maximum page size or the
+ * destination buffer length, and in both cases we have to take into
+ * account the space for our overhead and the extra bytes required by
+ * our caller.
+ */
+ sourceSize = (int)offsets[slots];
+ targetDestSize = (int)(page_max < dst_len ? page_max : dst_len);
+ targetDestSize -= (int)(sizeof(LZ4_PREFIX) + extra);
/* Compress, starting after the prefix bytes. */
lz4_len = LZ4_compress_destSize((const char *)src,
@@ -352,7 +373,7 @@ lz4_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
* Add a LZ4 compressor.
*/
static int
-lz_add_compressor(WT_CONNECTION *connection, int raw, const char *name)
+lz_add_compressor(WT_CONNECTION *connection, bool raw, const char *name)
{
LZ4_COMPRESSOR *lz4_compressor;
@@ -391,9 +412,9 @@ lz4_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
(void)config; /* Unused parameters */
- if ((ret = lz_add_compressor(connection, 1, "lz4")) != 0)
+ if ((ret = lz_add_compressor(connection, true, "lz4")) != 0)
return (ret);
- if ((ret = lz_add_compressor(connection, 0, "lz4-noraw")) != 0)
+ if ((ret = lz_add_compressor(connection, false, "lz4-noraw")) != 0)
return (ret);
return (0);
}
diff --git a/ext/compressors/snappy/snappy_compress.c b/ext/compressors/snappy/snappy_compress.c
index 981e334a2de..32f1ddcb9a0 100644
--- a/ext/compressors/snappy/snappy_compress.c
+++ b/ext/compressors/snappy/snappy_compress.c
@@ -31,10 +31,20 @@
#include <stdlib.h>
#include <string.h>
+/*
+ * We need to include the configuration file to detect whether this extension
+ * is being built into the WiredTiger library; application-loaded compression
+ * functions won't need it.
+ */
#include <wiredtiger_config.h>
+
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
/* Local compressor structure. */
typedef struct {
WT_COMPRESSOR compressor; /* Must come first */
@@ -42,6 +52,12 @@ typedef struct {
WT_EXTENSION_API *wt_api; /* Extension API */
} SNAPPY_COMPRESSOR;
+/*
+ * Snappy decompression requires an exact compressed byte count. WiredTiger
+ * doesn't track that value, store it in the destination buffer.
+ */
+#define SNAPPY_PREFIX sizeof(uint64_t)
+
#ifdef WORDS_BIGENDIAN
/*
* snappy_bswap64 --
@@ -64,11 +80,11 @@ snappy_bswap64(uint64_t v)
#endif
/*
- * wt_snappy_error --
+ * snappy_error --
* Output an error message, and return a standard error code.
*/
static int
-wt_snappy_error(WT_COMPRESSOR *compressor,
+snappy_error(WT_COMPRESSOR *compressor,
WT_SESSION *session, const char *call, snappy_status snret)
{
WT_EXTENSION_API *wt_api;
@@ -94,68 +110,69 @@ wt_snappy_error(WT_COMPRESSOR *compressor,
}
/*
- * wt_snappy_compress --
+ * snappy_compression --
* WiredTiger snappy compression.
*/
static int
-wt_snappy_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
+snappy_compression(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_len,
size_t *result_lenp, int *compression_failed)
{
snappy_status snret;
size_t snaplen;
+ uint64_t snaplen_u64;
char *snapbuf;
/*
- * dst_len was computed in wt_snappy_pre_size, so we know it's big
- * enough. Skip past the space we'll use to store the final count
- * of compressed bytes.
+ * dst_len was computed in snappy_pre_size, so we know it's big enough.
+ * Skip past the space we'll use to store the final count of compressed
+ * bytes.
*/
- snaplen = dst_len - sizeof(size_t);
- snapbuf = (char *)dst + sizeof(size_t);
+ snaplen = dst_len - SNAPPY_PREFIX;
+ snapbuf = (char *)dst + SNAPPY_PREFIX;
/* snaplen is an input and an output arg. */
snret = snappy_compress((char *)src, src_len, snapbuf, &snaplen);
- if (snret == SNAPPY_OK) {
- if (snaplen + sizeof(size_t) < src_len) {
- *result_lenp = snaplen + sizeof(size_t);
- *compression_failed = 0;
-
- /*
- * On decompression, snappy requires an exact compressed
- * byte count (the current value of snaplen). WiredTiger
- * does not preserve that value, so save snaplen at the
- * beginning of the destination buffer.
- *
- * Store the value in little-endian format.
- */
+ if (snret == SNAPPY_OK && snaplen + SNAPPY_PREFIX < src_len) {
+ *result_lenp = snaplen + SNAPPY_PREFIX;
+ *compression_failed = 0;
+
+ /*
+ * On decompression, snappy requires an exact compressed byte
+ * count (the current value of snaplen). WiredTiger does not
+ * preserve that value, so save snaplen at the beginning of
+ * the destination buffer.
+ *
+ * Store the value in little-endian format.
+ */
+ snaplen_u64 = snaplen;
#ifdef WORDS_BIGENDIAN
- snaplen = snappy_bswap64(snaplen);
+ snaplen_u64 = snappy_bswap64(snaplen_u64);
#endif
- *(size_t *)dst = snaplen;
- } else
- /* The compressor failed to produce a smaller result. */
- *compression_failed = 1;
+ *(uint64_t *)dst = snaplen_u64;
return (0);
}
- return (wt_snappy_error(compressor, session, "snappy_compress", snret));
+
+ *compression_failed = 1;
+ return (snret == SNAPPY_OK ?
+ 0 : snappy_error(compressor, session, "snappy_compress", snret));
}
/*
- * wt_snappy_decompress --
+ * snappy_decompression --
* WiredTiger snappy decompression.
*/
static int
-wt_snappy_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
+snappy_decompression(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len,
uint8_t *dst, size_t dst_len,
size_t *result_lenp)
{
WT_EXTENSION_API *wt_api;
snappy_status snret;
- size_t snaplen;
+ uint64_t snaplen;
wt_api = ((SNAPPY_COMPRESSOR *)compressor)->wt_api;
@@ -163,36 +180,36 @@ wt_snappy_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
* Retrieve the saved length, handling little- to big-endian conversion
* as necessary.
*/
- snaplen = *(size_t *)src;
+ snaplen = *(uint64_t *)src;
#ifdef WORDS_BIGENDIAN
snaplen = snappy_bswap64(snaplen);
#endif
- if (snaplen + sizeof(size_t) > src_len) {
+ if (snaplen + SNAPPY_PREFIX > src_len) {
(void)wt_api->err_printf(wt_api,
session,
- "wt_snappy_decompress: stored size exceeds buffer size");
+ "WT_COMPRESSOR.decompress: stored size exceeds source "
+ "size");
return (WT_ERROR);
}
/* dst_len is an input and an output arg. */
snret = snappy_uncompress(
- (char *)src + sizeof(size_t), snaplen, (char *)dst, &dst_len);
+ (char *)src + SNAPPY_PREFIX,
+ (size_t)snaplen, (char *)dst, &dst_len);
if (snret == SNAPPY_OK) {
*result_lenp = dst_len;
return (0);
}
-
- return (
- wt_snappy_error(compressor, session, "snappy_decompress", snret));
+ return (snappy_error(compressor, session, "snappy_decompress", snret));
}
/*
- * wt_snappy_pre_size --
+ * snappy_pre_size --
* WiredTiger snappy destination buffer sizing.
*/
static int
-wt_snappy_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
+snappy_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len,
size_t *result_lenp)
{
@@ -203,19 +220,19 @@ wt_snappy_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
/*
* Snappy requires the dest buffer be somewhat larger than the source.
* Fortunately, this is fast to compute, and will give us a dest buffer
- * in wt_snappy_compress that we can compress to directly. We add space
+ * in snappy_compress that we can compress to directly. We add space
* in the dest buffer to store the accurate compressed size.
*/
- *result_lenp = snappy_max_compressed_length(src_len) + sizeof(size_t);
+ *result_lenp = snappy_max_compressed_length(src_len) + SNAPPY_PREFIX;
return (0);
}
/*
- * wt_snappy_terminate --
+ * snappy_terminate --
* WiredTiger snappy compression termination.
*/
static int
-wt_snappy_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
+snappy_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
{
(void)session; /* Unused parameters */
@@ -227,9 +244,9 @@ int snappy_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
/*
* snappy_extension_init --
- * WiredTiger snappy compression extension - called directly when
- * Snappy support is built in, or via wiredtiger_extension_init when
- * snappy support is included via extension loading.
+ * WiredTiger snappy compression extension - called directly when snappy
+ * support is built in, or via wiredtiger_extension_init when snappy support
+ * is included via extension loading.
*/
int
snappy_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
@@ -241,11 +258,11 @@ snappy_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
if ((snappy_compressor = calloc(1, sizeof(SNAPPY_COMPRESSOR))) == NULL)
return (errno);
- snappy_compressor->compressor.compress = wt_snappy_compress;
+ snappy_compressor->compressor.compress = snappy_compression;
snappy_compressor->compressor.compress_raw = NULL;
- snappy_compressor->compressor.decompress = wt_snappy_decompress;
- snappy_compressor->compressor.pre_size = wt_snappy_pre_size;
- snappy_compressor->compressor.terminate = wt_snappy_terminate;
+ snappy_compressor->compressor.decompress = snappy_decompression;
+ snappy_compressor->compressor.pre_size = snappy_pre_size;
+ snappy_compressor->compressor.terminate = snappy_terminate;
snappy_compressor->wt_api = connection->get_extension_api(connection);
diff --git a/ext/compressors/zlib/zlib_compress.c b/ext/compressors/zlib/zlib_compress.c
index 484df0a6785..ef20503df0a 100644
--- a/ext/compressors/zlib/zlib_compress.c
+++ b/ext/compressors/zlib/zlib_compress.c
@@ -32,16 +32,18 @@
#include <stdlib.h>
#include <string.h>
-#include <wiredtiger.h>
-#include <wiredtiger_ext.h>
-
/*
* We need to include the configuration file to detect whether this extension
- * is being built into the WiredTiger library.
+ * is being built into the WiredTiger library; application-loaded compression
+ * functions won't need it.
*/
-#include "wiredtiger_config.h"
+#include <wiredtiger_config.h>
+
+#include <wiredtiger.h>
+#include <wiredtiger_ext.h>
+
#ifdef _MSC_VER
-#define inline __inline
+#define inline __inline
#endif
/* Local compressor structure. */
@@ -234,121 +236,163 @@ zlib_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
{
ZLIB_COMPRESSOR *zlib_compressor;
ZLIB_OPAQUE opaque;
- z_stream *best_zs, last_zs, zs;
- uint32_t curr_slot, last_slot;
- int ret;
+ z_stream *best_zs, *last_zs, _last_zs, *zs, _zs;
+ uint32_t curr_slot, last_slot, zlib_reserved;
+ bool increase_reserve;
+ int ret, tret;
- curr_slot = last_slot = 0;
- (void)split_pct;
- (void)dst_len;
+ (void)split_pct; /* Unused parameters */
(void)final;
zlib_compressor = (ZLIB_COMPRESSOR *)compressor;
- memset(&zs, 0, sizeof(zs));
- zs.zalloc = zalloc;
- zs.zfree = zfree;
- opaque.compressor = compressor;
- opaque.session = session;
- zs.opaque = &opaque;
-
- if ((ret = deflateInit(&zs, zlib_compressor->zlib_level)) != Z_OK)
- return (zlib_error(compressor, session, "deflateInit", ret));
-
- zs.next_in = src;
- zs.next_out = dst;
/*
* Experimentally derived, reserve this many bytes for zlib to finish
* up a buffer. If this isn't sufficient, we don't fail but we will be
* inefficient.
*/
#define WT_ZLIB_RESERVED 24
- zs.avail_out = (uint32_t)(page_max - (extra + WT_ZLIB_RESERVED));
+#define WT_ZLIB_RESERVED_MAX 48
+ zlib_reserved = WT_ZLIB_RESERVED;
+
+ if (0) {
+retry: /* If we reached our maximum reserve, quit. */
+ if (zlib_reserved == WT_ZLIB_RESERVED_MAX)
+ return (0);
+ zlib_reserved = WT_ZLIB_RESERVED_MAX;
+ }
+
+ best_zs = last_zs = NULL;
+ last_slot = 0;
+ increase_reserve = false;
+ ret = 0;
- /* Save the stream state in case the chosen data doesn't fit. */
- if ((ret = deflateCopy(&last_zs, &zs)) != Z_OK)
- return (zlib_error(compressor, session, "deflateCopy", ret));
+ zs = &_zs;
+ memset(zs, 0, sizeof(*zs));
+ zs->zalloc = zalloc;
+ zs->zfree = zfree;
+ opaque.compressor = compressor;
+ opaque.session = session;
+ zs->opaque = &opaque;
+
+ if ((ret = deflateInit(zs, zlib_compressor->zlib_level)) != Z_OK)
+ return (zlib_error(compressor, session, "deflateInit", ret));
+
+ zs->next_in = src;
+ zs->next_out = dst;
+
+ /*
+ * Set the target size. The target size is complicated: we don't want
+ * to exceed the smaller of the maximum page size or the destination
+ * buffer length, and in both cases we have to take into account the
+ * space required by zlib to finish up the buffer and the extra bytes
+ * required by our caller.
+ */
+ zs->avail_out = (uint32_t)(page_max < dst_len ? page_max : dst_len);
+ zs->avail_out -= (uint32_t)(zlib_reserved + extra);
/*
* Strategy: take the available output size and compress that much
* input. Continue until there is no input small enough or the
* compression fails to fit.
*/
- for (best_zs = NULL;;) {
+ for (;;) {
/* Find the next slot we will try to compress up to. */
- if ((curr_slot = zlib_find_slot(
- zs.total_in + zs.avail_out, offsets, slots)) > last_slot) {
- zs.avail_in = offsets[curr_slot] - offsets[last_slot];
- while (zs.avail_in > 0 && zs.avail_out > 0)
- if ((ret = deflate(&zs, Z_SYNC_FLUSH)) != Z_OK)
- return (zlib_error(compressor,
- session, "deflate", ret));
+ curr_slot = zlib_find_slot(
+ zs->total_in + zs->avail_out, offsets, slots);
+ if (curr_slot > last_slot) {
+ zs->avail_in = offsets[curr_slot] - offsets[last_slot];
+ while (zs->avail_in > 0 && zs->avail_out > 0)
+ if ((ret = deflate(zs, Z_SYNC_FLUSH)) != Z_OK) {
+ ret = zlib_error(compressor,
+ session, "deflate", ret);
+ goto err;
+ }
}
/*
* We didn't do a deflate, or it didn't work: use the last saved
- * position.
+ * position (if any).
*/
- if (curr_slot <= last_slot || zs.avail_in > 0) {
- if ((ret = deflateEnd(&zs)) != Z_OK &&
- ret != Z_DATA_ERROR)
- return (zlib_error(
- compressor, session, "deflateEnd", ret));
-
- best_zs = &last_zs;
+ if (curr_slot <= last_slot || zs->avail_in > 0) {
+ best_zs = last_zs;
break;
}
- /* The last deflation succeeded, discard the saved one. */
- if ((ret = deflateEnd(&last_zs)) != Z_OK && ret != Z_DATA_ERROR)
- return (zlib_error(
- compressor, session, "deflateEnd", ret));
-
/*
* If there's more compression to do, save a snapshot and keep
* going, otherwise, use the current compression.
*/
last_slot = curr_slot;
- if (zs.avail_out > 0) {
- if ((ret = deflateCopy(&last_zs, &zs)) != Z_OK)
- return (zlib_error(
- compressor, session, "deflateCopy", ret));
+ if (zs->avail_out > 0) {
+ /* Discard any previously saved snapshot. */
+ if (last_zs != NULL) {
+ ret = deflateEnd(last_zs);
+ last_zs = NULL;
+ if (ret != Z_OK && ret != Z_DATA_ERROR) {
+ ret = zlib_error(compressor,
+ session, "deflateEnd", ret);
+ goto err;
+ }
+ }
+ last_zs = &_last_zs;
+ if ((ret = deflateCopy(last_zs, zs)) != Z_OK) {
+ last_zs = NULL;
+ ret = zlib_error(
+ compressor, session, "deflateCopy", ret);
+ goto err;
+ }
continue;
}
- best_zs = &zs;
+ best_zs = zs;
break;
}
- best_zs->avail_out += WT_ZLIB_RESERVED;
- ret = deflate(best_zs, Z_FINISH);
+ if (last_slot > 0 && best_zs != NULL) {
+ /* Add the reserved bytes and try to finish the compression. */
+ best_zs->avail_out += zlib_reserved;
+ ret = deflate(best_zs, Z_FINISH);
- /*
- * If the end marker didn't fit, report that we got no work done,
- * WiredTiger will compress the (possibly large) page image using
- * ordinary compression instead.
- */
- if (ret == Z_OK || ret == Z_BUF_ERROR)
- last_slot = 0;
- else if (ret != Z_STREAM_END)
- return (
- zlib_error(compressor, session, "deflate end block", ret));
+ /*
+ * If the end marker didn't fit with the default value, try
+ * again with a maximum value; if that doesn't work, report we
+ * got no work done, WiredTiger will compress the (possibly
+ * large) page image using ordinary compression instead.
+ */
+ if (ret == Z_OK || ret == Z_BUF_ERROR) {
+ last_slot = 0;
+ increase_reserve = true;
+ } else if (ret != Z_STREAM_END) {
+ ret = zlib_error(
+ compressor, session, "deflate end block", ret);
+ goto err;
+ }
+ ret = 0;
+ }
- if ((ret = deflateEnd(best_zs)) != Z_OK && ret != Z_DATA_ERROR)
- return (zlib_error(compressor, session, "deflateEnd", ret));
+err: if (zs != NULL &&
+ (tret = deflateEnd(zs)) != Z_OK && tret != Z_DATA_ERROR)
+ ret = zlib_error(compressor, session, "deflateEnd", tret);
+ if (last_zs != NULL &&
+ (tret = deflateEnd(last_zs)) != Z_OK && tret != Z_DATA_ERROR)
+ ret = zlib_error(compressor, session, "deflateEnd", tret);
- if (last_slot > 0) {
+ if (ret == 0 && last_slot > 0) {
*result_slotsp = last_slot;
*result_lenp = (size_t)best_zs->total_out;
} else {
- /* We didn't manage to compress anything: don't retry. */
+ /* We didn't manage to compress anything. */
*result_slotsp = 0;
*result_lenp = 1;
+
+ if (increase_reserve)
+ goto retry;
}
#if 0
/* Decompress the result and confirm it matches the original source. */
- if (last_slot > 0) {
+ if (ret == 0 && last_slot > 0) {
void *decomp;
size_t result_len;
@@ -363,19 +407,20 @@ zlib_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
"deflate compare with original source",
Z_DATA_ERROR);
zfree(&opaque, decomp);
- if (ret != 0)
- return (ret);
}
#endif
#if 0
- fprintf(stderr,
- "zlib_compress_raw (%s): page_max %" PRIuMAX ", slots %" PRIu32
- ", take %" PRIu32 ": %" PRIu32 " -> %" PRIuMAX "\n",
- final ? "final" : "not final", (uintmax_t)page_max,
- slots, last_slot, offsets[last_slot], (uintmax_t)*result_lenp);
+ if (ret == 0 && last_slot > 0)
+ fprintf(stderr,
+ "zlib_compress_raw (%s): page_max %" PRIuMAX ", slots %"
+ PRIu32 ", take %" PRIu32 ": %" PRIu32 " -> %" PRIuMAX "\n",
+ final ? "final" : "not final", (uintmax_t)page_max,
+ slots, last_slot, offsets[last_slot],
+ (uintmax_t)*result_lenp);
#endif
- return (0);
+
+ return (ret);
}
/*
@@ -396,7 +441,8 @@ zlib_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
* Add a zlib compressor.
*/
static int
-zlib_add_compressor(WT_CONNECTION *connection, int raw, const char *name)
+zlib_add_compressor(
+ WT_CONNECTION *connection, bool raw, const char *name, int zlib_level)
{
ZLIB_COMPRESSOR *zlib_compressor;
@@ -415,17 +461,80 @@ zlib_add_compressor(WT_CONNECTION *connection, int raw, const char *name)
zlib_compressor->compressor.terminate = zlib_terminate;
zlib_compressor->wt_api = connection->get_extension_api(connection);
-
- /*
- * Between 0-10: level: see zlib manual.
- */
- zlib_compressor->zlib_level = Z_DEFAULT_COMPRESSION;
+ zlib_compressor->zlib_level = zlib_level;
/* Load the compressor. */
return (connection->add_compressor(
connection, name, (WT_COMPRESSOR *)zlib_compressor, NULL));
}
+/*
+ * zlib_init_config --
+ * Handle zlib configuration.
+ */
+static int
+zlib_init_config(
+ WT_CONNECTION *connection, WT_CONFIG_ARG *config, int *zlib_levelp)
+{
+ WT_CONFIG_ITEM k, v;
+ WT_CONFIG_PARSER *config_parser;
+ WT_EXTENSION_API *wtext;
+ int ret, zlib_level;
+
+ /* If configured as a built-in, there's no configuration argument. */
+ if (config == NULL)
+ return (0);
+
+ /*
+ * Zlib compression engine allows applications to specify a compression
+ * level; review the configuration.
+ */
+ wtext = connection->get_extension_api(connection);
+ if ((ret = wtext->config_get(wtext, NULL, config, "config", &v)) != 0) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_EXTENSION_API.config_get: zlib configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ if ((ret = wtext->config_parser_open(
+ wtext, NULL, v.str, v.len, &config_parser)) != 0) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_EXTENSION_API.config_parser_open: zlib configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ while ((ret = config_parser->next(config_parser, &k, &v)) == 0)
+ if (strlen("compression_level") == k.len &&
+ strncmp("compression_level", k.str, k.len) == 0) {
+ /*
+ * Between 0-9: level: see zlib manual.
+ */
+ zlib_level = (int)v.val;
+ if (zlib_level < 0 || zlib_level > 9) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_CONFIG_PARSER.next: zlib configure: "
+ "unsupported compression level %d",
+ zlib_level);
+ return (EINVAL);
+ }
+ *zlib_levelp = zlib_level;
+ continue;
+ }
+ if (ret != WT_NOTFOUND) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_CONFIG_PARSER.next: zlib configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ if ((ret = config_parser->close(config_parser)) != 0) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_CONFIG_PARSER.close: zlib configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ return (0);
+}
+
int zlib_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
/*
@@ -437,13 +546,17 @@ int zlib_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
int
zlib_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
{
- int ret;
+ int ret, zlib_level;
- (void)config; /* Unused parameters */
+ zlib_level = Z_DEFAULT_COMPRESSION; /* Default */
+ if ((ret = zlib_init_config(connection, config, &zlib_level)) != 0)
+ return (ret);
- if ((ret = zlib_add_compressor(connection, 1, "zlib")) != 0)
+ if ((ret = zlib_add_compressor(
+ connection, true, "zlib", zlib_level)) != 0)
return (ret);
- if ((ret = zlib_add_compressor(connection, 0, "zlib-noraw")) != 0)
+ if ((ret = zlib_add_compressor(
+ connection, false, "zlib-noraw", zlib_level)) != 0)
return (ret);
return (0);
}
diff --git a/ext/compressors/zstd/Makefile.am b/ext/compressors/zstd/Makefile.am
new file mode 100644
index 00000000000..9f0997011e9
--- /dev/null
+++ b/ext/compressors/zstd/Makefile.am
@@ -0,0 +1,11 @@
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)/src/include
+
+if HAVE_BUILTIN_EXTENSION_ZSTD
+noinst_LTLIBRARIES = libwiredtiger_zstd.la
+else
+lib_LTLIBRARIES = libwiredtiger_zstd.la
+libwiredtiger_zstd_la_LDFLAGS = -avoid-version -module
+endif
+
+libwiredtiger_zstd_la_SOURCES = zstd_compress.c
+libwiredtiger_zstd_la_LIBADD = -lzstd
diff --git a/ext/compressors/zstd/zstd_compress.c b/ext/compressors/zstd/zstd_compress.c
new file mode 100644
index 00000000000..3d0447248b6
--- /dev/null
+++ b/ext/compressors/zstd/zstd_compress.c
@@ -0,0 +1,358 @@
+/*-
+ * Public Domain 2014-2016 MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <zstd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * We need to include the configuration file to detect whether this extension
+ * is being built into the WiredTiger library; application-loaded compression
+ * functions won't need it.
+ */
+#include <wiredtiger_config.h>
+
+#include <wiredtiger.h>
+#include <wiredtiger_ext.h>
+
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
+/* Local compressor structure. */
+typedef struct {
+ WT_COMPRESSOR compressor; /* Must come first */
+
+ WT_EXTENSION_API *wt_api; /* Extension API */
+
+ int compression_level; /* compression level */
+} ZSTD_COMPRESSOR;
+
+/*
+ * Zstd decompression requires an exact compressed byte count. WiredTiger
+ * doesn't track that value, store it in the destination buffer.
+ */
+#define ZSTD_PREFIX sizeof(uint64_t)
+
+#ifdef WORDS_BIGENDIAN
+/*
+ * zstd_bswap64 --
+ * 64-bit unsigned little-endian to/from big-endian value.
+ */
+static inline uint64_t
+zstd_bswap64(uint64_t v)
+{
+ return (
+ ((v << 56) & 0xff00000000000000UL) |
+ ((v << 40) & 0x00ff000000000000UL) |
+ ((v << 24) & 0x0000ff0000000000UL) |
+ ((v << 8) & 0x000000ff00000000UL) |
+ ((v >> 8) & 0x00000000ff000000UL) |
+ ((v >> 24) & 0x0000000000ff0000UL) |
+ ((v >> 40) & 0x000000000000ff00UL) |
+ ((v >> 56) & 0x00000000000000ffUL)
+ );
+}
+#endif
+
+/*
+ * zstd_error --
+ * Output an error message, and return a standard error code.
+ */
+static int
+zstd_error(WT_COMPRESSOR *compressor,
+ WT_SESSION *session, const char *call, size_t error)
+{
+ WT_EXTENSION_API *wt_api;
+
+ wt_api = ((ZSTD_COMPRESSOR *)compressor)->wt_api;
+
+ (void)wt_api->err_printf(wt_api, session,
+ "zstd error: %s: %s", call, ZSTD_getErrorName(error));
+ return (WT_ERROR);
+}
+
+/*
+ * zstd_compress --
+ * WiredTiger Zstd compression.
+ */
+static int
+zstd_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t dst_len,
+ size_t *result_lenp, int *compression_failed)
+{
+ ZSTD_COMPRESSOR *zcompressor;
+ size_t zstd_ret;
+ uint64_t zstd_len;
+
+ zcompressor = (ZSTD_COMPRESSOR *)compressor;
+
+ /* Compress, starting past the prefix bytes. */
+ zstd_ret = ZSTD_compress(
+ dst + ZSTD_PREFIX, dst_len - ZSTD_PREFIX,
+ src, src_len, zcompressor->compression_level);
+
+ /*
+ * If compression succeeded and the compressed length is smaller than
+ * the original size, return success.
+ */
+ if (!ZSTD_isError(zstd_ret) && zstd_ret + ZSTD_PREFIX < src_len) {
+ *result_lenp = zstd_ret + ZSTD_PREFIX;
+ *compression_failed = 0;
+
+ /*
+ * On decompression, Zstd requires an exact compressed byte
+ * count (the current value of zstd_ret). WiredTiger does not
+ * preserve that value, so save zstd_ret at the beginning of
+ * the destination buffer.
+ *
+ * Store the value in little-endian format.
+ */
+ zstd_len = zstd_ret;
+#ifdef WORDS_BIGENDIAN
+ zstd_len = zstd_bswap64(zstd_len);
+#endif
+ *(uint64_t *)dst = zstd_len;
+ return (0);
+ }
+
+ *compression_failed = 1;
+ return (ZSTD_isError(zstd_ret) ?
+ zstd_error(compressor, session, "ZSTD_compress", zstd_ret) : 0);
+}
+
+/*
+ * zstd_decompress --
+ * WiredTiger Zstd decompression.
+ */
+static int
+zstd_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ uint8_t *dst, size_t dst_len,
+ size_t *result_lenp)
+{
+ WT_EXTENSION_API *wt_api;
+ size_t zstd_ret;
+ uint64_t zstd_len;
+
+ wt_api = ((ZSTD_COMPRESSOR *)compressor)->wt_api;
+
+ /*
+ * Retrieve the saved length, handling little- to big-endian conversion
+ * as necessary.
+ */
+ zstd_len = *(uint64_t *)src;
+#ifdef WORDS_BIGENDIAN
+ zstd_len = zstd_bswap64(zstd_len);
+#endif
+ if (zstd_len + ZSTD_PREFIX > src_len) {
+ (void)wt_api->err_printf(wt_api,
+ session,
+ "WT_COMPRESSOR.decompress: stored size exceeds source "
+ "size");
+ return (WT_ERROR);
+ }
+
+ zstd_ret =
+ ZSTD_decompress(dst, dst_len, src + ZSTD_PREFIX, (size_t)zstd_len);
+
+ if (!ZSTD_isError(zstd_ret)) {
+ *result_lenp = zstd_ret;
+ return (0);
+ }
+ return (zstd_error(compressor, session, "ZSTD_decompress", zstd_ret));
+}
+
+/*
+ * zstd_pre_size --
+ * WiredTiger Zstd destination buffer sizing for compression.
+ */
+static int
+zstd_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
+ uint8_t *src, size_t src_len, size_t *result_lenp)
+{
+ (void)compressor; /* Unused parameters */
+ (void)session;
+ (void)src;
+
+ /*
+ * Zstd compression runs faster if the destination buffer is sized at
+ * the upper-bound of the buffer size needed by the compression. Use
+ * the library calculation of that overhead (plus our overhead).
+ */
+ *result_lenp = ZSTD_compressBound(src_len) + ZSTD_PREFIX;
+ return (0);
+}
+
+/*
+ * zstd_terminate --
+ * WiredTiger Zstd compression termination.
+ */
+static int
+zstd_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
+{
+ (void)session; /* Unused parameters */
+
+ free(compressor);
+ return (0);
+}
+
+/*
+ * zstd_init_config --
+ * Handle zstd configuration.
+ */
+static int
+zstd_init_config(
+ WT_CONNECTION *connection, WT_CONFIG_ARG *config, int *compression_levelp)
+{
+ WT_CONFIG_ITEM k, v;
+ WT_CONFIG_PARSER *config_parser;
+ WT_EXTENSION_API *wtext;
+ int ret;
+
+ /* If configured as a built-in, there's no configuration argument. */
+ if (config == NULL)
+ return (0);
+
+ /*
+ * Zstd compression engine allows applications to specify a compression
+ * level; review the configuration.
+ */
+ wtext = connection->get_extension_api(connection);
+ if ((ret = wtext->config_get(wtext, NULL, config, "config", &v)) != 0) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_EXTENSION_API.config_get: zstd configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ if ((ret = wtext->config_parser_open(
+ wtext, NULL, v.str, v.len, &config_parser)) != 0) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_EXTENSION_API.config_parser_open: zstd configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ while ((ret = config_parser->next(config_parser, &k, &v)) == 0)
+ if (strlen("compression_level") == k.len &&
+ strncmp("compression_level", k.str, k.len) == 0) {
+ *compression_levelp = (int)v.val;
+ continue;
+ }
+ if (ret != WT_NOTFOUND) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_CONFIG_PARSER.next: zstd configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ if ((ret = config_parser->close(config_parser)) != 0) {
+ (void)wtext->err_printf(wtext, NULL,
+ "WT_CONFIG_PARSER.close: zstd configure: %s",
+ wtext->strerror(wtext, NULL, ret));
+ return (ret);
+ }
+ return (0);
+}
+
+int zstd_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
+
+/*
+ * zstd_extension_init --
+ * WiredTiger Zstd compression extension - called directly when Zstd
+ * support is built in, or via wiredtiger_extension_init when Zstd support
+ * is included via extension loading.
+ */
+int
+zstd_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
+{
+ ZSTD_COMPRESSOR *zstd_compressor;
+ int compression_level, ret;
+
+ /*
+ * Zstd's sweet-spot is better compression than zlib at significantly
+ * faster compression/decompression speeds. LZ4 and snappy are faster
+ * than zstd, but have worse compression ratios. Applications wanting
+ * faster compression/decompression with worse compression will select
+ * LZ4 or snappy, so we configure zstd for better compression.
+ *
+ * From the zstd github site, default measurements of the compression
+ * engines we support, listing compression ratios with compression and
+ * decompression speeds:
+ *
+ * Name Ratio C.speed D.speed
+ * MB/s MB/s
+ * zstd 2.877 330 940
+ * zlib 2.730 95 360
+ * LZ4 2.101 620 3100
+ * snappy 2.091 480 1600
+ *
+ * Set the zstd compression level to 3: according to the zstd web site,
+ * that reduces zstd's compression speed to around 200 MB/s, increasing
+ * the compression ratio to 3.100 (close to zlib's best compression
+ * ratio). In other words, position zstd as a zlib replacement, having
+ * similar compression at much higher compression/decompression speeds.
+ */
+ compression_level = 3;
+ if ((ret =
+ zstd_init_config(connection, config, &compression_level)) != 0)
+ return (ret);
+
+ if ((zstd_compressor = calloc(1, sizeof(ZSTD_COMPRESSOR))) == NULL)
+ return (errno);
+
+ zstd_compressor->compressor.compress = zstd_compress;
+ zstd_compressor->compressor.compress_raw = NULL;
+ zstd_compressor->compressor.decompress = zstd_decompress;
+ zstd_compressor->compressor.pre_size = zstd_pre_size;
+ zstd_compressor->compressor.terminate = zstd_terminate;
+
+ zstd_compressor->wt_api = connection->get_extension_api(connection);
+
+ zstd_compressor->compression_level = compression_level;
+
+ /* Load the compressor */
+ return (connection->add_compressor(
+ connection, "zstd", (WT_COMPRESSOR *)zstd_compressor, NULL));
+}
+
+/*
+ * We have to remove this symbol when building as a builtin extension otherwise
+ * it will conflict with other builtin libraries.
+ */
+#ifndef HAVE_BUILTIN_EXTENSION_ZSTD
+/*
+ * wiredtiger_extension_init --
+ * WiredTiger Zstd compression extension.
+ */
+int
+wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
+{
+ return (zstd_extension_init(connection, config));
+}
+#endif
diff --git a/src/conn/conn_api.c b/src/conn/conn_api.c
index 8a87aa9c7da..04c29e957a3 100644
--- a/src/conn/conn_api.c
+++ b/src/conn/conn_api.c
@@ -789,14 +789,17 @@ __conn_get_extension_api(WT_CONNECTION *wt_conn)
return (&conn->extension_api);
}
+#ifdef HAVE_BUILTIN_EXTENSION_LZ4
+ extern int lz4_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
+#endif
#ifdef HAVE_BUILTIN_EXTENSION_SNAPPY
extern int snappy_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
#endif
#ifdef HAVE_BUILTIN_EXTENSION_ZLIB
extern int zlib_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
#endif
-#ifdef HAVE_BUILTIN_EXTENSION_LZ4
- extern int lz4_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
+#ifdef HAVE_BUILTIN_EXTENSION_ZSTD
+ extern int zstd_extension_init(WT_CONNECTION *, WT_CONFIG_ARG *);
#endif
/*
@@ -808,14 +811,17 @@ __conn_load_default_extensions(WT_CONNECTION_IMPL *conn)
{
WT_UNUSED(conn);
+#ifdef HAVE_BUILTIN_EXTENSION_LZ4
+ WT_RET(lz4_extension_init(&conn->iface, NULL));
+#endif
#ifdef HAVE_BUILTIN_EXTENSION_SNAPPY
WT_RET(snappy_extension_init(&conn->iface, NULL));
#endif
#ifdef HAVE_BUILTIN_EXTENSION_ZLIB
WT_RET(zlib_extension_init(&conn->iface, NULL));
#endif
-#ifdef HAVE_BUILTIN_EXTENSION_LZ4
- WT_RET(lz4_extension_init(&conn->iface, NULL));
+#ifdef HAVE_BUILTIN_EXTENSION_ZSTD
+ WT_RET(zstd_extension_init(&conn->iface, NULL));
#endif
return (0);
}
diff --git a/src/docs/build-posix.dox b/src/docs/build-posix.dox
index 4889bf931c9..3e7f8f37acd 100644
--- a/src/docs/build-posix.dox
+++ b/src/docs/build-posix.dox
@@ -150,10 +150,14 @@ Configure WiredTiger to support the \c verbose configuration string to
Configure WiredTiger for <a href="http://www.zlib.net/">zlib</a>
compression; see @ref compression for more information.
+@par \c --enable-zstd
+Configure WiredTiger for <a href="https://github.com/facebook/zstd">Zstd</a>
+compression; see @ref compression for more information.
+
@par <code>--with-builtins</code>
Configure WiredTiger to include support for extensions in the main library.
This avoids requiring additional libraries for supported extensions. Currently
-supported options are \c lz4, \c snappy and \c zlib.
+supported options are \c lz4, \c snappy, \c zlib and \c zstd.
@par <code>--with-python-prefix</code>
Configure WiredTiger to install Python libraries to a non-standard Python
diff --git a/src/docs/compression.dox b/src/docs/compression.dox
index 0be96835760..74bed5c6f68 100644
--- a/src/docs/compression.dox
+++ b/src/docs/compression.dox
@@ -1,7 +1,7 @@
/*! @m_page{{c,java},compression,Compressors}
This section explains how to configure WiredTiger's builtin support for
-the lz4, snappy and zlib compression engines.
+the lz4, snappy, zlib and zstd compression engines.
@section compression_lz4 Using LZ4 compression
@@ -85,11 +85,53 @@ an extension. For example, with the WiredTiger library installed in
@snippet ex_all.c Configure zlib extension
+The default compression level for the zlib compression is
+\c Z_DEFAULT_COMPRESSION (see the zlib documentation for further
+information); compression can be configured to other levels using the
+additional configuration argument \c compression_level.
+
+@snippet ex_all.c Configure zlib extension with compression level
+
Finally, when creating the WiredTiger object, set \c block_compressor
to \c zlib:
@snippet ex_all.c Create a zlib compressed table
+@section compression_zstd Using Zstd compression
+
+To use the builtin support for Facebook's
+<a href="https://github.com/facebook/zstd">Zstd</a>
+compression, first check that Zstd is installed in include and library
+directories searched by the compiler. Once Zstd is installed, you can
+enable Zstd using the \c --enable-zstd option to configure.
+
+If Zstd is installed in a location not normally searched by the
+compiler toolchain, you'll need to modify the \c CPPFLAGS and \c LDFLAGS
+to indicate these locations. For example, with the Zstd includes and
+libraries installed in \c /usr/local/include and \c /usr/local/lib, you
+would run configure with the following additional arguments:
+
+@code
+--enable-zstd CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/include"
+@endcode
+
+When opening the WiredTiger database, load the Zstd shared library as
+an extension. For example, with the WiredTiger library installed in
+\c /usr/local/lib, you would use the following extension:
+
+@snippet ex_all.c Configure zstd extension
+
+The default compression level for the zstd compression is 3; compression
+can be configured to other levels using the additional configuration
+argument \c compression_level.
+
+@snippet ex_all.c Configure zstd extension with compression level
+
+Finally, when creating the WiredTiger object, set \c block_compressor
+to \c zstd:
+
+@snippet ex_all.c Create a zstd compressed table
+
@section compression_upgrading Upgrading compression engines
WiredTiger does not store information with file blocks to identify the
diff --git a/src/docs/spell.ok b/src/docs/spell.ok
index a2ef7658ec6..4b1337f84b8 100644
--- a/src/docs/spell.ok
+++ b/src/docs/spell.ok
@@ -95,6 +95,7 @@ WiredTigerStat
WiredTigerTestCase
Yann
Za
+Zstd
aR
abstime
ack'ed
@@ -507,3 +508,4 @@ xa
yieldcpu
zlib
zseries
+zstd
diff --git a/src/docs/wtperf.dox b/src/docs/wtperf.dox
index 085e1addf61..83aadf8a776 100644
--- a/src/docs/wtperf.dox
+++ b/src/docs/wtperf.dox
@@ -160,7 +160,7 @@ properly close connection at end of test. Setting to false does not sync data t
@par compact (boolean, default=false)
post-populate compact for LSM merging activity
@par compression (string, default="none")
-compression extension. Allowed configuration values are: 'none', 'lz4', 'snappy', 'zlib'
+compression extension. Allowed configuration values are: 'none', 'lz4', 'snappy', 'zlib', 'zstd'
@par create (boolean, default=true)
do population phase; false to use existing database
@par database_count (unsigned int, default=1)
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index 7bbdf85d954..b6185b4ead6 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -1005,9 +1005,9 @@ struct __wt_session {
* @config{block_compressor, configure a compressor for file blocks.
* Permitted values are \c "none" or custom compression engine name
* created with WT_CONNECTION::add_compressor. If WiredTiger has
- * builtin support for \c "snappy"\, \c "lz4" or \c "zlib" compression\,
- * these names are also available. See @ref compression for more
- * information., a string; default \c none.}
+ * builtin support for \c "lz4"\, \c "snappy"\, \c "zlib" or \c "zstd"
+ * compression\, these names are also available. See @ref compression
+ * for more information., a string; default \c none.}
* @config{cache_resident, do not ever evict the object's pages from
* cache. Not compatible with LSM tables; see @ref
* tuning_cache_resident for more information., a boolean flag; default
@@ -2338,11 +2338,11 @@ struct __wt_connection {
* @config{&nbsp;&nbsp;&nbsp;&nbsp;compressor, configure a compressor for log
* records. Permitted values are \c "none" or custom compression engine name
* created with WT_CONNECTION::add_compressor. If WiredTiger has builtin
- * support for \c "snappy"\, \c "lz4" or \c "zlib" compression\, these names are
- * also available. See @ref compression for more information., a string;
- * default \c none.}
- * @config{&nbsp;&nbsp;&nbsp;&nbsp;enabled, enable logging
- * subsystem., a boolean flag; default \c false.}
+ * support for \c "lz4"\, \c "snappy"\, \c "zlib" or \c "zstd" compression\,
+ * these names are also available. See @ref compression for more information.,
+ * a string; default \c none.}
+ * @config{&nbsp;&nbsp;&nbsp;&nbsp;enabled, enable
+ * logging subsystem., a boolean flag; default \c false.}
* @config{&nbsp;&nbsp;&nbsp;&nbsp;file_max, the maximum size of log files., an
* integer between 100KB and 2GB; default \c 100MB.}
* @config{&nbsp;&nbsp;&nbsp;&nbsp;path, the name of a directory into which log
diff --git a/test/format/config.c b/test/format/config.c
index 542adf33da2..95b05c3c833 100644
--- a/test/format/config.c
+++ b/test/format/config.c
@@ -270,28 +270,33 @@ config_compression(const char *conf_name)
*/
switch (mmrand(NULL, 1, 20)) {
#ifdef HAVE_BUILTIN_EXTENSION_LZ4
- case 1: case 2: case 3: case 4: /* 20% lz4 */
+ case 1: case 2: /* 10% lz4 */
cstr = "lz4";
break;
- case 5: /* 5% lz4-no-raw */
+ case 3: /* 5% lz4-no-raw */
cstr = "lz4-noraw";
break;
#endif
#ifdef HAVE_BUILTIN_EXTENSION_SNAPPY
- case 6: case 7: case 8: case 9: /* 30% snappy */
- case 10: case 11:
+ case 4: case 5: case 6: case 7: /* 30% snappy */
+ case 8: case 9:
cstr = "snappy";
break;
#endif
#ifdef HAVE_BUILTIN_EXTENSION_ZLIB
- case 12: case 13: case 14: case 15: /* 20% zlib */
+ case 10: case 11: case 12: case 13: /* 20% zlib */
cstr = "zlib";
break;
- case 16: /* 5% zlib-no-raw */
+ case 14: /* 5% zlib-no-raw */
cstr = "zlib-noraw";
break;
#endif
- case 17: case 18: case 19: case 20: /* 20% no compression */
+#ifdef HAVE_BUILTIN_EXTENSION_ZSTD
+ case 15: case 16 case 17: /* 15% zstd */
+ cstr = "zstd";
+ break;
+#endif
+ case 18: case 19: case 20: /* 15% no compression */
default:
break;
}
@@ -748,6 +753,8 @@ config_map_compression(const char *s, u_int *vp)
*vp = COMPRESS_ZLIB;
else if (strcmp(s, "zlib-noraw") == 0)
*vp = COMPRESS_ZLIB_NO_RAW;
+ else if (strcmp(s, "zstd") == 0)
+ *vp = COMPRESS_ZSTD;
else
testutil_die(EINVAL,
"illegal compression configuration: %s", s);
diff --git a/test/format/config.h b/test/format/config.h
index 725bc7c5d97..9bfba3cd0df 100644
--- a/test/format/config.h
+++ b/test/format/config.h
@@ -58,7 +58,7 @@ typedef struct {
} CONFIG;
#define COMPRESSION_LIST \
- "(none | lz4 | lz4-noraw | snappy | zlib | zlib-noraw)"
+ "(none | lz4 | lz4-noraw | snappy | zlib | zlib-noraw | zstd)"
static CONFIG c[] = {
{ "abort",
diff --git a/test/format/format.h b/test/format/format.h
index 363dcf9eea8..820bc020c9b 100644
--- a/test/format/format.h
+++ b/test/format/format.h
@@ -48,6 +48,8 @@
EXTPATH "compressors/snappy/.libs/libwiredtiger_snappy.so"
#define ZLIB_PATH \
EXTPATH "compressors/zlib/.libs/libwiredtiger_zlib.so"
+#define ZSTD_PATH \
+ EXTPATH "compressors/zstd/.libs/libwiredtiger_zstd.so"
#define REVERSE_PATH \
EXTPATH "collators/reverse/.libs/libwiredtiger_reverse_collator.so"
@@ -219,6 +221,7 @@ typedef struct {
#define COMPRESS_SNAPPY 5
#define COMPRESS_ZLIB 6
#define COMPRESS_ZLIB_NO_RAW 7
+#define COMPRESS_ZSTD 8
u_int c_compression_flag; /* Compression flag value */
u_int c_logging_compression_flag; /* Log compression flag value */
diff --git a/test/format/wts.c b/test/format/wts.c
index 1600786855a..23fdbce156c 100644
--- a/test/format/wts.c
+++ b/test/format/wts.c
@@ -50,6 +50,8 @@ compressor(uint32_t compress_flag)
return ("zlib");
case COMPRESS_ZLIB_NO_RAW:
return ("zlib-noraw");
+ case COMPRESS_ZSTD:
+ return ("zstd");
default:
break;
}
@@ -210,13 +212,14 @@ wts_open(const char *home, bool set_api, WT_CONNECTION **connp)
/* Extensions. */
p += snprintf(p, REMAIN(p, end),
",extensions=["
- "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"],",
+ "\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"],",
g.c_reverse ? REVERSE_PATH : "",
access(LZ4_PATH, R_OK) == 0 ? LZ4_PATH : "",
access(LZO_PATH, R_OK) == 0 ? LZO_PATH : "",
access(ROTN_PATH, R_OK) == 0 ? ROTN_PATH : "",
access(SNAPPY_PATH, R_OK) == 0 ? SNAPPY_PATH : "",
access(ZLIB_PATH, R_OK) == 0 ? ZLIB_PATH : "",
+ access(ZSTD_PATH, R_OK) == 0 ? ZSTD_PATH : "",
DATASOURCE("kvsbdb") ? KVS_BDB_PATH : "");
/*
diff --git a/test/suite/test_encrypt01.py b/test/suite/test_encrypt01.py
index d314cbeadfd..746c9d13e96 100644
--- a/test/suite/test_encrypt01.py
+++ b/test/suite/test_encrypt01.py
@@ -57,6 +57,7 @@ class test_encrypt01(wttest.WiredTigerTestCase):
('lz4', dict(log_compress='lz4', block_compress='lz4')),
('snappy', dict(log_compress='snappy', block_compress='snappy')),
('zlib', dict(log_compress='zlib', block_compress='zlib')),
+ ('zstd', dict(log_compress='zstd', block_compress='zstd')),
('none-snappy', dict(log_compress=None, block_compress='snappy')),
('snappy-lz4', dict(log_compress='snappy', block_compress='lz4')),
]