summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct8
-rw-r--r--build_posix/Make.subdirs1
-rw-r--r--dist/api_data.py30
-rw-r--r--dist/flags.py6
-rw-r--r--dist/s_string.ok1
-rw-r--r--lang/java/wiredtiger.i17
-rw-r--r--src/btree/bt_discard.c12
-rw-r--r--src/btree/bt_split.c47
-rw-r--r--src/btree/bt_sync.c29
-rw-r--r--src/btree/row_srch.c8
-rw-r--r--src/config/config_def.c29
-rw-r--r--src/conn/conn_api.c10
-rw-r--r--src/docs/tune-system-buffer-cache.dox19
-rw-r--r--src/evict/evict_file.c2
-rw-r--r--src/include/cache.h8
-rw-r--r--src/include/connection.h4
-rw-r--r--src/include/extern.h4
-rw-r--r--src/include/flags.h4
-rw-r--r--src/include/wiredtiger.in25
-rw-r--r--src/os_win/os_open.c11
-rw-r--r--src/schema/schema_stat.c16
-rw-r--r--src/session/session_api.c3
-rw-r--r--src/session/session_dhandle.c41
-rw-r--r--test/bloom/Makefile.am1
-rw-r--r--test/fops/Makefile.am2
-rw-r--r--test/recovery/Makefile.am14
-rw-r--r--test/recovery/recovery.c251
-rw-r--r--test/salvage/Makefile.am1
-rw-r--r--test/suite/test_stat02.py20
-rw-r--r--test/suite/test_stat05.py89
30 files changed, 600 insertions, 113 deletions
diff --git a/SConstruct b/SConstruct
index 70ed6e0220b..6a2b0497d15 100644
--- a/SConstruct
+++ b/SConstruct
@@ -167,6 +167,7 @@ if useTcmalloc:
if conf.CheckCHeader('gperftools/tcmalloc.h'):
wtlibs.append("libtcmalloc_minimal")
conf.env.Append(CPPDEFINES=['HAVE_LIBTCMALLOC'])
+ conf.env.Append(CPPDEFINES=['HAVE_POSIX_MEMALIGN'])
else:
print 'tcmalloc.h must be installed!'
Exit(1)
@@ -406,8 +407,11 @@ Default(t)
t = env.Program("t_huge",
"test/huge/huge.c",
LIBS=[wtlib] + wtlibs)
-#env.Alias("check", env.SmokeTest(t))
-Default(t)
+
+#t = env.Program("t_recovery",
+# "test/recovery/recovery.c",
+# LIBS=[wtlib] + wtlibs)
+#Default(t)
t = env.Program("t_fops",
["test/fops/file.c",
diff --git a/build_posix/Make.subdirs b/build_posix/Make.subdirs
index 0fa9e030659..e2f128a48df 100644
--- a/build_posix/Make.subdirs
+++ b/build_posix/Make.subdirs
@@ -31,5 +31,6 @@ test/fops
test/format
test/huge
test/packing
+test/recovery
test/salvage
test/thread
diff --git a/dist/api_data.py b/dist/api_data.py
index 99e08282e49..9afff74ca71 100644
--- a/dist/api_data.py
+++ b/dist/api_data.py
@@ -594,15 +594,16 @@ wiredtiger_open_common = connection_runtime_config + [
checkpoints''',
type='boolean'),
Config('direct_io', '', r'''
- Use \c O_DIRECT to access files. Options are given as a list,
- such as <code>"direct_io=[data]"</code>. Configuring
- \c direct_io requires care, see @ref
- tuning_system_buffer_cache_direct_io for important warnings.
- Including \c "data" will cause WiredTiger data files to use
- \c O_DIRECT, including \c "log" will cause WiredTiger log files
- to use \c O_DIRECT, and including \c "checkpoint" will cause
- WiredTiger data files opened at a checkpoint (i.e: read only) to
- use \c O_DIRECT''',
+ Use \c O_DIRECT on POSIX systems, and \c FILE_FLAG_NO_BUFFERING on
+ Windows to access files. Options are given as a list, such as
+ <code>"direct_io=[data]"</code>. Configuring \c direct_io requires
+ care, see @ref tuning_system_buffer_cache_direct_io for important
+ warnings. Including \c "data" will cause WiredTiger data files to use
+ direct I/O, including \c "log" will cause WiredTiger log files to use
+ direct I/O, and including \c "checkpoint" will cause WiredTiger data
+ files opened at a checkpoint (i.e: read only) to use direct I/O.
+ \c direct_io should be combined with \c write_through to get the
+ equivalent of \c O_DIRECT on Windows.''',
type='list', choices=['checkpoint', 'data', 'log']),
Config('encryption', '', r'''
configure an encryptor for system wide metadata and logs.
@@ -674,6 +675,17 @@ wiredtiger_open_common = connection_runtime_config + [
@ref tune_durability for more information''',
choices=['dsync', 'fsync', 'none']),
]),
+ Config('write_through', '', r'''
+ Use \c FILE_FLAG_WRITE_THROUGH on Windows to write to files. Ignored
+ on non-Windows systems. Options are given as a list, such as
+ <code>"write_through=[data]"</code>. Configuring \c write_through
+ requires care, see @ref tuning_system_buffer_cache_direct_io for
+ important warnings. Including \c "data" will cause WiredTiger data
+ files to write through cache, including \c "log" will cause WiredTiger
+ log files to write through cache. \c write_through should be combined
+ with \c direct_io to get the equivalent of POSIX \c O_DIRECT on
+ Windows.''',
+ type='list', choices=['data', 'log']),
]
wiredtiger_open = wiredtiger_open_common + [
diff --git a/dist/flags.py b/dist/flags.py
index da677c17389..0e2bad0910c 100644
--- a/dist/flags.py
+++ b/dist/flags.py
@@ -8,12 +8,6 @@ flags = {
###################################################
# Internal routine flag declarations
###################################################
- 'cache_flush' : [
- 'SYNC_CHECKPOINT',
- 'SYNC_CLOSE',
- 'SYNC_DISCARD',
- 'SYNC_WRITE_LEAVES',
- ],
'file_types' : [
'FILE_TYPE_CHECKPOINT',
'FILE_TYPE_DATA',
diff --git a/dist/s_string.ok b/dist/s_string.ok
index 26c0a905b82..c14f4c961e6 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -584,6 +584,7 @@ fopen
fp
fprintf
free'd
+fscanf
fstat
fsync
fsyncs
diff --git a/lang/java/wiredtiger.i b/lang/java/wiredtiger.i
index ae370ec89f5..1326b9ebb90 100644
--- a/lang/java/wiredtiger.i
+++ b/lang/java/wiredtiger.i
@@ -395,15 +395,20 @@ javaCloseHandler(WT_EVENT_HANDLER *handler, WT_SESSION *session,
WT_CURSOR *cursor)
{
int ret;
+ JAVA_CALLBACK *jcb;
WT_UNUSED(handler);
- if (cursor != NULL)
- ret = cursorCloseHandler(NULL, session, (JAVA_CALLBACK *)
- cursor->lang_private);
- else
- ret = closeHandler(NULL, session, (JAVA_CALLBACK *)
- ((WT_SESSION_IMPL *)session)->lang_private);
+ ret = 0;
+ if (cursor != NULL) {
+ if ((jcb = (JAVA_CALLBACK *)cursor->lang_private) != NULL) {
+ ret = cursorCloseHandler(NULL, session, jcb);
+ cursor->lang_private = NULL;
+ }
+ } else if ((jcb = ((WT_SESSION_IMPL *)session)->lang_private) != NULL) {
+ ret = closeHandler(NULL, session, jcb);
+ ((WT_SESSION_IMPL *)session)->lang_private = NULL;
+ }
return (ret);
}
diff --git a/src/btree/bt_discard.c b/src/btree/bt_discard.c
index 67e70d0cdb9..32418a9c063 100644
--- a/src/btree/bt_discard.c
+++ b/src/btree/bt_discard.c
@@ -51,12 +51,14 @@ __wt_page_out(WT_SESSION_IMPL *session, WT_PAGE **pagep)
*pagep = NULL;
/*
- * We should never discard a dirty page, the file's current eviction
- * point or a page queued for LRU eviction.
+ * We should never discard ...
*/
- WT_ASSERT(session, !__wt_page_is_modified(page));
- WT_ASSERT(session, !F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU));
- WT_ASSERT(session, !__wt_fair_islocked(session, &page->page_lock));
+ WT_ASSERT( /* ... a dirty page */
+ session, !__wt_page_is_modified(page));
+ WT_ASSERT( /* ... a page queued for LRU eviction */
+ session, !F_ISSET_ATOMIC(page, WT_PAGE_EVICT_LRU));
+ WT_ASSERT( /* ... a locked page */
+ session, !__wt_fair_islocked(session, &page->page_lock));
#ifdef HAVE_DIAGNOSTIC
{
diff --git a/src/btree/bt_split.c b/src/btree/bt_split.c
index c0c739d68ad..9e45bf10a5c 100644
--- a/src/btree/bt_split.c
+++ b/src/btree/bt_split.c
@@ -796,7 +796,7 @@ __split_multi_inmem_final(WT_PAGE *orig, WT_MULTI *multi)
uint32_t i, slot;
/*
- * We've successfully created new in-memory pages. For error-handling
+ * We successfully created new in-memory pages. For error-handling
* reasons, we've left the update chains referenced by both the original
* and new pages. We're ready to discard the original page, terminate
* the original page's reference to any update list we moved.
@@ -818,6 +818,25 @@ __split_multi_inmem_final(WT_PAGE *orig, WT_MULTI *multi)
}
/*
+ * __split_multi_inmem_fail --
+ * Discard allocated pages after failure.
+ */
+static void
+__split_multi_inmem_fail(WT_SESSION_IMPL *session, WT_REF *ref)
+{
+ /*
+ * We failed creating new in-memory pages. For error-handling reasons,
+ * we've left the update chains referenced by both the original and
+ * new pages. Discard the new pages, setting a flag so the discard code
+ * doesn't discard the updates on the page.
+ */
+ if (ref->page != NULL) {
+ F_SET_ATOMIC(ref->page, WT_PAGE_UPDATE_IGNORE);
+ __wt_free_ref(session, ref->page, ref, true);
+ }
+}
+
+/*
* __wt_multi_to_ref --
* Move a multi-block list into an array of WT_REF structures.
*/
@@ -1555,6 +1574,7 @@ __wt_split_reverse(WT_SESSION_IMPL *session, WT_REF *ref)
int
__wt_split_rewrite(WT_SESSION_IMPL *session, WT_REF *ref)
{
+ WT_DECL_RET;
WT_PAGE *page;
WT_PAGE_MODIFY *mod;
WT_REF new;
@@ -1573,7 +1593,7 @@ __wt_split_rewrite(WT_SESSION_IMPL *session, WT_REF *ref)
* Build the new page.
*/
memset(&new, 0, sizeof(new));
- WT_RET(__split_multi_inmem(session, page, &new, &mod->mod_multi[0]));
+ WT_ERR(__split_multi_inmem(session, page, &new, &mod->mod_multi[0]));
/*
* The rewrite succeeded, we can no longer fail.
@@ -1597,6 +1617,9 @@ __wt_split_rewrite(WT_SESSION_IMPL *session, WT_REF *ref)
WT_PUBLISH(ref->state, WT_REF_MEM);
return (0);
+
+err: __split_multi_inmem_fail(session, &new);
+ return (ret);
}
/*
@@ -1655,24 +1678,8 @@ __split_multi(WT_SESSION_IMPL *session, WT_REF *ref, bool closing)
__wt_page_out(session, &page);
if (0) {
-err: /*
- * A note on error handling: when handling unresolved changes,
- * we create new in-memory pages with those unresolved changes.
- * The problem is the new pages are given references to the
- * original page's update lists, and once all of the pages are
- * created, there's a second pass to remove the updates from the
- * original page. If an error occurs, we can't simply free the
- * newly created pages, that would discard the original page's
- * updates. Set a flag so the discard function doesn't discard
- * the updates on the page.
- */
- for (i = 0; i < new_entries; ++i)
- if (ref_new[i]->page != NULL) {
- F_SET_ATOMIC(
- ref_new[i]->page, WT_PAGE_UPDATE_IGNORE);
- __wt_free_ref(session,
- ref_new[i]->page, ref_new[i], true);
- }
+err: for (i = 0; i < new_entries; ++i)
+ __split_multi_inmem_fail(session, ref_new[i]);
}
__wt_free(session, ref_new);
diff --git a/src/btree/bt_sync.c b/src/btree/bt_sync.c
index 110f9f8fb0c..7395cce11e1 100644
--- a/src/btree/bt_sync.c
+++ b/src/btree/bt_sync.c
@@ -13,7 +13,7 @@
* Flush pages for a specific file.
*/
static int
-__sync_file(WT_SESSION_IMPL *session, int syncop)
+__sync_file(WT_SESSION_IMPL *session, WT_CACHE_OP syncop)
{
struct timespec end, start;
WT_BTREE *btree;
@@ -128,14 +128,21 @@ __sync_file(WT_SESSION_IMPL *session, int syncop)
if (walk == NULL)
break;
- page = walk->page;
- mod = page->modify;
-
/* Skip clean pages. */
- if (!__wt_page_is_modified(page))
+ if (!__wt_page_is_modified(walk->page))
continue;
/*
+ * Take a local reference to the page modify structure
+ * now that we know the page is dirty. It needs to be
+ * done in this order otherwise the page modify
+ * structure could have been created between taking the
+ * reference and checking modified.
+ */
+ page = walk->page;
+ mod = page->modify;
+
+ /*
* Write dirty pages, unless we can be sure they only
* became dirty after the checkpoint started.
*
@@ -169,6 +176,9 @@ __sync_file(WT_SESSION_IMPL *session, int syncop)
WT_ERR(__wt_reconcile(session, walk, NULL, 0));
}
break;
+ case WT_SYNC_CLOSE:
+ case WT_SYNC_DISCARD:
+ WT_ILLEGAL_VALUE_ERR(session);
}
if (WT_VERBOSE_ISSET(session, WT_VERB_CHECKPOINT)) {
@@ -250,7 +260,7 @@ err: /* On error, clear any left-over tree walk. */
* Cache operations.
*/
int
-__wt_cache_op(WT_SESSION_IMPL *session, WT_CKPT *ckptbase, int op)
+__wt_cache_op(WT_SESSION_IMPL *session, WT_CKPT *ckptbase, WT_CACHE_OP op)
{
WT_DECL_RET;
WT_BTREE *btree;
@@ -269,6 +279,9 @@ __wt_cache_op(WT_SESSION_IMPL *session, WT_CKPT *ckptbase, int op)
WT_ASSERT(session, btree->ckpt == NULL);
btree->ckpt = ckptbase;
break;
+ case WT_SYNC_DISCARD:
+ case WT_SYNC_WRITE_LEAVES:
+ break;
}
switch (op) {
@@ -280,7 +293,6 @@ __wt_cache_op(WT_SESSION_IMPL *session, WT_CKPT *ckptbase, int op)
case WT_SYNC_DISCARD:
WT_ERR(__wt_evict_file(session, op));
break;
- WT_ILLEGAL_VALUE_ERR(session);
}
err: switch (op) {
@@ -288,6 +300,9 @@ err: switch (op) {
case WT_SYNC_CLOSE:
btree->ckpt = NULL;
break;
+ case WT_SYNC_DISCARD:
+ case WT_SYNC_WRITE_LEAVES:
+ break;
}
return (ret);
diff --git a/src/btree/row_srch.c b/src/btree/row_srch.c
index 87929d8a457..7b21f1e40bb 100644
--- a/src/btree/row_srch.c
+++ b/src/btree/row_srch.c
@@ -487,7 +487,13 @@ leaf_match: cbt->compare = 0;
return (0);
-err: if (leaf != NULL)
+err: /*
+ * Release the current page if the search started at the root. If the
+ * search didn't start at the root we should never have gone looking
+ * beyond the start page.
+ */
+ WT_ASSERT(session, leaf == NULL || leaf == current);
+ if (leaf == NULL)
WT_TRET(__wt_page_release(session, current, 0));
return (ret);
}
diff --git a/src/config/config_def.c b/src/config/config_def.c
index c8aca15d103..311ddd56b7a 100644
--- a/src/config/config_def.c
+++ b/src/config/config_def.c
@@ -552,6 +552,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open[] = {
"\"split\",\"temporary\",\"transaction\",\"verify\",\"version\","
"\"write\"]",
NULL, 0 },
+ { "write_through", "list",
+ NULL, "choices=[\"data\",\"log\"]",
+ NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@@ -629,6 +632,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_all[] = {
"\"write\"]",
NULL, 0 },
{ "version", "string", NULL, NULL, NULL, 0 },
+ { "write_through", "list",
+ NULL, "choices=[\"data\",\"log\"]",
+ NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@@ -701,6 +707,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_basecfg[] = {
"\"write\"]",
NULL, 0 },
{ "version", "string", NULL, NULL, NULL, 0 },
+ { "write_through", "list",
+ NULL, "choices=[\"data\",\"log\"]",
+ NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@@ -772,6 +781,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_usercfg[] = {
"\"split\",\"temporary\",\"transaction\",\"verify\",\"version\","
"\"write\"]",
NULL, 0 },
+ { "write_through", "list",
+ NULL, "choices=[\"data\",\"log\"]",
+ NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@@ -984,8 +996,8 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"statistics_log=(on_close=0,path=\"WiredTigerStat.%d.%H\","
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
"transaction_sync=(enabled=0,method=fsync),use_environment_priv=0"
- ",verbose=",
- confchk_wiredtiger_open, 35
+ ",verbose=,write_through=",
+ confchk_wiredtiger_open, 36
},
{ "wiredtiger_open_all",
"async=(enabled=0,ops_max=1024,threads=2),buffer_alignment=-1,"
@@ -1005,8 +1017,8 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"statistics_log=(on_close=0,path=\"WiredTigerStat.%d.%H\","
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
"transaction_sync=(enabled=0,method=fsync),use_environment_priv=0"
- ",verbose=,version=(major=0,minor=0)",
- confchk_wiredtiger_open_all, 36
+ ",verbose=,version=(major=0,minor=0),write_through=",
+ confchk_wiredtiger_open_all, 37
},
{ "wiredtiger_open_basecfg",
"async=(enabled=0,ops_max=1024,threads=2),buffer_alignment=-1,"
@@ -1025,8 +1037,8 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"statistics_log=(on_close=0,path=\"WiredTigerStat.%d.%H\","
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
"transaction_sync=(enabled=0,method=fsync),verbose=,"
- "version=(major=0,minor=0)",
- confchk_wiredtiger_open_basecfg, 31
+ "version=(major=0,minor=0),write_through=",
+ confchk_wiredtiger_open_basecfg, 32
},
{ "wiredtiger_open_usercfg",
"async=(enabled=0,ops_max=1024,threads=2),buffer_alignment=-1,"
@@ -1044,8 +1056,9 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",name=,quota=0,reserve=0,size=500MB),statistics=none,"
"statistics_log=(on_close=0,path=\"WiredTigerStat.%d.%H\","
"sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
- "transaction_sync=(enabled=0,method=fsync),verbose=",
- confchk_wiredtiger_open_usercfg, 30
+ "transaction_sync=(enabled=0,method=fsync),verbose=,"
+ "write_through=",
+ confchk_wiredtiger_open_usercfg, 31
},
{ NULL, NULL, NULL, 0 }
};
diff --git a/src/conn/conn_api.c b/src/conn/conn_api.c
index d86b02287f0..c65b74e4e4e 100644
--- a/src/conn/conn_api.c
+++ b/src/conn/conn_api.c
@@ -1947,6 +1947,16 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
goto err;
}
+ WT_ERR(__wt_config_gets(session, cfg, "write_through", &cval));
+ for (ft = file_types; ft->name != NULL; ft++) {
+ ret = __wt_config_subgets(session, &cval, ft->name, &sval);
+ if (ret == 0) {
+ if (sval.val)
+ FLD_SET(conn->write_through, ft->flag);
+ } else if (ret != WT_NOTFOUND)
+ goto err;
+ }
+
/*
* If buffer alignment is not configured, use zero unless direct I/O is
* also configured, in which case use the build-time default.
diff --git a/src/docs/tune-system-buffer-cache.dox b/src/docs/tune-system-buffer-cache.dox
index 32b92d0df39..1919c66997a 100644
--- a/src/docs/tune-system-buffer-cache.dox
+++ b/src/docs/tune-system-buffer-cache.dox
@@ -17,6 +17,17 @@ for WiredTiger's data files:
@snippet ex_all.c Configure direct_io for data files
+On Windows, the "direct_io" configuration string controls whether the operating
+system cache is used to buffer reads, and writes to disk, i.e.,
+FILE_FLAG_NO_BUFFERING. When "direct_io" is off, Windows will use free RAM to
+cache access to files. This may had adverse effects because Windows may page out
+the WiredTiger buffer cache instead of its file cache. An additional
+configuration string "write_through" controls whether the disk is allowed to
+cache the writes. Enabling this flag increases write latency as the drive must
+ensure all writes are persisted to disk, but it ensures write durability. To get
+the equivalent of \c O_DIRECT on Windows, "direct_io", and "write_through" must
+be both set.
+
Direct I/O implies a writing thread waits for the write to complete
(which is a slower operation than writing into the system buffer cache),
and configuring direct I/O is likely to decrease overall application
@@ -36,11 +47,11 @@ should also specify \c O_DIRECT when configuring their file access. A
standard Linux system utility that supports \c O_DIRECT is the \c dd
utility, when using the \c iflag=direct command-line option.
-Additionally, many Linux systems require specific alignment for buffers
-used for I/O when direct I/O is configured, and using the wrong
+Additionally, Windows, and many Linux systems require specific alignment for
+buffers used for I/O when direct I/O is configured, and using the wrong
alignment can cause data loss or corruption. When direct I/O is
-configured on Linux systems, WiredTiger aligns I/O buffers to 4KB; if
-different alignment is required by your system, the \c buffer_alignment
+configured on Windows, and Linux systems, WiredTiger aligns I/O buffers to 4KB;
+if different alignment is required by your system, the \c buffer_alignment
configuration to the wiredtiger_open call should be configured to the
correct value.
diff --git a/src/evict/evict_file.c b/src/evict/evict_file.c
index 448de57d88e..043fbf6bbeb 100644
--- a/src/evict/evict_file.c
+++ b/src/evict/evict_file.c
@@ -13,7 +13,7 @@
* Discard pages for a specific file.
*/
int
-__wt_evict_file(WT_SESSION_IMPL *session, int syncop)
+__wt_evict_file(WT_SESSION_IMPL *session, WT_CACHE_OP syncop)
{
WT_DECL_RET;
WT_PAGE *page;
diff --git a/src/include/cache.h b/src/include/cache.h
index caf8996e68b..d8a3829863f 100644
--- a/src/include/cache.h
+++ b/src/include/cache.h
@@ -39,6 +39,14 @@ struct __wt_evict_worker {
uint32_t flags;
};
+/* Cache operations. */
+typedef enum __wt_cache_op {
+ WT_SYNC_CHECKPOINT,
+ WT_SYNC_CLOSE,
+ WT_SYNC_DISCARD,
+ WT_SYNC_WRITE_LEAVES
+} WT_CACHE_OP;
+
/*
* WiredTiger cache structure.
*/
diff --git a/src/include/connection.h b/src/include/connection.h
index a585e08ef1a..35a83d7c50f 100644
--- a/src/include/connection.h
+++ b/src/include/connection.h
@@ -412,7 +412,9 @@ struct __wt_connection_impl {
wt_off_t data_extend_len; /* file_extend data length */
wt_off_t log_extend_len; /* file_extend log length */
- uint32_t direct_io; /* O_DIRECT file type flags */
+ /* O_DIRECT/FILE_FLAG_NO_BUFFERING file type flags */
+ uint32_t direct_io;
+ uint32_t write_through; /* FILE_FLAG_WRITE_THROUGH type flags */
bool mmap; /* mmap configuration */
uint32_t verbose;
diff --git a/src/include/extern.h b/src/include/extern.h
index 75064c56334..032b94b7040 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -159,7 +159,7 @@ extern int __wt_split_reverse(WT_SESSION_IMPL *session, WT_REF *ref);
extern int __wt_split_rewrite(WT_SESSION_IMPL *session, WT_REF *ref);
extern int __wt_split_multi(WT_SESSION_IMPL *session, WT_REF *ref, int closing);
extern int __wt_btree_stat_init(WT_SESSION_IMPL *session, WT_CURSOR_STAT *cst);
-extern int __wt_cache_op(WT_SESSION_IMPL *session, WT_CKPT *ckptbase, int op);
+extern int __wt_cache_op(WT_SESSION_IMPL *session, WT_CKPT *ckptbase, WT_CACHE_OP op);
extern int __wt_upgrade(WT_SESSION_IMPL *session, const char *cfg[]);
extern int __wt_verify(WT_SESSION_IMPL *session, const char *cfg[]);
extern int __wt_verify_dsk_image(WT_SESSION_IMPL *session, const char *tag, const WT_PAGE_HEADER *dsk, size_t size, bool empty_page_ok);
@@ -317,7 +317,7 @@ extern void __wt_curtable_set_key(WT_CURSOR *cursor, ...);
extern void __wt_curtable_set_value(WT_CURSOR *cursor, ...);
extern int __wt_table_range_truncate(WT_CURSOR_TABLE *start, WT_CURSOR_TABLE *stop);
extern int __wt_curtable_open(WT_SESSION_IMPL *session, const char *uri, const char *cfg[], WT_CURSOR **cursorp);
-extern int __wt_evict_file(WT_SESSION_IMPL *session, int syncop);
+extern int __wt_evict_file(WT_SESSION_IMPL *session, WT_CACHE_OP syncop);
extern void __wt_evict_list_clear_page(WT_SESSION_IMPL *session, WT_REF *ref);
extern int __wt_evict_server_wake(WT_SESSION_IMPL *session);
extern int __wt_evict_create(WT_SESSION_IMPL *session);
diff --git a/src/include/flags.h b/src/include/flags.h
index 99b6f1c483f..95fe18b9ecb 100644
--- a/src/include/flags.h
+++ b/src/include/flags.h
@@ -64,10 +64,6 @@
#define WT_SESSION_NO_SCHEMA_LOCK 0x00008000
#define WT_SESSION_QUIET_CORRUPT_FILE 0x00010000
#define WT_SESSION_SERVER_ASYNC 0x00020000
-#define WT_SYNC_CHECKPOINT 0x00000001
-#define WT_SYNC_CLOSE 0x00000002
-#define WT_SYNC_DISCARD 0x00000004
-#define WT_SYNC_WRITE_LEAVES 0x00000008
#define WT_TXN_LOG_CKPT_CLEANUP 0x00000001
#define WT_TXN_LOG_CKPT_PREPARE 0x00000002
#define WT_TXN_LOG_CKPT_START 0x00000004
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index 037399625ea..044611d655e 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -2130,15 +2130,17 @@ struct __wt_connection {
* true.}
* @config{create, create the database if it does not exist., a boolean flag;
* default \c false.}
- * @config{direct_io, Use \c O_DIRECT to access files. Options are given as a
+ * @config{direct_io, Use \c O_DIRECT on POSIX systems\, and \c
+ * FILE_FLAG_NO_BUFFERING on Windows to access files. Options are given as a
* list\, such as <code>"direct_io=[data]"</code>. Configuring \c direct_io
* requires care\, see @ref tuning_system_buffer_cache_direct_io for important
- * warnings. Including \c "data" will cause WiredTiger data files to use \c
- * O_DIRECT\, including \c "log" will cause WiredTiger log files to use \c
- * O_DIRECT\, and including \c "checkpoint" will cause WiredTiger data files
- * opened at a checkpoint (i.e: read only) to use \c O_DIRECT., a list\, with
- * values chosen from the following options: \c "checkpoint"\, \c "data"\, \c
- * "log"; default empty.}
+ * warnings. Including \c "data" will cause WiredTiger data files to use direct
+ * I/O\, including \c "log" will cause WiredTiger log files to use direct I/O\,
+ * and including \c "checkpoint" will cause WiredTiger data files opened at a
+ * checkpoint (i.e: read only) to use direct I/O. \c direct_io should be
+ * combined with \c write_through to get the equivalent of \c O_DIRECT on
+ * Windows., a list\, with values chosen from the following options: \c
+ * "checkpoint"\, \c "data"\, \c "log"; default empty.}
* @config{encryption = (, configure an encryptor for system wide metadata and
* logs. If a system wide encryptor is set\, it is also used for encrypting
* data files and tables\, unless encryption configuration is explicitly set for
@@ -2339,6 +2341,15 @@ struct __wt_connection {
* "overflow"\, \c "read"\, \c "reconcile"\, \c "recovery"\, \c "salvage"\, \c
* "shared_cache"\, \c "split"\, \c "temporary"\, \c "transaction"\, \c
* "verify"\, \c "version"\, \c "write"; default empty.}
+ * @config{write_through, Use \c FILE_FLAG_WRITE_THROUGH on Windows to write to
+ * files. Ignored on non-Windows systems. Options are given as a list\, such
+ * as <code>"write_through=[data]"</code>. Configuring \c write_through requires
+ * care\, see @ref tuning_system_buffer_cache_direct_io for important warnings.
+ * Including \c "data" will cause WiredTiger data files to write through cache\,
+ * including \c "log" will cause WiredTiger log files to write through cache.
+ * \c write_through should be combined with \c direct_io to get the equivalent
+ * of POSIX \c O_DIRECT on Windows., a list\, with values chosen from the
+ * following options: \c "data"\, \c "log"; default empty.}
* @configend
* Additionally, if files named \c WiredTiger.config or \c WiredTiger.basecfg
* appear in the WiredTiger home directory, they are read for configuration
diff --git a/src/os_win/os_open.c b/src/os_win/os_open.c
index c7b30408e63..c3106763452 100644
--- a/src/os_win/os_open.c
+++ b/src/os_win/os_open.c
@@ -78,11 +78,20 @@ __wt_open(WT_SESSION_IMPL *session,
} else
dwCreationDisposition = OPEN_EXISTING;
+ /*
+ * direct_io means no OS file caching. This requires aligned buffer
+ * allocations like O_DIRECT.
+ */
if (dio_type && FLD_ISSET(conn->direct_io, dio_type)) {
- f |= FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH;
+ f |= FILE_FLAG_NO_BUFFERING;
direct_io = true;
}
+ /* FILE_FLAG_WRITE_THROUGH does not require aligned buffers */
+ if (dio_type && FLD_ISSET(conn->write_through, dio_type)) {
+ f |= FILE_FLAG_WRITE_THROUGH;
+ }
+
if (dio_type == WT_FILE_TYPE_LOG &&
FLD_ISSET(conn->txn_logsync, WT_LOG_DSYNC)) {
f |= FILE_FLAG_WRITE_THROUGH;
diff --git a/src/schema/schema_stat.c b/src/schema/schema_stat.c
index 88f92b71599..d73d66cd399 100644
--- a/src/schema/schema_stat.c
+++ b/src/schema/schema_stat.c
@@ -96,15 +96,17 @@ __curstat_size_only(WT_SESSION_IMPL *session,
* are concurrent schema level operations (for example drop). That is
* fine - failing here results in falling back to the slow path of
* opening the handle.
+ * !!! Deliberately discard the return code from a failed call - the
+ * error is flagged by not setting fast to true.
*/
- WT_ERR(__wt_filesize_name(session, namebuf.data, true, &filesize));
+ if (__wt_filesize_name(session, namebuf.data, true, &filesize) == 0) {
+ /* Setup and populate the statistics structure */
+ __wt_stat_dsrc_init_single(&cst->u.dsrc_stats);
+ cst->u.dsrc_stats.block_size = filesize;
+ __wt_curstat_dsrc_final(cst);
- /* Setup and populate the statistics structure */
- __wt_stat_dsrc_init_single(&cst->u.dsrc_stats);
- cst->u.dsrc_stats.block_size = filesize;
- __wt_curstat_dsrc_final(cst);
-
- *was_fast = true;
+ *was_fast = true;
+ }
err: __wt_free(session, tableconf);
__wt_buf_free(session, &namebuf);
diff --git a/src/session/session_api.c b/src/session/session_api.c
index 2045329b8ff..ed0e016dcb2 100644
--- a/src/session/session_api.c
+++ b/src/session/session_api.c
@@ -147,7 +147,8 @@ __session_close(WT_SESSION *wt_session, const char *config)
* Notify the user that we are closing the cursor handle
* via the registered close callback.
*/
- if (session->event_handler->handle_close != NULL)
+ if (session->event_handler->handle_close != NULL &&
+ !WT_STREQ(cursor->uri, WT_LAS_URI))
WT_TRET(session->event_handler->handle_close(
session->event_handler, wt_session, cursor));
WT_TRET(cursor->close(cursor));
diff --git a/src/session/session_dhandle.c b/src/session/session_dhandle.c
index 346e9c0ab38..ec2f0921ef2 100644
--- a/src/session/session_dhandle.c
+++ b/src/session/session_dhandle.c
@@ -132,6 +132,25 @@ __wt_session_lock_dhandle(
want_exclusive = LF_ISSET(WT_DHANDLE_EXCLUSIVE);
/*
+ * If this session already has exclusive access to the handle, there is
+ * no point trying to lock it again.
+ *
+ * This should only happen if a checkpoint handle is locked multiple
+ * times during a checkpoint operation, or the handle is already open
+ * without any special flags. In particular, it must fail if
+ * attempting to checkpoint a handle opened for a bulk load, even in
+ * the same session.
+ */
+ if (dhandle->excl_session == session) {
+ if (!LF_ISSET(WT_DHANDLE_LOCK_ONLY) &&
+ (!F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ F_ISSET(btree, WT_BTREE_SPECIAL_FLAGS)))
+ return (EBUSY);
+ ++dhandle->excl_ref;
+ return (0);
+ }
+
+ /*
* Check that the handle is open. We've already incremented
* the reference count, so once the handle is open it won't be
* closed by another thread.
@@ -207,6 +226,11 @@ __wt_session_lock_dhandle(
/* We have an exclusive lock, we're done. */
F_SET(dhandle, WT_DHANDLE_EXCLUSIVE);
+ WT_ASSERT(session,
+ dhandle->excl_session == NULL &&
+ dhandle->excl_ref == 0);
+ dhandle->excl_session = session;
+ dhandle->excl_ref = 1;
WT_ASSERT(session, !F_ISSET(dhandle, WT_DHANDLE_DEAD));
return (0);
}
@@ -454,19 +478,10 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
WT_RET(__session_get_dhandle(session, uri, checkpoint));
dhandle = session->dhandle;
- /*
- * If this session already owns the handle, increase
- * the owner ref count.
- */
- if (dhandle->excl_session == session)
- dhandle->excl_ref++;
- else {
- /* Try to lock the handle. */
- WT_RET(__wt_session_lock_dhandle(
- session, flags, &is_dead));
- if (is_dead)
- continue;
- }
+ /* Try to lock the handle. */
+ WT_RET(__wt_session_lock_dhandle(session, flags, &is_dead));
+ if (is_dead)
+ continue;
/* If the handle is open in the mode we want, we're done. */
if (LF_ISSET(WT_DHANDLE_LOCK_ONLY) ||
diff --git a/test/bloom/Makefile.am b/test/bloom/Makefile.am
index f03c41c77ff..86d87c70071 100644
--- a/test/bloom/Makefile.am
+++ b/test/bloom/Makefile.am
@@ -8,6 +8,7 @@ t_LDFLAGS = -static
# Run this during a "make check" smoke test.
TESTS = $(noinst_PROGRAMS)
+LOG_COMPILER = $(TEST_WRAPPER)
clean-local:
rm -rf WiredTiger* *.core __*
diff --git a/test/fops/Makefile.am b/test/fops/Makefile.am
index 9ccbbbfaac5..a4fa7175f1b 100644
--- a/test/fops/Makefile.am
+++ b/test/fops/Makefile.am
@@ -7,7 +7,9 @@ t_LDADD = $(top_builddir)/libwiredtiger.la
t_SOURCES = thread.h file.c fops.c t.c
t_LDFLAGS = -static
+# Run this during a "make check" smoke test.
TESTS = $(noinst_PROGRAMS)
+LOG_COMPILER = $(TEST_WRAPPER)
clean-local:
rm -rf WT_TEST *.core
diff --git a/test/recovery/Makefile.am b/test/recovery/Makefile.am
new file mode 100644
index 00000000000..60f237dad10
--- /dev/null
+++ b/test/recovery/Makefile.am
@@ -0,0 +1,14 @@
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/test/utility
+
+noinst_PROGRAMS = t
+t_SOURCES = recovery.c
+t_LDADD = $(top_builddir)/libwiredtiger.la
+t_LDFLAGS = -static
+
+# Run this during a "make check" smoke test.
+TESTS = $(noinst_PROGRAMS)
+LOG_COMPILER = $(TEST_WRAPPER)
+
+clean-local:
+ rm -rf WiredTiger* *.core __*
diff --git a/test/recovery/recovery.c b/test/recovery/recovery.c
new file mode 100644
index 00000000000..b888973d048
--- /dev/null
+++ b/test/recovery/recovery.c
@@ -0,0 +1,251 @@
+/*-
+ * Public Domain 2014-2015 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 <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include <wiredtiger.h>
+
+#include "test_util.i"
+
+static char home[512]; /* Program working dir */
+static const char *progname; /* Program name */
+static const char *uri = "table:main";
+
+#define RECORDS_FILE "records"
+
+#define ENV_CONFIG \
+ "create,log=(file_max=10M,archive=false,enabled)," \
+ "transaction_sync=(enabled,method=none)"
+#define ENV_CONFIG_REC "log=(recover=on)"
+#define MAX_VAL 4096
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-h dir]\n", progname);
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Child process creates the database and table, and then writes data into
+ * the table until it is killed by the parent.
+ */
+static void
+fill_db()
+{
+ FILE *fp;
+ WT_CONNECTION *conn;
+ WT_CURSOR *cursor;
+ WT_ITEM data;
+ WT_RAND_STATE rnd;
+ WT_SESSION *session;
+ uint64_t i;
+ int ret;
+ uint8_t buf[MAX_VAL];
+
+ __wt_random_init(&rnd);
+ memset(buf, 0, sizeof(buf));
+ /*
+ * Initialize the first 25% to random values. Leave a bunch of data
+ * space at the end to emphasize zero data.
+ */
+ for (i = 0; i < MAX_VAL/4; i++)
+ buf[i] = (uint8_t)__wt_random(&rnd);
+
+ /*
+ * Run in the home directory so that the records file is in there too.
+ */
+ chdir(home);
+ if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG, &conn)) != 0)
+ testutil_die(ret, "wiredtiger_open");
+ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
+ testutil_die(ret, "WT_CONNECTION:open_session");
+ if ((ret = session->create(session,
+ uri, "key_format=Q,value_format=u")) != 0)
+ testutil_die(ret, "WT_SESSION.create: %s", uri);
+ if ((ret =
+ session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0)
+ testutil_die(ret, "WT_SESSION.open_cursor: %s", uri);
+
+ /*
+ * Keep a separate file with the records we wrote for checking.
+ */
+ (void)unlink(RECORDS_FILE);
+ if ((fp = fopen(RECORDS_FILE, "w")) == NULL)
+ testutil_die(errno, "fopen");
+ /*
+ * Set to no buffering.
+ */
+ setvbuf(fp, NULL, _IONBF, 0);
+
+ /*
+ * Write data into the table until we are killed by the parent.
+ * The data in the buffer is already set to random content.
+ */
+ data.data = buf;
+ for (i = 0;; ++i) {
+ data.size = __wt_random(&rnd) % MAX_VAL;
+ cursor->set_key(cursor, i);
+ cursor->set_value(cursor, &data);
+ if ((ret = cursor->insert(cursor)) != 0)
+ testutil_die(ret, "WT_CURSOR.insert");
+ /*
+ * Save the key separately for checking later.
+ */
+ if (fprintf(fp, "%" PRIu64 "\n", i) == -1)
+ testutil_die(errno, "fprintf");
+ if (i % 5000)
+ __wt_yield();
+ }
+}
+
+extern int __wt_optind;
+extern char *__wt_optarg;
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ WT_CONNECTION *conn;
+ WT_CURSOR *cursor;
+ WT_SESSION *session;
+ WT_RAND_STATE rnd;
+ uint64_t key;
+ uint32_t absent, count, timeout;
+ int ch, status, ret;
+ pid_t pid;
+ char *working_dir;
+
+ if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+
+ working_dir = NULL;
+ timeout = 10;
+ while ((ch = __wt_getopt(progname, argc, argv, "h:t:")) != EOF)
+ switch (ch) {
+ case 'h':
+ working_dir = __wt_optarg;
+ break;
+ case 't':
+ timeout = (uint32_t)atoi(__wt_optarg);
+ break;
+ default:
+ usage();
+ }
+ argc -= __wt_optind;
+ argv += __wt_optind;
+ if (argc != 0)
+ usage();
+
+ testutil_work_dir_from_path(home, 512, working_dir);
+ testutil_make_work_dir(home);
+
+ /*
+ * Fork a child to insert as many items. We will then randomly
+ * kill the child, run recovery and make sure all items we wrote
+ * exist after recovery runs.
+ */
+ if ((pid = fork()) < 0)
+ testutil_die(errno, "fork");
+
+ if (pid == 0) { /* child */
+ fill_db();
+ return (EXIT_SUCCESS);
+ }
+
+ /* parent */
+ __wt_random_init(&rnd);
+ /* Sleep for the configured amount of time before killing the child. */
+ printf("Parent: sleep %" PRIu32 " seconds, then kill child\n", timeout);
+ sleep(timeout);
+
+ /*
+ * !!! It should be plenty long enough to make sure more than one
+ * log file exists. If wanted, that check would be added here.
+ */
+ printf("Kill child\n");
+ if (kill(pid, SIGKILL) != 0)
+ testutil_die(errno, "kill");
+ waitpid(pid, &status, 0);
+
+ /*
+ * !!! If we wanted to take a copy of the directory before recovery,
+ * this is the place to do it.
+ */
+ chdir(home);
+ printf("Open database, run recovery and verify content\n");
+ if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG_REC, &conn)) != 0)
+ testutil_die(ret, "wiredtiger_open");
+ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
+ testutil_die(ret, "WT_CONNECTION:open_session");
+ if ((ret =
+ session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0)
+ testutil_die(ret, "WT_SESSION.open_cursor: %s", uri);
+
+ if ((fp = fopen(RECORDS_FILE, "r")) == NULL)
+ testutil_die(errno, "fopen");
+
+ /*
+ * For every key in the saved file, verify that the key exists
+ * in the table after recovery. Since we did write-no-sync, we
+ * expect every key to have been recovered.
+ */
+ for (absent = count = 0;; ++count) {
+ ret = fscanf(fp, "%" SCNu64 "\n", &key);
+ if (ret != EOF && ret != 1)
+ testutil_die(errno, "fscanf");
+ if (ret == EOF)
+ break;
+ cursor->set_key(cursor, key);
+ if ((ret = cursor->search(cursor)) != 0) {
+ if (ret != WT_NOTFOUND)
+ testutil_die(ret, "search");
+ printf("no record with key %" PRIu64 "\n", key);
+ ++absent;
+ }
+ }
+ fclose(fp);
+ if ((ret = conn->close(conn, NULL)) != 0)
+ testutil_die(ret, "WT_CONNECTION:close");
+ if (absent) {
+ printf("%u record(s) absent from %u\n", absent, count);
+ return (EXIT_FAILURE);
+ }
+ printf("%u records verified\n", count);
+ return (EXIT_SUCCESS);
+}
diff --git a/test/salvage/Makefile.am b/test/salvage/Makefile.am
index 95b3785aa63..3e686dd2951 100644
--- a/test/salvage/Makefile.am
+++ b/test/salvage/Makefile.am
@@ -8,6 +8,7 @@ t_LDFLAGS = -static
# Run this during a "make check" smoke test.
TESTS = $(noinst_PROGRAMS)
+LOG_COMPILER = $(TEST_WRAPPER)
clean-local:
rm -rf WiredTiger* *.core __*
diff --git a/test/suite/test_stat02.py b/test/suite/test_stat02.py
index c2f2a69b046..8643d700793 100644
--- a/test/suite/test_stat02.py
+++ b/test/suite/test_stat02.py
@@ -37,20 +37,24 @@ from helper import complex_populate, complex_populate_lsm, simple_populate
class test_stat_cursor_config(wttest.WiredTigerTestCase):
pfx = 'test_stat_cursor_config'
uri = [
- ('1', dict(uri='file:' + pfx, pop=simple_populate)),
- ('2', dict(uri='table:' + pfx, pop=simple_populate)),
- ('3', dict(uri='table:' + pfx, pop=complex_populate)),
- ('4', dict(uri='table:' + pfx, pop=complex_populate_lsm))
+ ('file', dict(uri='file:' + pfx, pop=simple_populate, cfg='')),
+ ('table', dict(uri='table:' + pfx, pop=simple_populate, cfg='')),
+ ('table-lsm',
+ dict(uri='table:' + pfx, pop=simple_populate, cfg=',type=lsm')),
+ ('complex', dict(uri='table:' + pfx, pop=complex_populate, cfg='')),
+ ('complex-lsm',
+ dict(uri='table:' + pfx, pop=complex_populate_lsm, cfg=''))
]
data_config = [
('none', dict(data_config='none', ok=[])),
- ( 'all', dict(data_config='all', ok=['empty', 'fast', 'all'])),
- ('fast', dict(data_config='fast', ok=['empty', 'fast']))
+ ( 'all', dict(data_config='all', ok=['empty', 'fast', 'all', 'size'])),
+ ('fast', dict(data_config='fast', ok=['empty', 'fast', 'size']))
]
cursor_config = [
('empty', dict(cursor_config='empty')),
( 'all', dict(cursor_config='all')),
- ('fast', dict(cursor_config='fast'))
+ ('fast', dict(cursor_config='fast')),
+ ('size', dict(cursor_config='size'))
]
scenarios = number_scenarios(
@@ -67,7 +71,7 @@ class test_stat_cursor_config(wttest.WiredTigerTestCase):
# For each database/cursor configuration, confirm the right combinations
# succeed or fail.
def test_stat_cursor_config(self):
- self.pop(self, self.uri, 'key_format=S', 100)
+ self.pop(self, self.uri, 'key_format=S' + self.cfg, 100)
config = 'statistics=('
if self.cursor_config != 'empty':
config = config + self.cursor_config
diff --git a/test/suite/test_stat05.py b/test/suite/test_stat05.py
new file mode 100644
index 00000000000..9c8fa48cc79
--- /dev/null
+++ b/test/suite/test_stat05.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-2015 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.
+
+import itertools, wiredtiger, wttest
+from suite_subprocess import suite_subprocess
+from wtscenario import multiply_scenarios, number_scenarios
+from wiredtiger import stat
+from helper import complex_populate, complex_populate_lsm, simple_populate
+from helper import complex_value_populate, key_populate, value_populate
+
+# test_stat05.py
+# Statistics cursor using size only
+class test_stat_cursor_config(wttest.WiredTigerTestCase):
+ pfx = 'test_stat_cursor_size'
+ uri = [
+ ('file', dict(uri='file:' + pfx, pop=simple_populate, cfg='')),
+ ('table', dict(uri='table:' + pfx, pop=simple_populate, cfg='')),
+ ('table-lsm', dict(uri='table:' + pfx, pop=simple_populate,
+ cfg=',type=lsm,lsm=(chunk_size=1MB,merge_min=2)')),
+ ('complex', dict(uri='table:' + pfx, pop=complex_populate, cfg='')),
+ ('complex-lsm',
+ dict(uri='table:' + pfx, pop=complex_populate_lsm,
+ cfg=',lsm=(chunk_size=1MB,merge_min=2)')),
+ ]
+
+ scenarios = number_scenarios(uri)
+
+ # Override WiredTigerTestCase to enable statistics
+ def setUpConnectionOpen(self, dir):
+ conn = wiredtiger.wiredtiger_open(dir,
+ 'create,' +
+ 'statistics=(fast),' +
+ 'error_prefix="%s: "' % self.shortid())
+ return conn
+
+ def openAndWalkStatCursor(self):
+ c = self.session.open_cursor(
+ 'statistics:' + self.uri, None, 'statistics=(size)')
+ count = 0
+ while c.next() == 0:
+ count += 1
+ c.close()
+
+
+ # Open a size-only statistics cursor on various table types. Ensure that
+ # the cursor open succeeds. Insert enough data that LSM tables to need to
+ # switch and merge.
+ def test_stat_cursor_size(self):
+ self.pop(self, self.uri, 'key_format=S' + self.cfg, 100)
+ self.openAndWalkStatCursor()
+ cursor = self.session.open_cursor(self.uri, None)
+ for i in range(100, 40000 + 1):
+ if i % 100 == 0:
+ self.openAndWalkStatCursor()
+ if self.pop == simple_populate:
+ cursor[key_populate(cursor, i)] = value_populate(cursor, i)
+ else:
+ v = complex_value_populate(cursor, i)
+ cursor[key_populate(cursor, i)] = (v[0], v[1], v[2], v[3])
+ cursor.close()
+ self.openAndWalkStatCursor()
+
+if __name__ == '__main__':
+ wttest.run()