summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2013-05-30 16:12:03 -0700
committerAlex Gorrod <alexg@wiredtiger.com>2013-05-30 16:12:03 -0700
commit0c0e1fea6bf8ed00c829aa6e6c5ddb4eb17125ce (patch)
treec302b4f66df2b61c9b8fd7e3254ec01e8ec2d1dc
parente8f6358f9ab66b74a7e7643e4104c927291bbcd8 (diff)
parentb6a0a9bddca7cc6b614778785d6de7d7f18cd1e3 (diff)
downloadmongo-0c0e1fea6bf8ed00c829aa6e6c5ddb4eb17125ce.tar.gz
Merge pull request #556 from wiredtiger/hot-backup
Fix several bugs in hot backup, including race conditions between backup and table drop (and other schema level operations). @closes #557
-rw-r--r--examples/c/ex_all.c112
-rw-r--r--ext/compressors/bzip2/bzip2_compress.c154
-rw-r--r--ext/compressors/nop/nop_compress.c100
-rw-r--r--ext/compressors/snappy/snappy_compress.c59
-rw-r--r--src/btree/bt_handle.c16
-rw-r--r--src/cursor/cur_backup.c318
-rw-r--r--src/docs/upgrading.dox8
-rw-r--r--src/include/btree.h2
-rw-r--r--src/include/cursor.h9
-rw-r--r--src/include/extern.h9
-rw-r--r--src/include/misc.h13
-rw-r--r--src/include/session.h1
-rw-r--r--src/include/wiredtiger.in14
-rw-r--r--src/include/wiredtiger_ext.h2
-rw-r--r--src/include/wt_internal.h2
-rw-r--r--src/lsm/lsm_tree.c9
-rw-r--r--src/lsm/lsm_worker.c8
-rw-r--r--src/schema/schema_worker.c50
-rw-r--r--src/session/session_api.c14
-rw-r--r--src/txn/txn_ckpt.c2
-rw-r--r--test/format/Makefile.am3
-rw-r--r--test/format/backup.c157
-rw-r--r--test/format/bulk.c (renamed from test/format/wts_bulk.c)12
-rw-r--r--test/format/format.h13
-rw-r--r--test/format/ops.c (renamed from test/format/wts_ops.c)75
-rw-r--r--test/format/t.c6
-rw-r--r--test/format/wts.c65
-rw-r--r--test/suite/helper.py33
-rw-r--r--test/suite/test_backup01.py (renamed from test/suite/test_backup.py)44
-rw-r--r--test/suite/test_backup03.py128
-rw-r--r--test/suite/test_checkpoint01.py13
31 files changed, 937 insertions, 514 deletions
diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c
index edf2437d167..7e5e1568eff 100644
--- a/examples/c/ex_all.c
+++ b/examples/c/ex_all.c
@@ -44,7 +44,6 @@
#include <wiredtiger.h>
int add_collator(WT_CONNECTION *conn);
-int add_compressor(WT_CONNECTION *conn);
int add_extractor(WT_CONNECTION *conn);
int checkpoint_ops(WT_SESSION *session);
int connection_ops(WT_CONNECTION *conn);
@@ -683,117 +682,6 @@ add_collator(WT_CONNECTION *conn)
return (ret);
}
-/*! [WT_COMPRESSOR compress] */
-/*
- * A simple compression example that passes data through unchanged.
- */
-static int
-my_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)
-{
- /* Unused parameters */
- (void)compressor;
- (void)session;
-
- *compression_failed = 0;
- if (dst_len < src_len) {
- *compression_failed = 1;
- return (0);
- }
- memcpy(dst, src, src_len);
- *result_lenp = src_len;
- return (0);
-}
-/*! [WT_COMPRESSOR compress] */
-
-/*! [WT_COMPRESSOR decompress] */
-/*
- * A simple decompression example that passes data through unchanged.
- */
-static int
-my_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)
-{
- /* Unused parameters */
- (void)compressor;
- (void)session;
-
- if (dst_len < src_len)
- return (ENOMEM);
-
- memcpy(dst, src, src_len);
- *result_lenp = src_len;
- return (0);
-}
-/*! [WT_COMPRESSOR decompress] */
-
-/*! [WT_COMPRESSOR presize] */
-/*
- * A simple pre-size example that returns the source length.
- */
-static int
-my_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
- uint8_t *src, size_t src_len,
- size_t *result_lenp)
-{
- /* Unused parameters */
- (void)compressor;
- (void)session;
- (void)src;
-
- *result_lenp = src_len;
- return (0);
-}
-/*! [WT_COMPRESSOR presize] */
-
-static int
-my_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
- size_t page_max, u_int split_pct, size_t extra,
- uint8_t *src, uint32_t *offsets, uint32_t slots,
- uint8_t *dst, size_t dst_len, int final,
- size_t *result_lenp, uint32_t *result_slotsp)
-{
- /* Unused parameters */
- (void)compressor;
- (void)session;
- (void)page_max;
- (void)split_pct;
- (void)extra;
- (void)src;
- (void)offsets;
- (void)slots;
- (void)dst;
- (void)dst_len;
- (void)final;
- (void)result_lenp;
- (void)result_slotsp;
-
- return (0);
-}
-
-int
-add_compressor(WT_CONNECTION *conn)
-{
- int ret;
-
- /*! [WT_COMPRESSOR register] */
- static WT_COMPRESSOR my_compressor = {
- my_compress,
- my_compress_raw, /* NULL, if no raw compression */
- my_decompress,
- my_pre_size, /* NULL, if pre-sizing not needed */
- NULL /* NULL, if no termination cleanup */
- };
- ret = conn->add_compressor(conn, "my_compress", &my_compressor, NULL);
- /*! [WT_COMPRESSOR register] */
-
- return (ret);
-}
-
/*! [WT_EXTRACTOR] */
static int
my_extract(WT_EXTRACTOR *extractor, WT_SESSION *session,
diff --git a/ext/compressors/bzip2/bzip2_compress.c b/ext/compressors/bzip2/bzip2_compress.c
index aa162009abe..c7001549638 100644
--- a/ext/compressors/bzip2/bzip2_compress.c
+++ b/ext/compressors/bzip2/bzip2_compress.c
@@ -26,6 +26,7 @@
*/
#include <bzlib.h>
+#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
@@ -33,68 +34,105 @@
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
-static WT_EXTENSION_API *wt_api;
-
static int
bzip2_compress(WT_COMPRESSOR *, WT_SESSION *,
uint8_t *, size_t, uint8_t *, size_t, size_t *, int *);
static int
bzip2_decompress(WT_COMPRESSOR *, WT_SESSION *,
uint8_t *, size_t, uint8_t *, size_t, size_t *);
+static int
+bzip2_terminate(WT_COMPRESSOR *, WT_SESSION *);
#ifdef WIREDTIGER_TEST_COMPRESS_RAW
static int
-bzip2_compress_raw(WT_COMPRESSOR *, WT_SESSION *, size_t, u_int,
+bzip2_compress_raw(WT_COMPRESSOR *, WT_SESSION *, size_t, int,
size_t, uint8_t *, uint32_t *, uint32_t, uint8_t *, size_t, int,
size_t *, uint32_t *);
#endif
-static WT_COMPRESSOR bzip2_compressor = {
- bzip2_compress, NULL, bzip2_decompress, NULL, NULL };
+/* Local compressor structure. */
+typedef struct {
+ WT_COMPRESSOR compressor; /* Must come first */
-/* between 0-4: set the amount of verbosity to stderr */
-static int bz_verbosity = 0;
+ WT_EXTENSION_API *wt_api; /* Extension API */
-/* between 1-9: set the block size to 100k x this number (compression only) */
-static int bz_blocksize100k = 1;
+ int bz_verbosity; /* Configuration */
+ int bz_blocksize100k;
+ int bz_workfactor;
+ int bz_small;
+} BZIP_COMPRESSOR;
/*
- * between 0-250: workFactor: see bzip2 manual. 0 is a reasonable default
- * (compression only)
+ * Bzip gives us a cookie to pass to the underlying allocation functions; we
+ * we need two handles, package them up.
*/
-static int bz_workfactor = 0;
-
-/* if nonzero, decompress using less memory, but slower (decompression only) */
-static int bz_small = 0;
+typedef struct {
+ WT_COMPRESSOR *compressor;
+ WT_SESSION *session;
+} BZIP_OPAQUE;
int
wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
{
+ BZIP_COMPRESSOR *bzip_compressor;
+
(void)config; /* Unused parameters */
- /* Find the extension API */
- wt_api = connection->get_extension_api(connection);
+ if ((bzip_compressor = calloc(1, sizeof(BZIP_COMPRESSOR))) == NULL)
+ return (errno);
+
+ bzip_compressor->compressor.compress = bzip2_compress;
+ bzip_compressor->compressor.compress_raw = NULL;
+ bzip_compressor->compressor.decompress = bzip2_decompress;
+ bzip_compressor->compressor.pre_size = NULL;
+ bzip_compressor->compressor.terminate = bzip2_terminate;
+
+ bzip_compressor->wt_api = connection->get_extension_api(connection);
+
+ /* between 0-4: set the amount of verbosity to stderr */
+ bzip_compressor->bz_verbosity = 0;
+
+ /*
+ * between 1-9: set the block size to 100k x this number (compression
+ * only)
+ */
+ bzip_compressor->bz_blocksize100k = 1;
+
+ /*
+ * between 0-250: workFactor: see bzip2 manual. 0 is a reasonable
+ * default (compression only)
+ */
+ bzip_compressor->bz_workfactor = 0;
+
+ /*
+ * if nonzero, decompress using less memory, but slower (decompression
+ * only)
+ */
+ bzip_compressor->bz_small = 0;
/* Load the compressor */
#ifdef WIREDTIGER_TEST_COMPRESS_RAW
- bzip2_compressor.compress_raw = bzip2_compress_raw;
+ bzip_compressor->compressor.compress_raw = bzip2_compress_raw;
return (connection->add_compressor(
- connection, "raw", &bzip2_compressor, NULL));
+ connection, "raw", (WT_COMPRESSOR *)bzip_compressor, NULL));
#else
return (connection->add_compressor(
- connection, "bzip2", &bzip2_compressor, NULL));
+ connection, "bzip2", (WT_COMPRESSOR *)bzip_compressor, NULL));
#endif
}
-/* Bzip2 WT_COMPRESSOR implementation for WT_CONNECTION::add_compressor. */
/*
* bzip2_error --
* Output an error message, and return a standard error code.
*/
static int
-bzip2_error(WT_SESSION *session, const char *call, int bzret)
+bzip2_error(
+ WT_COMPRESSOR *compressor, WT_SESSION *session, const char *call, int bzret)
{
+ WT_EXTENSION_API *wt_api;
const char *msg;
+ wt_api = ((BZIP_COMPRESSOR *)compressor)->wt_api;
+
switch (bzret) {
case BZ_MEM_ERROR:
msg = "BZ_MEM_ERROR";
@@ -128,21 +166,32 @@ bzip2_error(WT_SESSION *session, const char *call, int bzret)
break;
}
- (void)wt_api->err_printf(wt_api,
- session, "bzip2 error: %s: %s: %d", call, msg, bzret);
+ (void)wt_api->err_printf(wt_api, session,
+ "bzip2 error: %s: %s: %d", call, msg, bzret);
return (WT_ERROR);
}
static void *
bzalloc(void *cookie, int number, int size)
{
- return (wt_api->scr_alloc(wt_api, cookie, (size_t)(number * size)));
+ BZIP_OPAQUE *opaque;
+ WT_EXTENSION_API *wt_api;
+
+ opaque = cookie;
+ wt_api = ((BZIP_COMPRESSOR *)opaque->compressor)->wt_api;
+ return (wt_api->scr_alloc(
+ wt_api, opaque->session, (size_t)(number * size)));
}
static void
bzfree(void *cookie, void *p)
{
- wt_api->scr_free(wt_api, cookie, p);
+ BZIP_OPAQUE *opaque;
+ WT_EXTENSION_API *wt_api;
+
+ opaque = cookie;
+ wt_api = ((BZIP_COMPRESSOR *)opaque->compressor)->wt_api;
+ wt_api->scr_free(wt_api, opaque->session, p);
}
static int
@@ -151,19 +200,26 @@ bzip2_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *dst, size_t dst_len,
size_t *result_lenp, int *compression_failed)
{
+ BZIP_COMPRESSOR *bzip_compressor;
+ BZIP_OPAQUE opaque;
bz_stream bz;
int ret;
- (void)compressor; /* Unused */
+ bzip_compressor = (BZIP_COMPRESSOR *)compressor;
memset(&bz, 0, sizeof(bz));
bz.bzalloc = bzalloc;
bz.bzfree = bzfree;
- bz.opaque = session;
+ opaque.compressor = compressor;
+ opaque.session = session;
+ bz.opaque = &opaque;
if ((ret = BZ2_bzCompressInit(&bz,
- bz_blocksize100k, bz_verbosity, bz_workfactor)) != BZ_OK)
- return (bzip2_error(session, "BZ2_bzCompressInit", ret));
+ bzip_compressor->bz_blocksize100k,
+ bzip_compressor->bz_verbosity,
+ bzip_compressor->bz_workfactor)) != BZ_OK)
+ return (bzip2_error(
+ compressor, session, "BZ2_bzCompressInit", ret));
bz.next_in = (char *)src;
bz.avail_in = (uint32_t)src_len;
@@ -176,7 +232,8 @@ bzip2_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
*compression_failed = 1;
if ((ret = BZ2_bzCompressEnd(&bz)) != BZ_OK)
- return (bzip2_error(session, "BZ2_bzCompressEnd", ret));
+ return (
+ bzip2_error(compressor, session, "BZ2_bzCompressEnd", ret));
return (0);
}
@@ -207,7 +264,7 @@ __bzip2_compress_raw_random(void)
*/
static int
bzip2_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
- size_t page_max, u_int split_pct, size_t extra,
+ size_t page_max, int split_pct, size_t extra,
uint8_t *src, uint32_t *offsets, uint32_t slots,
uint8_t *dst, size_t dst_len, int final,
size_t *result_lenp, uint32_t *result_slotsp)
@@ -215,7 +272,7 @@ bzip2_compress_raw(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint32_t take, twenty_pct;
int compression_failed, ret;
- (void)page_max; /* Unused */
+ (void)page_max; /* Unused parameters */
(void)split_pct;
(void)extra;
(void)final;
@@ -281,18 +338,24 @@ bzip2_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *dst, size_t dst_len,
size_t *result_lenp)
{
+ BZIP_COMPRESSOR *bzip_compressor;
+ BZIP_OPAQUE opaque;
bz_stream bz;
int ret, tret;
- (void)compressor; /* Unused */
+ bzip_compressor = (BZIP_COMPRESSOR *)compressor;
memset(&bz, 0, sizeof(bz));
bz.bzalloc = bzalloc;
bz.bzfree = bzfree;
- bz.opaque = session;
+ opaque.compressor = compressor;
+ opaque.session = session;
+ bz.opaque = &opaque;
- if ((ret = BZ2_bzDecompressInit(&bz, bz_small, bz_verbosity)) != BZ_OK)
- return (bzip2_error(session, "BZ2_bzDecompressInit", ret));
+ if ((ret = BZ2_bzDecompressInit(&bz,
+ bzip_compressor->bz_small, bzip_compressor->bz_verbosity)) != BZ_OK)
+ return (bzip2_error(
+ compressor, session, "BZ2_bzDecompressInit", ret));
bz.next_in = (char *)src;
bz.avail_in = (uint32_t)src_len;
@@ -302,12 +365,21 @@ bzip2_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
*result_lenp = dst_len - bz.avail_out;
ret = 0;
} else
- (void)bzip2_error(session, "BZ2_bzDecompress", ret);
+ (void)bzip2_error(compressor, session, "BZ2_bzDecompress", ret);
if ((tret = BZ2_bzDecompressEnd(&bz)) != BZ_OK)
- return (bzip2_error(session, "BZ2_bzDecompressEnd", tret));
+ return (bzip2_error(
+ compressor, session, "BZ2_bzDecompressEnd", tret));
return (ret == 0 ?
- 0 : bzip2_error(session, "BZ2_bzDecompressEnd", ret));
+ 0 : bzip2_error(compressor, session, "BZ2_bzDecompressEnd", ret));
+}
+
+static int
+bzip2_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
+{
+ (void)session; /* Unused parameters */
+
+ free(compressor);
+ return (0);
}
-/* End Bzip2 WT_COMPRESSOR implementation for WT_CONNECTION::add_compressor. */
diff --git a/ext/compressors/nop/nop_compress.c b/ext/compressors/nop/nop_compress.c
index 8a0765e2db8..c017d6a33c1 100644
--- a/ext/compressors/nop/nop_compress.c
+++ b/ext/compressors/nop/nop_compress.c
@@ -25,46 +25,82 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
+#include <errno.h>
+#include <stdlib.h>
#include <string.h>
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
-static WT_EXTENSION_API *wt_api;
-
static int
nop_compress(WT_COMPRESSOR *, WT_SESSION *,
uint8_t *, size_t, uint8_t *, size_t, size_t *, int *);
static int
nop_decompress(WT_COMPRESSOR *, WT_SESSION *,
uint8_t *, size_t, uint8_t *, size_t, size_t *);
+static int
+nop_pre_size(WT_COMPRESSOR *, WT_SESSION *, uint8_t *, size_t, size_t *);
+static int
+nop_terminate(WT_COMPRESSOR *, WT_SESSION *);
+
+/*! [WT_COMPRESSOR initialization] */
+/* Local compressor structure. */
+typedef struct {
+ WT_COMPRESSOR compressor; /* Must come first */
-static WT_COMPRESSOR nop_compressor = {
- nop_compress, NULL, nop_decompress, NULL, NULL };
+ WT_EXTENSION_API *wt_api; /* Extension API */
+} NOP_COMPRESSOR;
-/*! [WT_EXTENSION_API initialization] */
+/*
+ * A simple shared library compression example.
+ */
int
wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
{
+ NOP_COMPRESSOR *nop_compressor;
+
(void)config; /* Unused parameters */
- /* Find the extension API */
- wt_api = connection->get_extension_api(connection);
+ if ((nop_compressor = calloc(1, sizeof(NOP_COMPRESSOR))) == NULL)
+ return (errno);
+
+ /*
+ * Allocate a local compressor structure, with a WT_COMPRESSOR structure
+ * as the first field, allowing us to treat references to either type of
+ * structure as a reference to the other type.
+ *
+ * This could be simplified if only a single database is opened in the
+ * application, we could use a static WT_COMPRESSOR structure, and a
+ * static reference to the WT_EXTENSION_API methods, then we don't need
+ * to allocate memory when the compressor is initialized or free it when
+ * the compressor is terminated. However, this approach is more general
+ * purpose and supports multiple databases per application.
+ */
+ nop_compressor->compressor.compress = nop_compress;
+ nop_compressor->compressor.compress_raw = NULL;
+ nop_compressor->compressor.decompress = nop_decompress;
+ nop_compressor->compressor.pre_size = nop_pre_size;
+ nop_compressor->compressor.terminate = nop_terminate;
+
+ nop_compressor->wt_api = connection->get_extension_api(connection);
/* Load the compressor */
return (connection->add_compressor(
- connection, "nop", &nop_compressor, NULL));
+ connection, "nop", (WT_COMPRESSOR *)nop_compressor, NULL));
}
-/*! [WT_EXTENSION_API initialization] */
+/*! [WT_COMPRESSOR initialization] */
-/* Implementation of WT_COMPRESSOR for WT_CONNECTION::add_compressor. */
+/*! [WT_COMPRESSOR compress] */
+/*
+ * A simple compression example that passes data through unchanged.
+ */
static int
nop_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)
{
- (void)compressor; /* Unused */
+ (void)compressor; /* Unused parameters */
(void)session;
*compression_failed = 0;
@@ -78,14 +114,19 @@ nop_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
return (0);
}
+/*! [WT_COMPRESSOR compress] */
+/*! [WT_COMPRESSOR decompress] */
+/*
+ * A simple compression example that passes data through unchanged.
+ */
static int
nop_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)
{
- (void)compressor; /* Unused */
+ (void)compressor; /* Unused parameters */
(void)session;
(void)src_len;
@@ -97,4 +138,37 @@ nop_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
*result_lenp = dst_len;
return (0);
}
-/* End implementation of WT_COMPRESSOR. */
+/*! [WT_COMPRESSOR decompress] */
+
+/*! [WT_COMPRESSOR presize] */
+/*
+ * A simple pre-size example that returns the source length.
+ */
+static int
+nop_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
+ uint8_t *src, size_t src_len,
+ size_t *result_lenp)
+{
+ /* Unused parameters */
+ (void)compressor;
+ (void)session;
+ (void)src;
+
+ *result_lenp = src_len;
+ return (0);
+}
+/*! [WT_COMPRESSOR presize] */
+
+/*! [WT_COMPRESSOR terminate] */
+/*
+ * A simple termination example that frees the allocated memory.
+ */
+static int
+nop_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
+{
+ (void)session; /* Unused parameters */
+
+ free(compressor);
+ return (0);
+}
+/*! [WT_COMPRESSOR terminate] */
diff --git a/ext/compressors/snappy/snappy_compress.c b/ext/compressors/snappy/snappy_compress.c
index 0e8261b6226..efd6fe45bff 100644
--- a/ext/compressors/snappy/snappy_compress.c
+++ b/ext/compressors/snappy/snappy_compress.c
@@ -26,14 +26,13 @@
*/
#include <snappy-c.h>
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <wiredtiger.h>
#include <wiredtiger_ext.h>
-static WT_EXTENSION_API *wt_api;
-
static int
wt_snappy_compress(WT_COMPRESSOR *, WT_SESSION *,
uint8_t *, size_t, uint8_t *, size_t, size_t *, int *);
@@ -42,33 +41,51 @@ wt_snappy_decompress(WT_COMPRESSOR *, WT_SESSION *,
uint8_t *, size_t, uint8_t *, size_t, size_t *);
static int
wt_snappy_pre_size(WT_COMPRESSOR *, WT_SESSION *, uint8_t *, size_t, size_t *);
+static int
+wt_snappy_terminate(WT_COMPRESSOR *, WT_SESSION *);
-static WT_COMPRESSOR wt_snappy_compressor = {
- wt_snappy_compress, NULL, wt_snappy_decompress, wt_snappy_pre_size, NULL };
+/* Local compressor structure. */
+typedef struct {
+ WT_COMPRESSOR compressor; /* Must come first */
+
+ WT_EXTENSION_API *wt_api; /* Extension API */
+} SNAPPY_COMPRESSOR;
int
wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
{
+ SNAPPY_COMPRESSOR *snappy_compressor;
+
(void)config; /* Unused parameters */
- /* Find the extension API */
- wt_api = connection->get_extension_api(connection);
+ if ((snappy_compressor = calloc(1, sizeof(SNAPPY_COMPRESSOR))) == NULL)
+ return (errno);
+
+ snappy_compressor->compressor.compress = wt_snappy_compress;
+ 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->wt_api = connection->get_extension_api(connection);
- /* Load the compressor */
return (connection->add_compressor(
- connection, "snappy", &wt_snappy_compressor, NULL));
+ connection, "snappy", (WT_COMPRESSOR *)snappy_compressor, NULL));
}
-/* Snappy WT_COMPRESSOR for WT_CONNECTION::add_compressor. */
/*
* wt_snappy_error --
* Output an error message, and return a standard error code.
*/
static int
-wt_snappy_error(WT_SESSION *session, const char *call, snappy_status snret)
+wt_snappy_error(WT_COMPRESSOR *compressor,
+ WT_SESSION *session, const char *call, snappy_status snret)
{
+ WT_EXTENSION_API *wt_api;
const char *msg;
+ wt_api = ((SNAPPY_COMPRESSOR *)compressor)->wt_api;
+
switch (snret) {
case SNAPPY_BUFFER_TOO_SMALL:
msg = "SNAPPY_BUFFER_TOO_SMALL";
@@ -96,8 +113,6 @@ wt_snappy_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
size_t snaplen;
char *snapbuf;
- (void)compressor; /* Unused */
-
/*
* 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
@@ -125,7 +140,7 @@ wt_snappy_compress(WT_COMPRESSOR *compressor, WT_SESSION *session,
*compression_failed = 1;
return (0);
}
- return (wt_snappy_error(session, "snappy_compress", snret));
+ return (wt_snappy_error(compressor, session, "snappy_compress", snret));
}
static int
@@ -134,10 +149,11 @@ wt_snappy_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *dst, size_t dst_len,
size_t *result_lenp)
{
+ WT_EXTENSION_API *wt_api;
snappy_status snret;
size_t snaplen;
- (void)compressor; /* Unused */
+ wt_api = ((SNAPPY_COMPRESSOR *)compressor)->wt_api;
/* retrieve the saved length */
snaplen = *(size_t *)src;
@@ -157,7 +173,8 @@ wt_snappy_decompress(WT_COMPRESSOR *compressor, WT_SESSION *session,
return (0);
}
- return (wt_snappy_error(session, "snappy_decompress", snret));
+ return (
+ wt_snappy_error(compressor, session, "snappy_decompress", snret));
}
static int
@@ -165,7 +182,7 @@ wt_snappy_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len,
size_t *result_lenp)
{
- (void)compressor; /* Unused */
+ (void)compressor; /* Unused parameters */
(void)session;
(void)src;
@@ -178,4 +195,12 @@ wt_snappy_pre_size(WT_COMPRESSOR *compressor, WT_SESSION *session,
*result_lenp = snappy_max_compressed_length(src_len) + sizeof(size_t);
return (0);
}
-/* End Snappy WT_COMPRESSOR for WT_CONNECTION::add_compressor. */
+
+static int
+wt_snappy_terminate(WT_COMPRESSOR *compressor, WT_SESSION *session)
+{
+ (void)session; /* Unused parameters */
+
+ free(compressor);
+ return (0);
+}
diff --git a/src/btree/bt_handle.c b/src/btree/bt_handle.c
index f8f58221c18..4400af93687 100644
--- a/src/btree/bt_handle.c
+++ b/src/btree/bt_handle.c
@@ -14,7 +14,7 @@ static int __btree_preload(WT_SESSION_IMPL *);
static int __btree_tree_open_empty(WT_SESSION_IMPL *, int);
static int pse1(WT_SESSION_IMPL *, const char *, uint32_t, uint32_t);
-static int pse2(WT_SESSION_IMPL *, const char *, uint32_t, uint32_t, uint32_t);
+static int pse2(WT_SESSION_IMPL *, const char *, uint32_t, uint32_t, int);
/*
* __wt_btree_open --
@@ -562,7 +562,7 @@ __btree_page_sizes(WT_SESSION_IMPL *session)
btree->maxleafitem = (uint32_t)cval.val;
WT_RET(__wt_config_gets(session, cfg, "split_pct", &cval));
- btree->split_pct = (u_int)cval.val;
+ btree->split_pct = (int)cval.val;
/*
* When a page is forced to split, we want at least 50 entries on its
@@ -649,8 +649,8 @@ __wt_split_page_size(WT_BTREE *btree, uint32_t maxpagesize)
* we don't waste space when we write).
*/
a = maxpagesize; /* Don't overflow. */
- split_size =
- (uint32_t)WT_ALIGN((a * btree->split_pct) / 100, btree->allocsize);
+ split_size = (uint32_t)
+ WT_ALIGN((a * (u_int)btree->split_pct) / 100, btree->allocsize);
/*
* If the result of that calculation is the same as the allocation unit
@@ -658,7 +658,7 @@ __wt_split_page_size(WT_BTREE *btree, uint32_t maxpagesize)
* unit, use a percentage of the maximum page size).
*/
if (split_size == btree->allocsize)
- split_size = (uint32_t)((a * btree->split_pct) / 100);
+ split_size = (uint32_t)((a * (u_int)btree->split_pct) / 100);
return (split_size);
}
@@ -674,11 +674,11 @@ pse1(WT_SESSION_IMPL *session, const char *type, uint32_t max, uint32_t ovfl)
static int
pse2(WT_SESSION_IMPL *session,
- const char *type, uint32_t max, uint32_t ovfl, uint32_t pct)
+ const char *type, uint32_t max, uint32_t ovfl, int pct)
{
WT_RET_MSG(session, EINVAL,
"%s page size (%" PRIu32 "B) too small for the maximum item size "
- "(%" PRIu32 "B), because of the split percentage (%" PRIu32
- "%%); a split page must be able to hold at least 2 items",
+ "(%" PRIu32 "B), because of the split percentage (%d %%); a split "
+ "page must be able to hold at least 2 items",
type, max, ovfl, pct);
}
diff --git a/src/cursor/cur_backup.c b/src/cursor/cur_backup.c
index 5c95d89c9d7..e5f3880753e 100644
--- a/src/cursor/cur_backup.c
+++ b/src/cursor/cur_backup.c
@@ -7,20 +7,16 @@
#include "wt_internal.h"
-static int __backup_all(WT_SESSION_IMPL *, WT_CURSOR_BACKUP *, FILE *);
-static int __backup_file_create(WT_SESSION_IMPL *, FILE **);
+static int __backup_all(WT_SESSION_IMPL *, WT_CURSOR_BACKUP *);
+static int __backup_file_create(WT_SESSION_IMPL *, WT_CURSOR_BACKUP *);
static int __backup_file_remove(WT_SESSION_IMPL *);
static int __backup_list_append(
WT_SESSION_IMPL *, WT_CURSOR_BACKUP *, const char *);
static int __backup_start(
WT_SESSION_IMPL *, WT_CURSOR_BACKUP *, const char *[]);
static int __backup_stop(WT_SESSION_IMPL *);
-static int __backup_table(
- WT_SESSION_IMPL *, WT_CURSOR_BACKUP *, const char *, FILE *);
-static int __backup_table_element(WT_SESSION_IMPL *,
- WT_CURSOR_BACKUP *, WT_CURSOR *, const char *, const char *, FILE *);
static int __backup_uri(
- WT_SESSION_IMPL *, WT_CURSOR_BACKUP *, const char *[], FILE *, int *);
+ WT_SESSION_IMPL *, WT_CURSOR_BACKUP *, const char *[], int *);
/*
* __curbackup_next --
@@ -36,13 +32,13 @@ __curbackup_next(WT_CURSOR *cursor)
cb = (WT_CURSOR_BACKUP *)cursor;
CURSOR_API_CALL(cursor, session, next, NULL);
- if (cb->list == NULL || cb->list[cb->next] == NULL) {
+ if (cb->list == NULL || cb->list[cb->next].name == NULL) {
F_CLR(cursor, WT_CURSTD_KEY_SET);
WT_ERR(WT_NOTFOUND);
}
- cb->iface.key.data = cb->list[cb->next];
- cb->iface.key.size = WT_STORE_SIZE(strlen(cb->list[cb->next]) + 1);
+ cb->iface.key.data = cb->list[cb->next].name;
+ cb->iface.key.size = WT_STORE_SIZE(strlen(cb->list[cb->next].name) + 1);
++cb->next;
F_SET(cursor, WT_CURSTD_KEY_RET);
@@ -80,22 +76,29 @@ static int
__curbackup_close(WT_CURSOR *cursor)
{
WT_CURSOR_BACKUP *cb;
+ WT_CURSOR_BACKUP_ENTRY *p;
WT_DECL_RET;
WT_SESSION_IMPL *session;
- char **p;
int tret;
cb = (WT_CURSOR_BACKUP *)cursor;
CURSOR_API_CALL(cursor, session, close, NULL);
- /* Free the list of files. */
+ /* Release the handles, free the file names, free the list itself. */
if (cb->list != NULL) {
- for (p = cb->list; *p != NULL; ++p)
- __wt_free(session, *p);
+ for (p = cb->list; p->name != NULL; ++p) {
+ if (p->handle != NULL)
+ WT_WITH_DHANDLE(session, p->handle,
+ WT_TRET(
+ __wt_session_release_btree(session)));
+ __wt_free(session, p->name);
+ }
+
__wt_free(session, cb->list);
}
- ret = __wt_cursor_close(cursor);
+ WT_TRET(__wt_cursor_close(cursor));
+ session->bkp_cursor = NULL;
WT_WITH_SCHEMA_LOCK(session,
tret = __backup_stop(session)); /* Stop the backup. */
@@ -138,6 +141,7 @@ __wt_curbackup_open(WT_SESSION_IMPL *session,
cursor = &cb->iface;
*cursor = iface;
cursor->session = &session->iface;
+ session->bkp_cursor = cb;
cursor->key_format = "S"; /* Return the file names as the key. */
cursor->value_format = ""; /* No value. */
@@ -168,14 +172,12 @@ static int
__backup_start(
WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *cfg[])
{
- FILE *bfp;
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
int target_list;
conn = S2C(session);
- bfp = NULL;
cb->next = 0;
cb->list = NULL;
@@ -203,24 +205,28 @@ __backup_start(
__wt_spin_unlock(session, &conn->hot_backup_lock);
/* Create the hot backup file. */
- WT_ERR(__backup_file_create(session, &bfp));
+ WT_ERR(__backup_file_create(session, cb));
/*
* If a list of targets was specified, work our way through them.
* Else, generate a list of all database objects.
*/
target_list = 0;
- WT_ERR(__backup_uri(session, cb, cfg, bfp, &target_list));
+ WT_ERR(__backup_uri(session, cb, cfg, &target_list));
if (!target_list)
- WT_ERR(__backup_all(session, cb, bfp));
+ WT_ERR(__backup_all(session, cb));
+
+ /* Add the hot backup and single-threading file to the list. */
+ WT_ERR(__backup_list_append(session, cb, WT_METADATA_BACKUP));
+ WT_ERR(__backup_list_append(session, cb, WT_SINGLETHREAD));
/* Close the hot backup file. */
- ret = fclose(bfp);
- bfp = NULL;
+ ret = fclose(cb->bfp);
+ cb->bfp = NULL;
WT_ERR_TEST(ret == EOF, __wt_errno());
-err: if (bfp != NULL)
- WT_TRET(fclose(bfp) == 0 ? 0 : __wt_errno());
+err: if (cb->bfp != NULL)
+ WT_TRET(fclose(cb->bfp) == 0 ? 0 : __wt_errno());
if (ret != 0)
WT_TRET(__backup_stop(session));
@@ -256,31 +262,50 @@ __backup_stop(WT_SESSION_IMPL *session)
* Backup all objects in the database.
*/
static int
-__backup_all(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, FILE *bfp)
+__backup_all(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
{
+ WT_CONFIG_ITEM cval;
WT_CURSOR *cursor;
WT_DECL_RET;
int cmp;
- const char *key, *path, *uri, *value;
+ const char *key, *uri, *value;
cursor = NULL;
- path = NULL;
/*
- * Open a cursor on the metadata file.
- *
- * Copy object references from the metadata to the hot backup file.
- *
- * We're copying everything, there's nothing in the metadata file we
- * don't want. If that ever changes, we'll need to limit the copy to
- * specific object entries.
+ * Open a cursor on the metadata file and copy all of the entries to
+ * the hot backup file.
*/
WT_ERR(__wt_metadata_cursor(session, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
WT_ERR(cursor->get_key(cursor, &key));
WT_ERR(cursor->get_value(cursor, &value));
- WT_ERR_TEST(
- (fprintf(bfp, "%s\n%s\n", key, value) < 0), __wt_errno());
+ WT_ERR_TEST((fprintf(
+ cb->bfp, "%s\n%s\n", key, value) < 0), __wt_errno());
+
+ /*
+ * While reading the metadata file, check there are no "sources"
+ * or "types" which can't support hot backup. This checks for
+ * a data source that's non-standard, which can't be backed up,
+ * but is also sanity checking: if there's an entry backed by
+ * anything other than a file or lsm entry, we're confused.
+ */
+ if ((ret = __wt_config_getones(
+ session, value, "type", &cval)) == 0 &&
+ !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "file") &&
+ !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "lsm"))
+ WT_ERR_MSG(session, ENOTSUP,
+ "hot backup is not supported for objects of "
+ "type %.*s", (int)cval.len, cval.str);
+ WT_ERR_NOTFOUND_OK(ret);
+ if ((ret =__wt_config_getones(
+ session, value, "source", &cval)) == 0 &&
+ !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "file:") &&
+ !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "lsm:"))
+ WT_ERR_MSG(session, ENOTSUP,
+ "hot backup is not supported for objects of "
+ "source %.*s", (int)cval.len, cval.str);
+ WT_ERR_NOTFOUND_OK(ret);
}
WT_ERR_NOTFOUND_OK(ret);
@@ -294,20 +319,12 @@ __backup_all(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, FILE *bfp)
break;
if (strcmp(uri, WT_METADATA_URI) == 0)
continue;
- WT_ERR(
- __backup_list_append(session, cb, uri + strlen("file:")));
+ WT_ERR(__backup_list_append(session, cb, uri));
}
WT_ERR_NOTFOUND_OK(ret);
- /* Add the hot backup and single-threading file to the list. */
- WT_ERR(__backup_list_append(session, cb, WT_METADATA_BACKUP));
- WT_ERR(__backup_list_append(session, cb, WT_SINGLETHREAD));
-
-err:
- if (cursor != NULL)
+err: if (cursor != NULL)
WT_TRET(cursor->close(cursor));
- if (path != NULL)
- __wt_free(session, path);
return (ret);
}
@@ -317,19 +334,16 @@ err:
*/
static int
__backup_uri(WT_SESSION_IMPL *session,
- WT_CURSOR_BACKUP *cb, const char *cfg[], FILE *bfp, int *foundp)
+ WT_CURSOR_BACKUP *cb, const char *cfg[], int *foundp)
{
WT_CONFIG targetconf;
WT_CONFIG_ITEM cval, k, v;
WT_DECL_ITEM(tmp);
WT_DECL_RET;
int target_list;
- const char *path, *uri, *value;
+ const char *uri;
- *foundp = 0;
-
- path = NULL;
- target_list = 0;
+ *foundp = target_list = 0;
/*
* If we find a non-empty target configuration string, we have a job,
@@ -352,139 +366,10 @@ __backup_uri(WT_SESSION_IMPL *session,
"%s: invalid backup target: URIs may need quoting",
uri);
- if (WT_PREFIX_MATCH(uri, "file:")) {
- /* Copy metadata file information to the backup file. */
- WT_ERR(__wt_metadata_read(session, uri, &value));
- WT_ERR_TEST((fprintf(bfp,
- "%s\n%s\n", uri, value) < 0), __wt_errno());
-
- WT_ERR(__backup_list_append(
- session, cb, uri + strlen("file:")));
- continue;
- }
- if (WT_PREFIX_MATCH(uri, "table:")) {
- WT_ERR(__backup_table(session, cb, uri, bfp));
- continue;
- }
-
- /*
- * It doesn't make sense to backup anything other than a file
- * or table.
- */
- WT_ERR_MSG(
- session, EINVAL, "%s: invalid backup target object", uri);
+ WT_ERR(__wt_schema_worker(
+ session, uri, NULL, __wt_backup_list_append, cfg, 0));
}
WT_ERR_NOTFOUND_OK(ret);
- if (!target_list)
- return (0);
-
- /* Add the hot backup and single-threading file to the list. */
- WT_ERR(__backup_list_append(session, cb, WT_METADATA_BACKUP));
- WT_ERR(__backup_list_append(session, cb, WT_SINGLETHREAD));
-
-err: if (path != NULL)
- __wt_free(session, path);
- __wt_scr_free(&tmp);
- return (ret);
-}
-
-/*
- * __backup_table --
- * Squirrel around in the metadata table until we have enough information
- * to back up a table.
- */
-static int
-__backup_table(
- WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri, FILE *bfp)
-{
- WT_CURSOR *cursor;
- WT_DECL_ITEM(tmp);
- WT_DECL_RET;
- size_t i;
- const char *value;
-
- cursor = NULL;
- WT_RET(__wt_scr_alloc(session, 512, &tmp));
-
- /* Open a cursor on the metadata file. */
- WT_ERR(__wt_metadata_cursor(session, NULL, &cursor));
-
- /* Copy the table's metadata entry to the hot backup file. */
- cursor->set_key(cursor, uri);
- WT_ERR(cursor->search(cursor));
- WT_ERR(cursor->get_value(cursor, &value));
- WT_ERR_TEST((fprintf(bfp, "%s\n%s\n", uri, value) < 0), __wt_errno());
- uri += strlen("table:");
-
- /* Copy the table's column groups and index entries... */
- WT_ERR(
- __backup_table_element(session, cb, cursor, "colgroup:", uri, bfp));
- WT_ERR(__backup_table_element(session, cb, cursor, "index:", uri, bfp));
-
- /* Copy the table's file entries... */
- for (i = 0; i < cb->list_next; ++i) {
- WT_ERR(__wt_buf_fmt(session, tmp, "file:%s", cb->list[i]));
- cursor->set_key(cursor, tmp->data);
- WT_ERR(cursor->search(cursor));
- WT_ERR(cursor->get_value(cursor, &value));
- WT_ERR_TEST((fprintf(bfp,
- "file:%s\n%s\n", cb->list[i], value) < 0), __wt_errno());
- }
-
-err: if (cursor != NULL)
- WT_TRET(cursor->close(cursor));
- __wt_scr_free(&tmp);
- return (ret);
-}
-
-/*
- * __backup_table_element --
- * Backup the column groups or indices.
- */
-static int
-__backup_table_element(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb,
- WT_CURSOR *cursor, const char *elem, const char *table, FILE *bfp)
-{
- WT_CONFIG_ITEM cval;
- WT_DECL_RET;
- WT_DECL_ITEM(tmp);
- int cmp;
- const char *key, *value;
-
- WT_RET(__wt_scr_alloc(session, 512, &tmp));
-
- WT_ERR(__wt_buf_fmt(session, tmp, "%s%s", elem, table));
- cursor->set_key(cursor, tmp->data);
- if ((ret = cursor->search_near(cursor, &cmp)) == 0 && cmp < 0)
- ret = cursor->next(cursor);
- for (; ret == 0; ret = cursor->next(cursor)) {
- /* Check for a match with the specified table name. */
- WT_ERR(cursor->get_key(cursor, &key));
- if (!WT_PREFIX_MATCH(key, elem) ||
- !WT_PREFIX_MATCH(key + strlen(elem), table) ||
- (key[strlen(elem) + strlen(table)] != ':' &&
- key[strlen(elem) + strlen(table)] != '\0'))
- break;
-
- /* Dump the metadata entry. */
- WT_ERR(cursor->get_value(cursor, &value));
- WT_ERR_TEST(
- (fprintf(bfp, "%s\n%s\n", key, value) < 0), __wt_errno());
-
- /* Save the source URI, if it is a file. */
- WT_ERR(__wt_config_getones(session, value, "source", &cval));
- if (cval.len > strlen("file:") &&
- WT_PREFIX_MATCH(cval.str, "file:")) {
- WT_ERR(__wt_buf_fmt(session, tmp, "%.*s",
- (int)(cval.len - strlen("file:")),
- cval.str + strlen("file:")));
- WT_ERR(__backup_list_append(
- session, cb, (const char *)tmp->data));
- } else
- WT_ERR_MSG(session, EINVAL,
- "%s: unknown data source '%.*s'",
- (const char *)tmp->data, (int)cval.len, cval.str);
- }
err: __wt_scr_free(&tmp);
return (ret);
@@ -495,16 +380,14 @@ err: __wt_scr_free(&tmp);
* Create the meta-data backup file.
*/
static int
-__backup_file_create(WT_SESSION_IMPL *session, FILE **fpp)
+__backup_file_create(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
{
WT_DECL_RET;
const char *path;
- *fpp = NULL;
-
/* Open the hot backup file. */
WT_RET(__wt_filename(session, WT_METADATA_BACKUP, &path));
- WT_ERR_TEST((*fpp = fopen(path, "w")) == NULL, __wt_errno());
+ WT_ERR_TEST((cb->bfp = fopen(path, "w")) == NULL, __wt_errno());
err: __wt_free(session, path);
return (ret);
@@ -521,17 +404,58 @@ __backup_file_remove(WT_SESSION_IMPL *session)
}
/*
+ * __wt_backup_list_append --
+ * Append a new file name to the list, allocated space as necessary.
+ * Called via the schema_worker function.
+ */
+int
+__wt_backup_list_append(WT_SESSION_IMPL *session, const char *name)
+{
+ WT_CURSOR_BACKUP *cb;
+ const char *value;
+
+ cb = session->bkp_cursor;
+
+ /* Add the metadata entry to the backup file. */
+ WT_RET(__wt_metadata_read(session, name, &value));
+ WT_RET_TEST(
+ (fprintf(cb->bfp, "%s\n%s\n", name, value) < 0), __wt_errno());
+
+ /* Add file type objects to the list of files to be copied. */
+ if (WT_PREFIX_MATCH(name, "file:"))
+ WT_RET(__backup_list_append(session, cb, name));
+
+ return (0);
+}
+
+/*
* __backup_list_append --
* Append a new file name to the list, allocated space as necessary.
*/
static int
__backup_list_append(
- WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *name)
+ WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri)
{
+ WT_CURSOR_BACKUP_ENTRY *p;
+ WT_DATA_HANDLE *old_dhandle;
+ WT_DECL_RET;
+ const char *name;
+ int need_handle;
+
/* Leave a NULL at the end to mark the end of the list. */
if (cb->list_next + 1 * sizeof(char *) >= cb->list_allocated)
WT_RET(__wt_realloc(session, &cb->list_allocated,
(cb->list_next + 100) * sizeof(char *), &cb->list));
+ p = &cb->list[cb->list_next];
+ p[0].name = p[1].name = NULL;
+ p[0].handle = p[1].handle = NULL;
+
+ need_handle = 0;
+ name = uri;
+ if (WT_PREFIX_MATCH(uri, "file:")) {
+ need_handle = 1;
+ name += strlen("file:");
+ }
/*
* !!!
@@ -542,8 +466,22 @@ __backup_list_append(
* that for now, that block manager might not even support physical
* copying of files by applications.
*/
- WT_RET(__wt_strdup(session, name, &cb->list[cb->list_next++]));
- cb->list[cb->list_next] = NULL;
+ WT_RET(__wt_strdup(session, name, &p->name));
+
+ /*
+ * If it's a file in the database, get a handle for the underlying
+ * object (this handle blocks schema level operations, for example
+ * WT_SESSION.drop or an LSM file discard after level merging).
+ */
+ if (need_handle) {
+ old_dhandle = session->dhandle;
+ if ((ret =
+ __wt_session_get_btree(session, uri, NULL, NULL, 0)) == 0)
+ p->handle = session->dhandle;
+ session->dhandle = old_dhandle;
+ WT_RET(ret);
+ }
+ ++cb->list_next;
return (0);
}
diff --git a/src/docs/upgrading.dox b/src/docs/upgrading.dox
index d8c069ecb43..622a3c4571a 100644
--- a/src/docs/upgrading.dox
+++ b/src/docs/upgrading.dox
@@ -11,6 +11,7 @@ configuration string \c internal_page_max changed from 2KB to 4KB.
Applications wanting to create files with smaller allocation or internal
page sizes will need to set those configuration values explicitly.
</dd>
+
<dt>Shared cache configuration</dt>
<dd>
In the 1.6.1 release, an explicit shared_cache=(enable=boolean) option was
@@ -19,6 +20,13 @@ use shared cache functionality will need to add the enable option to the
configuration string. The default value for the option is false.
</dd>
+<dt>WT_COMPRESSOR::compress_raw signature</dt>
+<dd>
+In the 1.6.1 release, the \c split_pct argument to the
+WT_COMPRESSOR::compress_raw function changed type from \c u_int to \c int,
+applications may require modification to avoid compiler warnings.
+</dd>
+
</dl>
<hr>
@section version_160 Upgrading to Version 1.6.0
diff --git a/src/include/btree.h b/src/include/btree.h
index 8e756e518f4..3ef35562446 100644
--- a/src/include/btree.h
+++ b/src/include/btree.h
@@ -78,7 +78,7 @@ struct __wt_btree {
int internal_key_truncate; /* Reconcile: internal key truncate */
int maximum_depth; /* Reconcile: maximum tree depth */
int prefix_compression; /* Reconcile: key prefix compression */
- u_int split_pct; /* Reconcile: split page percent */
+ int split_pct; /* Reconcile: split page percent */
WT_COMPRESSOR *compressor; /* Reconcile: page compressor */
WT_RWLOCK *val_ovfl_lock; /* Reconcile: overflow value lock */
diff --git a/src/include/cursor.h b/src/include/cursor.h
index 3cc945ca2f3..a86b4b5f702 100644
--- a/src/include/cursor.h
+++ b/src/include/cursor.h
@@ -52,14 +52,19 @@
0 /* uint32_t flags */ \
}
+struct __wt_cursor_backup_entry {
+ char *name; /* File name */
+ WT_DATA_HANDLE *handle; /* Handle */
+};
struct __wt_cursor_backup {
WT_CURSOR iface;
size_t next; /* Cursor position */
+ FILE *bfp; /* Backup file */
- size_t list_allocated; /* List of files */
+ WT_CURSOR_BACKUP_ENTRY *list; /* List of files to be copied. */
+ size_t list_allocated;
size_t list_next;
- char **list;
};
struct __wt_cursor_btree {
diff --git a/src/include/extern.h b/src/include/extern.h
index 244cbc22ad5..0159869302c 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -586,6 +586,7 @@ extern int __wt_curbackup_open(WT_SESSION_IMPL *session,
const char *uri,
const char *cfg[],
WT_CURSOR **cursorp);
+extern int __wt_backup_list_append(WT_SESSION_IMPL *session, const char *name);
extern int __wt_curbulk_init(WT_CURSOR_BULK *cbulk, int bitmap);
extern int __wt_curconfig_open(WT_SESSION_IMPL *session,
const char *uri,
@@ -730,8 +731,10 @@ extern int __wt_lsm_tree_truncate( WT_SESSION_IMPL *session,
const char *cfg[]);
extern int __wt_lsm_tree_worker(WT_SESSION_IMPL *session,
const char *uri,
- int (*func)(WT_SESSION_IMPL *,
+ int (*file_func)(WT_SESSION_IMPL *,
const char *[]),
+ int (*name_func)(WT_SESSION_IMPL *,
+ const char *),
const char *cfg[],
uint32_t open_flags);
extern void *__wt_lsm_merge_worker(void *vargs);
@@ -1051,8 +1054,10 @@ extern int __wt_schema_get_source( WT_SESSION_IMPL *session,
extern int __wt_schema_name_check(WT_SESSION_IMPL *session, const char *uri);
extern int __wt_schema_worker(WT_SESSION_IMPL *session,
const char *uri,
- int (*func)(WT_SESSION_IMPL *,
+ int (*file_func)(WT_SESSION_IMPL *,
const char *[]),
+ int (*name_func)(WT_SESSION_IMPL *,
+ const char *),
const char *cfg[],
uint32_t open_flags);
extern int __wt_open_cursor(WT_SESSION_IMPL *session,
diff --git a/src/include/misc.h b/src/include/misc.h
index 8ded178346d..1d22922ac0c 100644
--- a/src/include/misc.h
+++ b/src/include/misc.h
@@ -140,13 +140,16 @@
memset(&(s), 0, sizeof(s))
/* Check if a string matches a prefix. */
-#define WT_PREFIX_MATCH(str, pre) \
- (strncmp((str), (pre), strlen(pre)) == 0)
+#define WT_PREFIX_MATCH(str, pfx) \
+ (strncmp((str), (pfx), strlen(pfx)) == 0)
+
+#define WT_PREFIX_MATCH_LEN(str, len, pfx) \
+ ((len) >= strlen(pfx) && WT_PREFIX_MATCH(str, pfx))
/* Check if a string matches a prefix, and move past it. */
-#define WT_PREFIX_SKIP(str, pre) \
- ((strncmp((str), (pre), strlen(pre)) == 0) ? \
- ((str) += strlen(pre), 1) : 0)
+#define WT_PREFIX_SKIP(str, pfx) \
+ ((strncmp((str), (pfx), strlen(pfx)) == 0) ? \
+ ((str) += strlen(pfx), 1) : 0)
/* Check if a string matches a byte string of len bytes. */
#define WT_STRING_MATCH(str, bytes, len) \
diff --git a/src/include/session.h b/src/include/session.h
index 8565fa50418..64fbfcd8185 100644
--- a/src/include/session.h
+++ b/src/include/session.h
@@ -62,6 +62,7 @@ struct __wt_session_impl {
WT_CURSOR *cursor; /* Current cursor */
/* Cursors closed with the session */
TAILQ_HEAD(__cursors, __wt_cursor) cursors;
+ WT_CURSOR_BACKUP *bkp_cursor; /* Cursor for current backup */
WT_BTREE *metafile; /* Metadata file */
void *meta_track; /* Metadata operation tracking */
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index 2005d208d44..89e9fefe0ec 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -1267,7 +1267,7 @@ struct __wt_connection {
* The application must first implement the WT_COMPRESSOR interface
* and then register the implementation with WiredTiger:
*
- * @snippet ex_all.c WT_COMPRESSOR register
+ * @snippet nop_compress.c WT_COMPRESSOR initialization
*
* @param connection the connection handle
* @param name the name of the compression function to be used in calls
@@ -1849,7 +1849,7 @@ struct __wt_collator {
* Applications register their implementation with WiredTiger by calling
* WT_CONNECTION::add_compressor.
*
- * @snippet ex_all.c WT_COMPRESSOR register
+ * @snippet nop_compress.c WT_COMPRESSOR initialization
*/
struct __wt_compressor {
/*!
@@ -1881,7 +1881,7 @@ struct __wt_compressor {
* decrease the length of the data (compression may not have completed)
* @returns zero for success, non-zero to indicate an error.
*
- * @snippet ex_all.c WT_COMPRESSOR compress
+ * @snippet nop_compress.c WT_COMPRESSOR compress
*/
int (*compress)(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len,
@@ -1994,7 +1994,7 @@ struct __wt_compressor {
* @returns zero for success, non-zero to indicate an error.
*/
int (*compress_raw)(WT_COMPRESSOR *compressor, WT_SESSION *session,
- size_t page_max, u_int split_pct, size_t extra,
+ size_t page_max, int split_pct, size_t extra,
uint8_t *src, uint32_t *offsets, uint32_t slots,
uint8_t *dst, size_t dst_len,
int final,
@@ -2033,7 +2033,7 @@ struct __wt_compressor {
* @param[out] result_lenp the length of the decompressed data
* @returns zero for success, non-zero to indicate an error.
*
- * @snippet ex_all.c WT_COMPRESSOR decompress
+ * @snippet nop_compress.c WT_COMPRESSOR decompress
*/
int (*decompress)(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len,
@@ -2075,7 +2075,7 @@ struct __wt_compressor {
* @param[out] result_lenp the required destination buffer size
* @returns zero for success, non-zero to indicate an error.
*
- * @snippet ex_all.c WT_COMPRESSOR presize
+ * @snippet nop_compress.c WT_COMPRESSOR presize
*/
int (*pre_size)(WT_COMPRESSOR *compressor, WT_SESSION *session,
uint8_t *src, size_t src_len, size_t *result_lenp);
@@ -2085,6 +2085,8 @@ struct __wt_compressor {
*
* The WT_COMPRESSOR::terminate callback is intended to allow cleanup,
* the handle will not be subsequently accessed by WiredTiger.
+ *
+ * @snippet nop_compress.c WT_COMPRESSOR terminate
*/
int (*terminate)(WT_COMPRESSOR *compressor, WT_SESSION *session);
};
diff --git a/src/include/wiredtiger_ext.h b/src/include/wiredtiger_ext.h
index d21449862c2..7d63e559d78 100644
--- a/src/include/wiredtiger_ext.h
+++ b/src/include/wiredtiger_ext.h
@@ -43,7 +43,7 @@ extern "C" {
* The following code is from the sample compression module, where compression
* extension functions are configured in the extension's entry point:
*
- * @snippet nop_compress.c WT_EXTENSION_API initialization
+ * @snippet nop_compress.c WT_COMPRESSOR initialization
*/
struct __wt_extension_api {
/* !!! To maintain backwards compatibility, this structure is append-only. */
diff --git a/src/include/wt_internal.h b/src/include/wt_internal.h
index 71c5c433035..690d8c9fba3 100644
--- a/src/include/wt_internal.h
+++ b/src/include/wt_internal.h
@@ -99,6 +99,8 @@ struct __wt_connection_stats;
typedef struct __wt_connection_stats WT_CONNECTION_STATS;
struct __wt_cursor_backup;
typedef struct __wt_cursor_backup WT_CURSOR_BACKUP;
+struct __wt_cursor_backup_entry;
+ typedef struct __wt_cursor_backup_entry WT_CURSOR_BACKUP_ENTRY;
struct __wt_cursor_btree;
typedef struct __wt_cursor_btree WT_CURSOR_BTREE;
struct __wt_cursor_bulk;
diff --git a/src/lsm/lsm_tree.c b/src/lsm/lsm_tree.c
index 1131c2f09f8..9a92cceae3e 100644
--- a/src/lsm/lsm_tree.c
+++ b/src/lsm/lsm_tree.c
@@ -820,7 +820,8 @@ err: if (locked)
int
__wt_lsm_tree_worker(WT_SESSION_IMPL *session,
const char *uri,
- int (*func)(WT_SESSION_IMPL *, const char *[]),
+ int (*file_func)(WT_SESSION_IMPL *, const char *[]),
+ int (*name_func)(WT_SESSION_IMPL *, const char *),
const char *cfg[], uint32_t open_flags)
{
WT_DECL_RET;
@@ -832,11 +833,11 @@ __wt_lsm_tree_worker(WT_SESSION_IMPL *session,
FLD_ISSET(open_flags, WT_DHANDLE_EXCLUSIVE) ? 1 : 0, &lsm_tree));
for (i = 0; i < lsm_tree->nchunks; i++) {
chunk = lsm_tree->chunk[i];
- if (func == __wt_checkpoint &&
+ if (file_func == __wt_checkpoint &&
F_ISSET(chunk, WT_LSM_CHUNK_ONDISK))
continue;
- WT_ERR(__wt_schema_worker(
- session, chunk->uri, func, cfg, open_flags));
+ WT_ERR(__wt_schema_worker(session, chunk->uri,
+ file_func, name_func, cfg, open_flags));
}
err: __wt_lsm_tree_release(session, lsm_tree);
return (ret);
diff --git a/src/lsm/lsm_worker.c b/src/lsm/lsm_worker.c
index ae6353197db..bc892b3309a 100644
--- a/src/lsm/lsm_worker.c
+++ b/src/lsm/lsm_worker.c
@@ -279,7 +279,7 @@ __wt_lsm_checkpoint_worker(void *arg)
F_SET(lsm_tree, WT_LSM_TREE_LOCKED);
WT_WITH_SCHEMA_LOCK(session,
ret = __wt_schema_worker(session, chunk->uri,
- __wt_checkpoint, NULL, 0));
+ __wt_checkpoint, NULL, NULL, 0));
F_CLR(lsm_tree, WT_LSM_TREE_LOCKED);
if (ret != 0) {
@@ -445,6 +445,12 @@ __lsm_drop_file(WT_SESSION_IMPL *session, const char *uri)
WT_RET(__lsm_discard_handle(session, uri, NULL));
WT_RET(__lsm_discard_handle(session, uri, "WiredTigerCheckpoint"));
+ /*
+ * Take the schema lock for the drop operation. Play games with the
+ * hot backup lock. Since __wt_schema_drop results in the hot backup
+ * lock being taken when it updates the metadata (which would be too
+ * late to prevent our drop).
+ */
WT_WITH_SCHEMA_LOCK(session,
ret = __wt_schema_drop(session, uri, drop_cfg));
diff --git a/src/schema/schema_worker.c b/src/schema/schema_worker.c
index 8546dff84af..485c751acd7 100644
--- a/src/schema/schema_worker.c
+++ b/src/schema/schema_worker.c
@@ -15,7 +15,8 @@
int
__wt_schema_worker(WT_SESSION_IMPL *session,
const char *uri,
- int (*func)(WT_SESSION_IMPL *, const char *[]),
+ int (*file_func)(WT_SESSION_IMPL *, const char *[]),
+ int (*name_func)(WT_SESSION_IMPL *, const char *),
const char *cfg[], uint32_t open_flags)
{
WT_COLGROUP *colgroup;
@@ -30,50 +31,65 @@ __wt_schema_worker(WT_SESSION_IMPL *session,
table = NULL;
tablename = uri;
+ if (name_func != NULL)
+ WT_ERR(name_func(session, uri));
+
/* Get the btree handle(s) and call the underlying function. */
if (WT_PREFIX_MATCH(uri, "file:")) {
- WT_ERR(__wt_session_get_btree_ckpt(
- session, uri, cfg, open_flags));
- ret = func(session, cfg);
- WT_TRET(__wt_session_release_btree(session));
+ if (file_func != NULL) {
+ WT_ERR(__wt_session_get_btree_ckpt(
+ session, uri, cfg, open_flags));
+ ret = file_func(session, cfg);
+ WT_TRET(__wt_session_release_btree(session));
+ }
} else if (WT_PREFIX_MATCH(uri, "colgroup:")) {
WT_ERR(__wt_schema_get_colgroup(session, uri, NULL, &colgroup));
- WT_ERR(__wt_schema_worker(
- session, colgroup->source, func, cfg, open_flags));
+ WT_ERR(__wt_schema_worker(session, colgroup->source,
+ file_func, name_func, cfg, open_flags));
} else if (WT_PREFIX_SKIP(tablename, "index:")) {
idx = NULL;
WT_ERR(__wt_schema_get_index(session, uri, NULL, &idx));
- WT_ERR(__wt_schema_worker(
- session, idx->source, func, cfg, open_flags));
+ WT_ERR(__wt_schema_worker(session, idx->source,
+ file_func, name_func, cfg, open_flags));
} else if (WT_PREFIX_MATCH(uri, "lsm:")) {
WT_ERR(__wt_lsm_tree_worker(
- session, uri, func, cfg, open_flags));
+ session, uri, file_func, name_func, cfg, open_flags));
} else if (WT_PREFIX_SKIP(tablename, "table:")) {
WT_ERR(__wt_schema_get_table(session,
tablename, strlen(tablename), 0, &table));
WT_ASSERT(session, session->dhandle == NULL);
+ /*
+ * We could make a recursive call for each colgroup or index
+ * URI, but since we have already opened the table, we can take
+ * a short cut and skip straight to the sources. If we have a
+ * name function, it needs to know about the intermediate URIs.
+ */
for (i = 0; i < WT_COLGROUPS(table); i++) {
colgroup = table->cgroups[i];
- WT_ERR(__wt_schema_worker(
- session, colgroup->source, func, cfg, open_flags));
+ if (name_func != NULL)
+ WT_ERR(name_func(session, colgroup->name));
+ WT_ERR(__wt_schema_worker(session, colgroup->source,
+ file_func, name_func, cfg, open_flags));
}
WT_ERR(__wt_schema_open_indices(session, table));
for (i = 0; i < table->nindices; i++) {
idx = table->indices[i];
- WT_ERR(__wt_schema_worker(
- session, idx->source, func, cfg, open_flags));
+ if (name_func != NULL)
+ WT_ERR(name_func(session, idx->name));
+ WT_ERR(__wt_schema_worker(session, idx->source,
+ file_func, name_func, cfg, open_flags));
}
} else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) {
wt_session = (WT_SESSION *)session;
- if (func == __wt_compact && dsrc->compact != NULL)
+ if (file_func == __wt_compact && dsrc->compact != NULL)
WT_ERR(dsrc->compact(
dsrc, wt_session, uri, (WT_CONFIG_ARG *)cfg));
- else if (func == __wt_salvage && dsrc->salvage != NULL)
+ else if (file_func == __wt_salvage && dsrc->salvage != NULL)
WT_ERR(dsrc->salvage(
dsrc, wt_session, uri, (WT_CONFIG_ARG *)cfg));
- else if (func == __wt_verify && dsrc->verify != NULL)
+ else if (file_func == __wt_verify && dsrc->verify != NULL)
WT_ERR(dsrc->verify(
dsrc, wt_session, uri, (WT_CONFIG_ARG *)cfg));
else
diff --git a/src/session/session_api.c b/src/session/session_api.c
index 2d037051955..68d04a8f640 100644
--- a/src/session/session_api.c
+++ b/src/session/session_api.c
@@ -350,7 +350,7 @@ __session_compact_worker(
SESSION_API_CALL(session, compact, config, cfg);
WT_WITH_SCHEMA_LOCK(session,
- ret = __wt_schema_worker(session, uri, __wt_compact, cfg, 0));
+ ret = __wt_schema_worker(session, uri, __wt_compact, NULL, cfg, 0));
err: API_END_NOTFOUND_MAP(session, ret);
}
@@ -466,8 +466,8 @@ __session_salvage(WT_SESSION *wt_session, const char *uri, const char *config)
SESSION_API_CALL(session, salvage, config, cfg);
WT_WITH_SCHEMA_LOCK(session,
- ret = __wt_schema_worker(session, uri,
- __wt_salvage, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_SALVAGE));
+ ret = __wt_schema_worker(session, uri, __wt_salvage,
+ NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_SALVAGE));
err: API_END_NOTFOUND_MAP(session, ret);
}
@@ -588,8 +588,8 @@ __session_upgrade(WT_SESSION *wt_session, const char *uri, const char *config)
SESSION_API_CALL(session, upgrade, config, cfg);
WT_WITH_SCHEMA_LOCK(session,
- ret = __wt_schema_worker(session, uri,
- __wt_upgrade, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_UPGRADE));
+ ret = __wt_schema_worker(session, uri, __wt_upgrade,
+ NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_UPGRADE));
err: API_END_NOTFOUND_MAP(session, ret);
}
@@ -608,8 +608,8 @@ __session_verify(WT_SESSION *wt_session, const char *uri, const char *config)
SESSION_API_CALL(session, verify, config, cfg);
WT_WITH_SCHEMA_LOCK(session,
- ret = __wt_schema_worker(session, uri,
- __wt_verify, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_VERIFY));
+ ret = __wt_schema_worker(session, uri, __wt_verify,
+ NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_VERIFY));
err: API_END_NOTFOUND_MAP(session, ret);
}
diff --git a/src/txn/txn_ckpt.c b/src/txn/txn_ckpt.c
index 8d4b56de2f1..d1c14362758 100644
--- a/src/txn/txn_ckpt.c
+++ b/src/txn/txn_ckpt.c
@@ -95,7 +95,7 @@ __checkpoint_apply(WT_SESSION_IMPL *session, const char *cfg[],
WT_ERR(__wt_buf_fmt(session, tmp, "%.*s", (int)k.len, k.str));
if ((ret = __wt_schema_worker(
- session, tmp->data, op, cfg, 0)) != 0)
+ session, tmp->data, op, NULL, cfg, 0)) != 0)
WT_ERR_MSG(session, ret, "%s", (const char *)tmp->data);
}
WT_ERR_NOTFOUND_OK(ret);
diff --git a/test/format/Makefile.am b/test/format/Makefile.am
index da0c950b080..ed6939ae583 100644
--- a/test/format/Makefile.am
+++ b/test/format/Makefile.am
@@ -6,7 +6,8 @@ AM_CPPFLAGS = -DWIREDTIGER_TEST_COMPRESS_RAW \
noinst_PROGRAMS = t
noinst_SCRIPTS = s_dumpcmp
t_SOURCES =\
- config.h format.h bdb.c config.c t.c util.c wts.c wts_bulk.c wts_ops.c
+ config.h format.h backup.c bdb.c bulk.c config.c ops.c t.c util.c wts.c
+
t_LDADD = $(top_builddir)/libwiredtiger.la -L$(BERKELEY_DB_PATH)/lib -ldb
t_LDFLAGS = -static
diff --git a/test/format/backup.c b/test/format/backup.c
new file mode 100644
index 00000000000..a7e2d10b909
--- /dev/null
+++ b/test/format/backup.c
@@ -0,0 +1,157 @@
+/*-
+ * Public Domain 2008-2013 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 "format.h"
+
+/*
+ * check_copy --
+ * Confirm the hot backup worked.
+ */
+static void
+check_copy(void)
+{
+ WT_CONNECTION *conn;
+ WT_SESSION *session;
+ int ret;
+
+ wts_open(RUNDIR_BACKUP, 0, &conn);
+
+ /*
+ * Open a session and verify the store; some data-sources don't support
+ * verify.
+ *
+ * XXX
+ * LSM can deadlock if WT_SESSION methods are called at the wrong time,
+ * don't do that for now.
+ */
+ if (!DATASOURCE("lsm") && !DATASOURCE("memrata")) {
+ if ((ret = conn->open_session(
+ conn, NULL, NULL, &session)) != 0)
+ die(ret, "connection.open_session");
+
+ if ((ret = session->verify(session, g.uri, NULL)) != 0)
+ die(ret, "session.verify: %s", g.uri);
+ }
+
+ if ((ret = conn->close(conn, NULL)) != 0)
+ die(ret, "connection.close: %s", RUNDIR_BACKUP);
+}
+
+/*
+ * hot_copy --
+ * Copy a single file into the hot backup directory.
+ */
+static void
+hot_copy(const char *name)
+{
+ char buf[1024];
+
+ (void)snprintf(
+ buf, sizeof(buf), "cp RUNDIR/%s RUNDIR/BACKUP/%s", name, name);
+ if (system(buf) != 0)
+ die(errno, "hot backup copy: %s", buf);
+}
+
+/*
+ * hot_backup --
+ * Periodically do a hot backup and verify it.
+ */
+void *
+hot_backup(void *arg)
+{
+ WT_CONNECTION *conn;
+ WT_CURSOR *backup_cursor;
+ WT_SESSION *session;
+ u_int period;
+ int ret;
+ const char *key;
+
+ (void)arg;
+
+ /* If hot backups aren't configured, we're done. */
+ if (!g.c_hot_backups)
+ return (NULL);
+
+ /* Hot backups aren't supported for non-standard data sources. */
+ if (DATASOURCE("kvsbdb") || DATASOURCE("memrata"))
+ return (NULL);
+
+ conn = g.wts_conn;
+
+ /* Open a session. */
+ if ((ret = conn->open_session(
+ conn, NULL, NULL, &session)) != 0)
+ die(ret, "connection.open_session");
+
+ /*
+ * Perform a hot backup at somewhere under 10 seconds (so we get at
+ * least one done), and then at 45 second intervals.
+ */
+ for (period = MMRAND(1, 10); !g.threads_finished; period = 45) {
+
+ /* Sleep for a short period so we don't make the run wait. */
+ if (period > 0) {
+ --period;
+ sleep(1);
+ if (g.threads_finished)
+ break;
+ }
+
+ /* Lock out named checkpoints */
+ if ((ret = pthread_rwlock_wrlock(&g.backup_lock)) != 0)
+ die(ret, "pthread_rwlock_wrlock: hot-backup lock");
+
+ /* Re-create the backup directory. */
+ (void)system("cd RUNDIR && rm -rf BACKUP");
+ if (mkdir(RUNDIR_BACKUP, 0777) != 0)
+ die(errno, "mkdir: %s", RUNDIR_BACKUP);
+
+ if ((ret = session->open_cursor(session,
+ "backup:", NULL, NULL, &backup_cursor)) != 0)
+ die(ret, "session.open_cursor: backup");
+
+ while ((ret = backup_cursor->next(backup_cursor)) == 0) {
+ if ((ret =
+ backup_cursor->get_key(backup_cursor, &key)) != 0)
+ die(ret, "cursor.get_key");
+ hot_copy(key);
+ }
+
+ if ((ret = backup_cursor->close(backup_cursor)) != 0)
+ die(ret, "cursor.close");
+
+ if ((ret = pthread_rwlock_unlock(&g.backup_lock)) != 0)
+ die(ret, "pthread_rwlock_unlock: hot-backup lock");
+
+ check_copy();
+ }
+
+ if ((ret = session->close(session, NULL)) != 0)
+ die(ret, "session.close");
+
+ return (NULL);
+}
diff --git a/test/format/wts_bulk.c b/test/format/bulk.c
index 71f01483481..14fcd5e0d9e 100644
--- a/test/format/wts_bulk.c
+++ b/test/format/bulk.c
@@ -43,7 +43,7 @@ wts_load(void)
die(ret, "connection.open_session");
if (g.logging != 0)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"=============== bulk load start ===============");
/*
@@ -84,7 +84,7 @@ wts_load(void)
cursor->set_key(cursor, g.key_cnt);
cursor->set_value(cursor, *(uint8_t *)value.data);
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s %" PRIu32 " {0x%02" PRIx8 "}",
"bulk V",
g.key_cnt, ((uint8_t *)value.data)[0]);
@@ -94,7 +94,7 @@ wts_load(void)
cursor->set_key(cursor, g.key_cnt);
cursor->set_value(cursor, &value);
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s %" PRIu32 " {%.*s}", "bulk V",
g.key_cnt,
(int)value.size, (char *)value.data);
@@ -102,12 +102,12 @@ wts_load(void)
case ROW:
cursor->set_key(cursor, &key);
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s %" PRIu32 " {%.*s}", "bulk K",
g.key_cnt, (int)key.size, (char *)key.data);
cursor->set_value(cursor, &value);
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s %" PRIu32 " {%.*s}", "bulk V",
g.key_cnt,
(int)value.size, (char *)value.data);
@@ -128,7 +128,7 @@ wts_load(void)
die(ret, "cursor.close");
if (g.logging != 0)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"=============== bulk load stop ===============");
if ((ret = session->close(session, NULL)) != 0)
diff --git a/test/format/format.h b/test/format/format.h
index 1871e425497..5f09e35d417 100644
--- a/test/format/format.h
+++ b/test/format/format.h
@@ -32,6 +32,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <pthread.h>
@@ -76,6 +77,7 @@ extern WT_EXTENSION_API *wt_api;
#define WT_NAME "wt" /* Object name */
#define RUNDIR "RUNDIR" /* Run home */
+#define RUNDIR_BACKUP "RUNDIR/BACKUP" /* Hot-backup directory */
#define RUNDIR_KVS "RUNDIR/KVS" /* Run home for data-source */
#define DATASOURCE(v) (strcmp(v, g.c_data_source) == 0 ? 1 : 0)
@@ -87,7 +89,8 @@ typedef struct {
void *bdb; /* BDB comparison handle */
void *dbc; /* BDB cursor handle */
- void *wts_conn; /* WT_CONNECTION handle */
+ WT_CONNECTION *wts_conn;
+ WT_EXTENSION_API *wt_api;
FILE *rand_log; /* Random number log */
@@ -101,6 +104,9 @@ typedef struct {
int replay; /* Replaying a run. */
int track; /* Track progress */
+ int threads_finished; /* Operations completed */
+
+ pthread_rwlock_t backup_lock; /* Hot backup running */
char *uri; /* Object name */
@@ -126,6 +132,7 @@ typedef struct {
char *c_data_source;
u_int c_delete_pct;
u_int c_dictionary;
+ u_int c_hot_backups;
char *c_file_type;
u_int c_huffman_key;
u_int c_huffman_value;
@@ -184,6 +191,7 @@ void config_print(int);
void config_setup(void);
void config_single(const char *, int);
void die(int, const char *, ...);
+void *hot_backup(void *);
void key_len_setup(void);
void key_gen_setup(uint8_t **);
void key_gen(uint8_t *, uint32_t *, uint64_t, int);
@@ -192,9 +200,10 @@ void track(const char *, uint64_t, TINFO *);
void val_gen_setup(uint8_t **);
void value_gen(uint8_t *, uint32_t *, uint64_t);
void wts_close(void);
+void wts_create(void);
void wts_dump(const char *, int);
void wts_load(void);
-void wts_open(void);
+void wts_open(const char *, int, WT_CONNECTION **);
void wts_ops(void);
uint32_t wts_rand(void);
void wts_read_scan(void);
diff --git a/test/format/wts_ops.c b/test/format/ops.c
index 9c9ddb2b88b..b69df945156 100644
--- a/test/format/wts_ops.c
+++ b/test/format/ops.c
@@ -48,6 +48,7 @@ wts_ops(void)
TINFO *tinfo, total;
WT_CONNECTION *conn;
WT_SESSION *session;
+ pthread_t backup_tid;
int ret, running;
uint32_t i;
@@ -57,7 +58,7 @@ wts_ops(void)
if (g.logging != 0) {
if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
die(ret, "connection.open_session");
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"=============== thread ops start ===============");
}
@@ -66,7 +67,16 @@ wts_ops(void)
total.id = 1;
(void)ops(&total);
} else {
- /* Create thread structure. */
+ /*
+ * We have to single-thread named checkpoints and hot backups,
+ * initialize a lock.
+ */
+ if ((ret = pthread_rwlock_init(&g.backup_lock, NULL)) != 0)
+ die(ret, "pthread_rwlock_init: hot-backup lock");
+
+ g.threads_finished = 0;
+
+ /* Create thread structure, start worker, hot-backup threads. */
if ((tinfo =
calloc((size_t)g.c_threads, sizeof(*tinfo))) == NULL)
die(errno, "calloc");
@@ -77,6 +87,9 @@ wts_ops(void)
&tinfo[i].tid, NULL, ops, &tinfo[i])) != 0)
die(ret, "pthread_create");
}
+ if ((ret =
+ pthread_create(&backup_tid, NULL, hot_backup, NULL)) != 0)
+ die(ret, "pthread_create");
/* Wait for the threads. */
for (;;) {
@@ -105,10 +118,17 @@ wts_ops(void)
(void)usleep(100000); /* 1/10th of a second */
}
free(tinfo);
+
+ /* Wait for the backup thread. */
+ g.threads_finished = 1;
+ (void)pthread_join(backup_tid, NULL);
+
+ if ((ret = pthread_rwlock_destroy(&g.backup_lock)) != 0)
+ die(ret, "pthread_rwlock_destroy: hot-backup lock");
}
if (g.logging != 0) {
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"=============== thread ops stop ===============");
if ((ret = session->close(session, NULL)) != 0)
die(ret, "session.close");
@@ -197,29 +217,42 @@ ops(void *arg)
if (cnt == ckpt_op) {
/*
- * LSM trees don't support named checkpoints, else half
- * the time we name the checkpoint.
+ * LSM trees don't support named checkpoints, else 25%
+ * of the time we name the checkpoint.
*/
- if (DATASOURCE("lsm") || MMRAND(1, 2) == 1)
+ if (DATASOURCE("lsm") || MMRAND(1, 4) == 1)
ckpt_config = NULL;
else {
(void)snprintf(buf, sizeof(buf),
"name=thread-%d", tinfo->id);
ckpt_config = buf;
}
+
+ /* Named checkpoints lock out hot backups */
+ if (ckpt_config != NULL &&
+ (ret = pthread_rwlock_wrlock(&g.backup_lock)) != 0)
+ die(ret,
+ "pthread_rwlock_wrlock: hot-backup lock");
+
if ((ret =
session->checkpoint(session, ckpt_config)) != 0)
die(ret, "session.checkpoint%s%s",
ckpt_config == NULL ? "" : ": ",
ckpt_config == NULL ? "" : ckpt_config);
+ if (ckpt_config != NULL &&
+ (ret = pthread_rwlock_unlock(&g.backup_lock)) != 0)
+ die(ret,
+ "pthread_rwlock_wrlock: hot-backup lock");
+
/*
* Pick the next checkpoint operation, try for roughly
* five checkpoint operations per thread run.
*/
ckpt_op += MMRAND(1, thread_ops) / 5;
}
- /* kvs doesn't support compaction. */
+
+ /* Data-sources don't support compaction. */
if (cnt == compact_op &&
!DATASOURCE("kvsbdb") && !DATASOURCE("memrata") &&
(ret = session->compact(session, g.uri, NULL)) != 0)
@@ -383,7 +416,7 @@ read_row(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno)
/* Log the operation */
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(wt_api,
+ (void)g.wt_api->msg_printf(g.wt_api,
session, "%-10s%" PRIu64, "read", keyno);
/* Retrieve the key/value pair by key. */
@@ -527,18 +560,18 @@ nextprev(WT_CURSOR *cursor, int next, int *notfoundp)
if (g.logging == LOG_OPS)
switch (g.type) {
case FIX:
- (void)wt_api->msg_printf(wt_api,
+ (void)g.wt_api->msg_printf(g.wt_api,
session, "%-10s%" PRIu64 " {0x%02x}", which,
keyno, ((char *)value.data)[0]);
break;
case ROW:
- (void)wt_api->msg_printf(
- wt_api, session, "%-10s{%.*s/%.*s}", which,
+ (void)g.wt_api->msg_printf(
+ g.wt_api, session, "%-10s{%.*s/%.*s}", which,
(int)key.size, (char *)key.data,
(int)value.size, (char *)value.data);
break;
case VAR:
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s%" PRIu64 " {%.*s}", which,
keyno, (int)value.size, (char *)value.data);
break;
@@ -563,7 +596,7 @@ row_update(
/* Log the operation */
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s{%.*s}\n%-10s{%.*s}",
insert ? "insertK" : "putK",
(int)key->size, (char *)key->data,
@@ -602,12 +635,12 @@ col_update(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t keyno)
/* Log the operation */
if (g.logging == LOG_OPS) {
if (g.type == FIX)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s%" PRIu64 " {0x%02" PRIx8 "}",
"update", keyno,
((uint8_t *)value->data)[0]);
else
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s%" PRIu64 " {%.*s}",
"update", keyno,
(int)value->size, (char *)value->data);
@@ -665,12 +698,12 @@ col_insert(WT_CURSOR *cursor, WT_ITEM *key, WT_ITEM *value, uint64_t *keynop)
if (g.logging == LOG_OPS) {
if (g.type == FIX)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s%" PRIu64 " {0x%02" PRIx8 "}",
"insert", keyno,
((uint8_t *)value->data)[0]);
else
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"%-10s%" PRIu64 " {%.*s}",
"insert", keyno,
(int)value->size, (char *)value->data);
@@ -699,8 +732,8 @@ row_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, int *notfoundp)
/* Log the operation */
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(
- wt_api, session, "%-10s%" PRIu64, "remove", keyno);
+ (void)g.wt_api->msg_printf(
+ g.wt_api, session, "%-10s%" PRIu64, "remove", keyno);
cursor->set_key(cursor, key);
ret = cursor->remove(cursor);
@@ -734,8 +767,8 @@ col_remove(WT_CURSOR *cursor, WT_ITEM *key, uint64_t keyno, int *notfoundp)
/* Log the operation */
if (g.logging == LOG_OPS)
- (void)wt_api->msg_printf(
- wt_api, session, "%-10s%" PRIu64, "remove", keyno);
+ (void)g.wt_api->msg_printf(
+ g.wt_api, session, "%-10s%" PRIu64, "remove", keyno);
cursor->set_key(cursor, keyno);
ret = cursor->remove(cursor);
diff --git a/test/format/t.c b/test/format/t.c
index eff9caced48..39f38d9580a 100644
--- a/test/format/t.c
+++ b/test/format/t.c
@@ -28,7 +28,6 @@
#include "format.h"
GLOBAL g;
-WT_EXTENSION_API *wt_api;
static void onint(int);
static void startup(void);
@@ -110,7 +109,8 @@ main(int argc, char *argv[])
track("starting up", 0ULL, NULL);
if (SINGLETHREADED)
bdb_open(); /* Initial file config */
- wts_open();
+ wts_open(RUNDIR, 1, &g.wts_conn);
+ wts_create();
wts_load(); /* Load initial records */
wts_verify("post-bulk verify"); /* Verify */
@@ -165,7 +165,7 @@ main(int argc, char *argv[])
* against the Berkeley DB data set again, if possible).
*/
if (g.c_delete_pct == 0) {
- wts_open();
+ wts_open(RUNDIR, 1, &g.wts_conn);
wts_salvage();
wts_verify("post-salvage verify");
wts_close();
diff --git a/test/format/wts.c b/test/format/wts.c
index f3f60f9cb4f..450325db3a9 100644
--- a/test/format/wts.c
+++ b/test/format/wts.c
@@ -58,23 +58,25 @@ static WT_EVENT_HANDLER event_handler = {
handle_progress
};
+/*
+ * wts_open --
+ * Open a connection to a WiredTiger database.
+ */
void
-wts_open(void)
+wts_open(const char *home, int set_api, WT_CONNECTION **connp)
{
WT_CONNECTION *conn;
- WT_SESSION *session;
- uint32_t maxintlpage, maxintlitem, maxleafpage, maxleafitem;
int ret;
- char config[2048], *end, *p;
+ char config[2048];
+
+ *connp = NULL;
/*
- * Open configuration.
- *
* Put configuration file configuration options second to last. Put
* command line configuration options at the end. Do this so they
* override the standard configuration.
*/
- snprintf(config, sizeof(config),
+ (void)snprintf(config, sizeof(config),
"create,"
"sync=false,cache_size=%" PRIu32 "MB,"
"buffer_alignment=512,error_prefix=\"%s\","
@@ -85,7 +87,7 @@ wts_open(void)
g.c_cache,
g.progname,
g.c_data_extend ? "file_extend=(data=8MB)," : "",
- REVERSE_PATH,
+ g.c_reverse ? REVERSE_PATH : "",
access(BZIP_PATH, R_OK) == 0 ? BZIP_PATH : "",
access(LZO_PATH, R_OK) == 0 ? LZO_PATH : "",
(access(RAW_PATH, R_OK) == 0 &&
@@ -96,21 +98,48 @@ wts_open(void)
g.c_config_open == NULL ? "" : g.c_config_open,
g.config_open == NULL ? "" : g.config_open);
+ /*
+ * Direct I/O may not work with hot-backups, doing copies through the
+ * buffer cache after configuring direct I/O in Linux won't work. If
+ * direct I/O is configured, turn off hot backups. This isn't a great
+ * place to do this check, but it's only here we have the configuration
+ * string.
+ */
+ g.c_hot_backups = strstr(config, "direct_io") == NULL;
+
if ((ret =
- wiredtiger_open("RUNDIR", &event_handler, config, &conn)) != 0)
- die(ret, "wiredtiger_open");
- g.wts_conn = conn;
- /* Load extension functions. */
- wt_api = conn->get_extension_api(conn);
+ wiredtiger_open(home, &event_handler, config, &conn)) != 0)
+ die(ret, "wiredtiger_open: %s", home);
- if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
- die(ret, "connection.open_session");
+ if (set_api)
+ g.wt_api = conn->get_extension_api(conn);
+
+ *connp = conn;
+}
+
+/*
+ * wts_create --
+ * Create the underlying store.
+ */
+void
+wts_create(void)
+{
+ WT_CONNECTION *conn;
+ WT_SESSION *session;
+ uint32_t maxintlpage, maxintlitem, maxleafpage, maxleafitem;
+ int ret;
+ char config[2048], *end, *p;
+
+ conn = g.wts_conn;
/*
- * Create the object.
+ * Create the underlying store.
*
* Make sure at least 2 internal page per thread can fit in cache.
*/
+ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
+ die(ret, "connection.open_session");
+
maxintlpage = 1U << g.c_intl_page_max;
while (maxintlpage > 512 &&
2 * g.c_threads * maxintlpage > g.c_cache << 20)
@@ -332,12 +361,12 @@ wts_verify(const char *tag)
if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
die(ret, "connection.open_session");
if (g.logging != 0)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"=============== verify start ===============");
if ((ret = session->verify(session, g.uri, NULL)) != 0)
die(ret, "session.verify: %s: %s", g.uri, tag);
if (g.logging != 0)
- (void)wt_api->msg_printf(wt_api, session,
+ (void)g.wt_api->msg_printf(g.wt_api, session,
"=============== verify stop ===============");
if ((ret = session->close(session, NULL)) != 0)
die(ret, "session.close");
diff --git a/test/suite/helper.py b/test/suite/helper.py
index fa8e95d249d..31215448987 100644
--- a/test/suite/helper.py
+++ b/test/suite/helper.py
@@ -165,26 +165,35 @@ def value_populate_complex(i):
# config: prefix of the session.create configuration string
# rows: entries to insert
def complex_populate(self, uri, config, rows):
+ complex_populate_type(self, uri, config, rows, '')
+def complex_populate_lsm(self, uri, config, rows):
+ complex_populate_type(self, uri, config, rows, 'type=lsm')
+def complex_populate_type(self, uri, config, rows, type):
self.session.create(uri,
config + ',value_format=SiSS,' +
'columns=(record,column2,column3,column4,column5),' +
'colgroups=(cgroup1,cgroup2,cgroup3,cgroup4,cgroup5,cgroup6)')
+
cgname = 'colgroup:' + uri.split(":")[1]
- self.session.create(cgname + ':cgroup1', 'columns=(column2)')
- self.session.create(cgname + ':cgroup2', 'columns=(column3)')
- self.session.create(cgname + ':cgroup3', 'columns=(column4)')
- self.session.create(cgname + ':cgroup4', 'columns=(column2,column3)')
- self.session.create(cgname + ':cgroup5', 'columns=(column3,column4)')
+ self.session.create(cgname + ':cgroup1', 'columns=(column2)' + ',' + type)
+ self.session.create(cgname + ':cgroup2', 'columns=(column3)' + ',' + type)
+ self.session.create(cgname + ':cgroup3', 'columns=(column4)' + ',' + type)
+ self.session.create(
+ cgname + ':cgroup4', 'columns=(column2,column3)' + ',' + type)
+ self.session.create(
+ cgname + ':cgroup5', 'columns=(column3,column4)' + ',' + type)
self.session.create(
- cgname + ':cgroup6', 'columns=(column2,column4,column5)')
+ cgname + ':cgroup6', 'columns=(column2,column4,column5)' + ',' + type)
indxname = 'index:' + uri.split(":")[1]
- self.session.create(indxname + ':indx1', 'columns=(column2)')
- self.session.create(indxname + ':indx2', 'columns=(column3)')
- self.session.create(indxname + ':indx3', 'columns=(column4)')
- self.session.create(indxname + ':indx4', 'columns=(column2,column4)')
- self.session.create(indxname + ':indx5', 'columns=(column3,column5)')
+ self.session.create(indxname + ':indx1', 'columns=(column2)' + ',' + type)
+ self.session.create(indxname + ':indx2', 'columns=(column3)' + ',' + type)
+ self.session.create(indxname + ':indx3', 'columns=(column4)' + ',' + type)
+ self.session.create(
+ indxname + ':indx4', 'columns=(column2,column4)' + ',' + type)
+ self.session.create(
+ indxname + ':indx5', 'columns=(column3,column5)' + ',' + type)
self.session.create(
- indxname + ':indx6', 'columns=(column3,column5,column4)')
+ indxname + ':indx6', 'columns=(column3,column5,column4)' + ',' + type)
cursor = self.session.open_cursor(uri, None)
for i in range(1, rows + 1):
cursor.set_key(key_populate(cursor, i))
diff --git a/test/suite/test_backup.py b/test/suite/test_backup01.py
index c53cd60f554..0ab7ab2e5ec 100644
--- a/test/suite/test_backup.py
+++ b/test/suite/test_backup01.py
@@ -31,7 +31,8 @@ import shutil
import string
from suite_subprocess import suite_subprocess
import wiredtiger, wttest
-from helper import compare_files, complex_populate, simple_populate
+from helper import compare_files,\
+ complex_populate, complex_populate_lsm, simple_populate
# test_backup.py
# Utilities: wt backup
@@ -41,17 +42,22 @@ class test_backup(wttest.WiredTigerTestCase, suite_subprocess):
pfx = 'test_backup'
objs = [
- ( 'file:' + pfx + '.1', simple_populate),
- ( 'file:' + pfx + '.2', simple_populate),
- ('table:' + pfx + '.3', simple_populate),
- ('table:' + pfx + '.4', simple_populate),
- ('table:' + pfx + '.5', complex_populate),
- ('table:' + pfx + '.6', complex_populate),
+ ( 'file:' + pfx + '.1', simple_populate, 0),
+ ( 'file:' + pfx + '.2', simple_populate, 0),
+ ('table:' + pfx + '.3', simple_populate, 0),
+ ('table:' + pfx + '.4', simple_populate, 0),
+ ('table:' + pfx + '.5', complex_populate, 0),
+ ('table:' + pfx + '.6', complex_populate, 0),
+ ('table:' + pfx + '.7', complex_populate_lsm, 1),
+ ('table:' + pfx + '.8', complex_populate_lsm, 1),
]
# Populate a set of objects.
- def populate(self):
+ def populate(self, skiplsm):
for i in self.objs:
+ if i[2]:
+ if skiplsm:
+ continue
i[1](self, i[0], 'key_format=S', 100)
# Compare the original and backed-up files using the wt dump command.
@@ -75,7 +81,7 @@ class test_backup(wttest.WiredTigerTestCase, suite_subprocess):
# Test backup of a database using the wt backup command.
def test_backup_database(self):
- self.populate()
+ self.populate(0)
os.mkdir(self.dir)
self.runWt(['backup', self.dir])
@@ -127,23 +133,16 @@ class test_backup(wttest.WiredTigerTestCase, suite_subprocess):
# Test backup of database subsets.
def test_backup_table(self):
- self.populate()
- self.backup_table([0,2,4])
- self.backup_table([1,3,5])
+ self.populate(0)
+ self.backup_table([0,2,4,6])
+ self.backup_table([1,3,5,7])
self.backup_table([0,1,2])
self.backup_table([3,4,5])
-
- # Test backup of random object types fails.
- def test_illegal_objects(self):
- for target in ('colgroup:xxx', 'index:xxx'):
- msg = '/invalid backup target object/'
- config = 'target=("%s")' % target
- self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
- lambda: self.session.open_cursor('backup:', None, config), msg)
+ self.backup_table([5,6,7])
# Test cursor reset runs through the list twice.
def test_cursor_reset(self):
- self.populate()
+ self.populate(0)
cursor = self.session.open_cursor('backup:', None, None)
i = 0
while True:
@@ -165,7 +164,8 @@ class test_backup(wttest.WiredTigerTestCase, suite_subprocess):
# Test that named checkpoints can't be deleted while backup cursors are
# open, but that normal checkpoints continue to work.
def test_checkpoint_delete(self):
- self.populate()
+ # You cannot name checkpoints including LSM tables, skip those.
+ self.populate(1)
# Confirm checkpoints are being deleted.
self.session.checkpoint("name=one")
diff --git a/test/suite/test_backup03.py b/test/suite/test_backup03.py
new file mode 100644
index 00000000000..a8b9340cba2
--- /dev/null
+++ b/test/suite/test_backup03.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+#
+# Public Domain 2008-2013 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.
+
+import glob
+import os
+import shutil
+import string
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+from helper import compare_files,\
+ complex_populate, complex_populate_lsm, simple_populate
+
+# test_backup03.py
+# Utilities: wt backup
+# Test cursor backup with target URIs
+class test_backup(wttest.WiredTigerTestCase, suite_subprocess):
+ dir='backup.dir' # Backup directory name
+
+ pfx = 'test_backup'
+ objs = [
+ ('table:' + pfx + '.1', simple_populate, 100),
+ ('lsm:' + pfx + '.2', simple_populate, 50000),
+ ('table:' + pfx + '.3', complex_populate, 100),
+ ('table:' + pfx + '.4', complex_populate_lsm, 100),
+ ]
+
+ # Populate a set of objects.
+ def populate(self):
+ for i in self.objs:
+ i[1](self, i[0], 'key_format=S', i[2])
+ # Backup needs a checkpoint
+ self.session.checkpoint(None)
+
+ # Compare the original and backed-up files using the wt dump command.
+ def compare(self, uri):
+ self.runWt(['dump', uri], outfilename='orig')
+ self.runWt(['-h', self.dir, 'dump', uri], outfilename='backup')
+ compare_files(self, 'orig', 'backup')
+
+ # Check that a URI doesn't exist, both the meta-data and the file names.
+ def confirmPathDoesNotExist(self, uri):
+ conn = wiredtiger.wiredtiger_open(self.dir)
+ session = conn.open_session()
+ self.assertRaises(wiredtiger.WiredTigerError,
+ lambda: session.open_cursor(uri, None, None))
+ conn.close()
+
+ self.assertEqual(
+ glob.glob(self.dir + '*' + uri.split(":")[1] + '*'), [],
+ 'confirmPathDoesNotExist: URI exists, file name matching \"' +
+ uri.split(":")[1] + '\" found')
+
+ # Backup a set of chosen tables/files using the wt backup command.
+ def backup_table_cursor(self, l):
+ # Remove any previous backup directories.
+ shutil.rmtree(self.dir, True)
+ os.mkdir(self.dir)
+
+ # Build the target list.
+ config = 'target=('
+ for i in range(0, len(self.objs)):
+ if i in l:
+ config += '"' + self.objs[i][0] + '",'
+ config += ')'
+
+ # Open up the backup cursor, and copy the files.
+ cursor = self.session.open_cursor('backup:', None, config)
+ while True:
+ ret = cursor.next()
+ if ret != 0:
+ break
+ #print 'Copy from: ' + cursor.get_key() + ' to ' + self.dir
+ shutil.copy(cursor.get_key(), self.dir)
+ self.assertEqual(ret, wiredtiger.WT_NOTFOUND)
+ cursor.close()
+
+ # Confirm the objects we backed up exist, with correct contents.
+ for i in range(0, len(self.objs)):
+ if i in l:
+ self.compare(self.objs[i][0])
+
+ # Confirm the other objects don't exist.
+ for i in range(0, len(self.objs)):
+ if i not in l:
+ self.confirmPathDoesNotExist(self.objs[i][0])
+
+ # Test backup with targets
+ def test_targets_groups(self):
+ self.populate()
+ self.backup_table_cursor([0,2])
+ self.backup_table_cursor([1,3])
+ self.backup_table_cursor([0,1,2])
+ self.backup_table_cursor([0,1,2,3])
+
+ def test_target_individual(self):
+ self.populate()
+ self.backup_table_cursor([0])
+ self.backup_table_cursor([1])
+ self.backup_table_cursor([2])
+ self.backup_table_cursor([3])
+
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/test/suite/test_checkpoint01.py b/test/suite/test_checkpoint01.py
index 6e1dd2e6385..aa479cb754a 100644
--- a/test/suite/test_checkpoint01.py
+++ b/test/suite/test_checkpoint01.py
@@ -26,7 +26,7 @@
# OTHER DEALINGS IN THE SOFTWARE.
import wiredtiger, wttest
-from helper import key_populate, simple_populate
+from helper import key_populate, complex_populate_lsm, simple_populate
# test_checkpoint01.py
# Checkpoint tests
@@ -325,6 +325,17 @@ class test_checkpoint_last_name(wttest.WiredTigerTestCase):
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
lambda: self.session.checkpoint(conf), msg)
+
+# Check we can't name checkpoints that include LSM tables.
+class test_checkpoint_lsm_name(wttest.WiredTigerTestCase):
+ def test_checkpoint_lsm_name(self):
+ complex_populate_lsm(self,
+ "table:checkpoint", 'type=lsm,key_format=S', 1000)
+ msg = '/LSM trees do not support named checkpoints/'
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: self.session.checkpoint("name=ckpt"), msg)
+
+
class test_checkpoint_empty(wttest.WiredTigerTestCase):
scenarios = [
('file', dict(uri='file:checkpoint')),