summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexander.gorrod@mongodb.com>2017-06-29 11:38:10 +1000
committerAlex Gorrod <alexander.gorrod@mongodb.com>2017-06-29 11:40:58 +1000
commit690302a49b61d5be3f4dcc285921eb362648055c (patch)
treed0bac8380e27a4ed7a38b9c82fc2996af87b2845
parenta72d5e357fc0e8b31e705cba539762cd79093773 (diff)
downloadmongo-690302a49b61d5be3f4dcc285921eb362648055c.tar.gz
Import wiredtiger: ff10db881161bbd1bc23e40ac385ff0de18f68ff from branch mongodb-3.6
ref: f59321a372..ff10db8811 for: 3.5.10 WT-1939 Improve error handling in example code WT-3181 Add support for MongoDB timestamps WT-3342 Create a new WiredTiger 2.9.2 release WT-3363 Add test case to detect when drops may be blocked by checkpoints WT-3373 Access violation due to a bug in internal page splitting WT-3385 Coverity 1376471: __wt_txn_parse_timestamp() memory overrun WT-3391 Create a WiredTiger 2.9.3 release. WT-3392 Coverity analysis complaints WT-3393 Missing barrier when a WT_UPDATE structure is appended to list. Also manually update wiredtiger_config.h pre-generated files in MongoDB source tree
-rw-r--r--src/third_party/wiredtiger/NEWS24
-rw-r--r--src/third_party/wiredtiger/README6
-rw-r--r--src/third_party/wiredtiger/RELEASE_INFO6
-rw-r--r--src/third_party/wiredtiger/SConstruct13
-rw-r--r--src/third_party/wiredtiger/build_darwin/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/build_freebsd/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/build_linux/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/build_openbsd/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/build_posix/Make.subdirs8
-rw-r--r--src/third_party/wiredtiger/build_posix/aclocal/options.m49
-rw-r--r--src/third_party/wiredtiger/build_posix/aclocal/version-set.m410
-rw-r--r--src/third_party/wiredtiger/build_posix/aclocal/version.m42
-rw-r--r--src/third_party/wiredtiger/build_solaris/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/build_win/wiredtiger_config.h6
-rw-r--r--src/third_party/wiredtiger/dist/api_data.py44
-rw-r--r--src/third_party/wiredtiger/dist/filelist1
-rw-r--r--src/third_party/wiredtiger/dist/flags.py3
-rw-r--r--src/third_party/wiredtiger/dist/package/wiredtiger.spec2
-rw-r--r--src/third_party/wiredtiger/dist/s_string.ok4
-rw-r--r--src/third_party/wiredtiger/examples/c/Makefile.am5
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_access.c59
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_all.c725
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_async.c62
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_backup.c133
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_call_center.c110
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_config_parse.c101
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_cursor.c126
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_data_source.c132
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_encrypt.c157
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_event_handler.c42
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_extending.c44
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_extractor.c132
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_file_system.c25
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_hello.c38
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_log.c198
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_pack.c48
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_process.c39
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_schema.c318
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_smoke.c67
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_stat.c196
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_sync.c98
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_thread.c66
-rw-r--r--src/third_party/wiredtiger/import.data2
-rw-r--r--src/third_party/wiredtiger/lang/java/java_doc.i3
-rw-r--r--src/third_party/wiredtiger/lang/python/wiredtiger.i13
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_curnext.c8
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_curprev.c8
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_delete.c9
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_ovfl.c4
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_read.c85
-rw-r--r--src/third_party/wiredtiger/src/btree/row_modify.c2
-rw-r--r--src/third_party/wiredtiger/src/cache/cache_las.c21
-rw-r--r--src/third_party/wiredtiger/src/config/config.c50
-rw-r--r--src/third_party/wiredtiger/src/config/config_def.c160
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_api.c85
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_open.c20
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_sweep.c4
-rw-r--r--src/third_party/wiredtiger/src/cursor/cur_join.c4
-rw-r--r--src/third_party/wiredtiger/src/docs/top/main.dox8
-rw-r--r--src/third_party/wiredtiger/src/docs/transactions.dox44
-rw-r--r--src/third_party/wiredtiger/src/evict/evict_lru.c10
-rw-r--r--src/third_party/wiredtiger/src/evict/evict_page.c3
-rw-r--r--src/third_party/wiredtiger/src/include/btmem.h22
-rw-r--r--src/third_party/wiredtiger/src/include/btree.h2
-rw-r--r--src/third_party/wiredtiger/src/include/btree.i3
-rw-r--r--src/third_party/wiredtiger/src/include/cache.h2
-rw-r--r--src/third_party/wiredtiger/src/include/config.h79
-rw-r--r--src/third_party/wiredtiger/src/include/connection.h6
-rw-r--r--src/third_party/wiredtiger/src/include/extern.h8
-rw-r--r--src/third_party/wiredtiger/src/include/flags.h1
-rw-r--r--src/third_party/wiredtiger/src/include/lsm.h8
-rw-r--r--src/third_party/wiredtiger/src/include/misc.h18
-rw-r--r--src/third_party/wiredtiger/src/include/serial.i4
-rw-r--r--src/third_party/wiredtiger/src/include/session.h1
-rw-r--r--src/third_party/wiredtiger/src/include/txn.h46
-rw-r--r--src/third_party/wiredtiger/src/include/txn.i177
-rw-r--r--src/third_party/wiredtiger/src/include/wiredtiger.in71
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_cursor.c8
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_manager.c6
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_merge.c4
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_tree.c22
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_work_unit.c4
-rw-r--r--src/third_party/wiredtiger/src/reconcile/rec_write.c108
-rw-r--r--src/third_party/wiredtiger/src/session/session_api.c41
-rw-r--r--src/third_party/wiredtiger/src/txn/txn.c289
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_ckpt.c53
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_ext.c2
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_log.c2
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_nsnap.c23
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_timestamp.c302
-rw-r--r--src/third_party/wiredtiger/test/checkpoint/checkpointer.c20
-rwxr-xr-xsrc/third_party/wiredtiger/test/checkpoint/smoke.sh10
-rw-r--r--src/third_party/wiredtiger/test/checkpoint/test_checkpoint.c17
-rw-r--r--src/third_party/wiredtiger/test/checkpoint/test_checkpoint.h2
-rw-r--r--src/third_party/wiredtiger/test/checkpoint/workers.c21
-rw-r--r--src/third_party/wiredtiger/test/csuite/Makefile.am3
-rw-r--r--src/third_party/wiredtiger/test/csuite/rwlock/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt2246_col_append/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt2323_join_visibility/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt2535_insert_race/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt2834_join_bloom_fix/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt2853_perf/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt2909_checkpoint_integrity/main.c3
-rw-r--r--src/third_party/wiredtiger/test/csuite/wt3363_checkpoint_op_races/main.c268
-rw-r--r--src/third_party/wiredtiger/test/format/config.h4
-rw-r--r--src/third_party/wiredtiger/test/format/format.h14
-rw-r--r--src/third_party/wiredtiger/test/format/ops.c43
-rw-r--r--src/third_party/wiredtiger/test/format/wts.c12
-rw-r--r--src/third_party/wiredtiger/test/suite/test_timestamp01.py67
-rw-r--r--src/third_party/wiredtiger/test/suite/test_timestamp02.py129
-rw-r--r--src/third_party/wiredtiger/test/utility/misc.c39
-rw-r--r--src/third_party/wiredtiger/test/utility/test_util.h44
-rw-r--r--src/third_party/wiredtiger/test/utility/thread.c282
-rw-r--r--src/third_party/wiredtiger/test/windows/windows_shim.h2
114 files changed, 3778 insertions, 2149 deletions
diff --git a/src/third_party/wiredtiger/NEWS b/src/third_party/wiredtiger/NEWS
index 380db269523..ffcefd5f8c1 100644
--- a/src/third_party/wiredtiger/NEWS
+++ b/src/third_party/wiredtiger/NEWS
@@ -1,6 +1,30 @@
Ticket reference tags refer to tickets in the MongoDB JIRA tracking system:
https://jira.mongodb.org
+WiredTiger release 2.9.3, 2017-06-27
+------------------------------------
+
+See the upgrading documentation for details of API and behavior changes.
+
+Significant changes:
+* WT-2972 Add an interface allowing partial updates to existing values
+* WT-3063 Add an interface allowing reservation of records for read-modify-write
+* WT-3142 Add a workload generator application
+* WT-3160 Improve eviction of internal pages from idle trees
+* WT-3245 Avoid hangs on shutdown when a utility thread encounters an error
+* WT-3258 Improve visibility into thread wait time due to pages exceeding memory_page_max
+* WT-3263 Allow archive on restart/recovery if clean shutdown
+* WT-3287 Review WiredTiger internal panic checks
+* WT-3292 Review/cleanup full-barrier calls in WiredTiger
+* WT-3296 LAS table fixes/improvements
+* WT-3327 Checkpoints can hang if time runs backward
+* WT-3345 Improve rwlock scaling
+* WT-3373 Access violation due to a bug in internal page splitting
+* WT-3379 Change when pages can be split to avoid excessively slowing some operations
+
+See JIRA changelog for a full listing:
+https://jira.mongodb.org/browse/WT/fixforversion/18291
+
WiredTiger release 2.9.2, 2017-05-25
------------------------------------
diff --git a/src/third_party/wiredtiger/README b/src/third_party/wiredtiger/README
index eb5324eb4d1..4def09abba6 100644
--- a/src/third_party/wiredtiger/README
+++ b/src/third_party/wiredtiger/README
@@ -1,6 +1,6 @@
-WiredTiger 2.9.3: (May 27, 2017)
+WiredTiger 3.0.0: (June 27, 2017)
-This is version 2.9.3 of WiredTiger.
+This is version 3.0.0 of WiredTiger.
WiredTiger release packages and documentation can be found at:
@@ -8,7 +8,7 @@ WiredTiger release packages and documentation can be found at:
The documentation for this specific release can be found at:
- http://source.wiredtiger.com/2.9.3/index.html
+ http://source.wiredtiger.com/3.0.0/index.html
The WiredTiger source code can be found at:
diff --git a/src/third_party/wiredtiger/RELEASE_INFO b/src/third_party/wiredtiger/RELEASE_INFO
index f18f6f67fc8..ccdff34f2d5 100644
--- a/src/third_party/wiredtiger/RELEASE_INFO
+++ b/src/third_party/wiredtiger/RELEASE_INFO
@@ -1,6 +1,6 @@
-WIREDTIGER_VERSION_MAJOR=2
-WIREDTIGER_VERSION_MINOR=9
-WIREDTIGER_VERSION_PATCH=3
+WIREDTIGER_VERSION_MAJOR=3
+WIREDTIGER_VERSION_MINOR=0
+WIREDTIGER_VERSION_PATCH=0
WIREDTIGER_VERSION="$WIREDTIGER_VERSION_MAJOR.$WIREDTIGER_VERSION_MINOR.$WIREDTIGER_VERSION_PATCH"
WIREDTIGER_RELEASE_DATE=`date "+%B %e, %Y"`
diff --git a/src/third_party/wiredtiger/SConstruct b/src/third_party/wiredtiger/SConstruct
index 2661807594d..748bf18db00 100644
--- a/src/third_party/wiredtiger/SConstruct
+++ b/src/third_party/wiredtiger/SConstruct
@@ -513,15 +513,10 @@ Default(t)
#Build the Examples
for ex in examples:
- if(ex in ['ex_all', 'ex_async', 'ex_encrypt', 'ex_file_system' , 'ex_thread']):
- exp = env.Program(ex, "examples/c/" + ex + ".c", LIBS=[wtlib, shim] + wtlibs)
- Default(exp)
- env.Alias("check", env.SmokeTest(exp))
- else:
- exp = env.Program(ex, "examples/c/" + ex + ".c", LIBS=[wtdll[1]] + wtlibs)
- Default(exp)
- if not ex == 'ex_log':
- env.Alias("check", env.SmokeTest(exp))
+ exp = env.Program(ex, "examples/c/" + ex + ".c", LIBS=[wtlib, shim, testutil] + wtlibs)
+ Default(exp)
+ if not ex == 'ex_log':
+ env.Alias("check", env.SmokeTest(exp))
# Install Target
#
diff --git a/src/third_party/wiredtiger/build_darwin/wiredtiger_config.h b/src/third_party/wiredtiger/build_darwin/wiredtiger_config.h
index 58d49ec42e7..44c62be8e1b 100644
--- a/src/third_party/wiredtiger/build_darwin/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_darwin/wiredtiger_config.h
@@ -142,6 +142,9 @@
/* Default alignment of buffers used for I/O */
#define WT_BUFFER_ALIGNMENT_DEFAULT 0
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
diff --git a/src/third_party/wiredtiger/build_freebsd/wiredtiger_config.h b/src/third_party/wiredtiger/build_freebsd/wiredtiger_config.h
index c742e200558..baba7e23e74 100644
--- a/src/third_party/wiredtiger/build_freebsd/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_freebsd/wiredtiger_config.h
@@ -142,6 +142,9 @@
/* Default alignment of buffers used for I/O */
#define WT_BUFFER_ALIGNMENT_DEFAULT 0
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
diff --git a/src/third_party/wiredtiger/build_linux/wiredtiger_config.h b/src/third_party/wiredtiger/build_linux/wiredtiger_config.h
index 1122e1e319d..fca49bf26cf 100644
--- a/src/third_party/wiredtiger/build_linux/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_linux/wiredtiger_config.h
@@ -142,6 +142,9 @@
/* Default alignment of buffers used for I/O */
#define WT_BUFFER_ALIGNMENT_DEFAULT 4096
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
diff --git a/src/third_party/wiredtiger/build_openbsd/wiredtiger_config.h b/src/third_party/wiredtiger/build_openbsd/wiredtiger_config.h
index b27211419c7..65b7dd71c2b 100644
--- a/src/third_party/wiredtiger/build_openbsd/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_openbsd/wiredtiger_config.h
@@ -142,6 +142,9 @@
/* Default alignment of buffers used for I/O */
#define WT_BUFFER_ALIGNMENT_DEFAULT 0
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Enable large inode numbers on Mac OS X 10.5. */
#ifndef _DARWIN_USE_64_BIT_INODE
# define _DARWIN_USE_64_BIT_INODE 1
diff --git a/src/third_party/wiredtiger/build_posix/Make.subdirs b/src/third_party/wiredtiger/build_posix/Make.subdirs
index ec928a9ead2..34f1746a811 100644
--- a/src/third_party/wiredtiger/build_posix/Make.subdirs
+++ b/src/third_party/wiredtiger/build_posix/Make.subdirs
@@ -21,14 +21,16 @@ ext/test/kvs_bdb HAVE_BERKELEY_DB
ext/test/fail_fs
.
api/leveldb LEVELDB
-examples/c
lang/java JAVA
-examples/java JAVA
lang/python PYTHON
-# Test/Benchmark support library.
+# Test/Benchmark/Examples support library.
test/utility
+# Example programs.
+examples/c
+examples/java JAVA
+
# Test programs.
test/bloom
test/checkpoint
diff --git a/src/third_party/wiredtiger/build_posix/aclocal/options.m4 b/src/third_party/wiredtiger/build_posix/aclocal/options.m4
index bc4b31dfee3..20d8ed08db5 100644
--- a/src/third_party/wiredtiger/build_posix/aclocal/options.m4
+++ b/src/third_party/wiredtiger/build_posix/aclocal/options.m4
@@ -244,6 +244,15 @@ no) wt_cv_enable_strict=no;;
esac
AC_MSG_RESULT($wt_cv_enable_strict)
+AC_MSG_CHECKING(if --with-timestamp-size option specified)
+AC_ARG_WITH(timestamp-size,
+ [AS_HELP_STRING([--with-timestamp-size=NUM],
+ [Size of transaction timestamps in bytes, default 8.])],
+ [with_timestamp_size=$withval],
+ [with_timestamp_size=8])
+AC_MSG_RESULT($with_timestamp_size)
+AC_DEFINE_UNQUOTED(WT_TIMESTAMP_SIZE, [$with_timestamp_size], [Size of a transaction timestamp in bytes])
+
AH_TEMPLATE(HAVE_VERBOSE, [Enable verbose message configuration.])
AC_MSG_CHECKING(if --enable-verbose option specified)
AC_ARG_ENABLE(verbose,
diff --git a/src/third_party/wiredtiger/build_posix/aclocal/version-set.m4 b/src/third_party/wiredtiger/build_posix/aclocal/version-set.m4
index bbf8547e548..5e54ad1cb69 100644
--- a/src/third_party/wiredtiger/build_posix/aclocal/version-set.m4
+++ b/src/third_party/wiredtiger/build_posix/aclocal/version-set.m4
@@ -1,14 +1,14 @@
dnl build by dist/s_version
-VERSION_MAJOR=2
-VERSION_MINOR=9
-VERSION_PATCH=3
-VERSION_STRING='"WiredTiger 2.9.3: (May 27, 2017)"'
+VERSION_MAJOR=3
+VERSION_MINOR=0
+VERSION_PATCH=0
+VERSION_STRING='"WiredTiger 3.0.0: (June 27, 2017)"'
AC_SUBST(VERSION_MAJOR)
AC_SUBST(VERSION_MINOR)
AC_SUBST(VERSION_PATCH)
AC_SUBST(VERSION_STRING)
-VERSION_NOPATCH=2.9
+VERSION_NOPATCH=3.0
AC_SUBST(VERSION_NOPATCH)
diff --git a/src/third_party/wiredtiger/build_posix/aclocal/version.m4 b/src/third_party/wiredtiger/build_posix/aclocal/version.m4
index 1126d7c147b..3c5980dbaad 100644
--- a/src/third_party/wiredtiger/build_posix/aclocal/version.m4
+++ b/src/third_party/wiredtiger/build_posix/aclocal/version.m4
@@ -1,2 +1,2 @@
dnl WiredTiger product version for AC_INIT. Maintained by dist/s_version
-2.9.3
+3.0.0
diff --git a/src/third_party/wiredtiger/build_solaris/wiredtiger_config.h b/src/third_party/wiredtiger/build_solaris/wiredtiger_config.h
index 868b1960cd0..cc8a4aa2ff7 100644
--- a/src/third_party/wiredtiger/build_solaris/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_solaris/wiredtiger_config.h
@@ -142,6 +142,9 @@
/* Default alignment of buffers used for I/O */
#define WT_BUFFER_ALIGNMENT_DEFAULT 0
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
diff --git a/src/third_party/wiredtiger/build_win/wiredtiger_config.h b/src/third_party/wiredtiger/build_win/wiredtiger_config.h
index 78d2784cb70..90cd40f1fae 100644
--- a/src/third_party/wiredtiger/build_win/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_win/wiredtiger_config.h
@@ -133,6 +133,9 @@
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
#if defined AC_APPLE_UNIVERSAL_BUILD
@@ -148,6 +151,9 @@
/* Default alignment of buffers used for I/O */
#define WT_BUFFER_ALIGNMENT_DEFAULT 0
+/* Size of a transaction timestamp in bytes */
+#define WT_TIMESTAMP_SIZE 8
+
/* Enable large inode numbers on Mac OS X 10.5. */
/* #ifndef _DARWIN_USE_64_BIT_INODE */
/* # define _DARWIN_USE_64_BIT_INODE 1 */
diff --git a/src/third_party/wiredtiger/dist/api_data.py b/src/third_party/wiredtiger/dist/api_data.py
index 3297c68147a..4a4ffae535d 100644
--- a/src/third_party/wiredtiger/dist/api_data.py
+++ b/src/third_party/wiredtiger/dist/api_data.py
@@ -401,6 +401,15 @@ connection_runtime_config = [
above 0 configures periodic checkpoints''',
min='0', max='100000'),
]),
+ Config('diagnostic_timing_stress', '', r'''
+ enable insertion of code that interrupts the usual timing of
+ operations with a goal of uncovering race conditions and unexpected
+ blocking. This option is intended for use with internal stress
+ testing of WiredTiger. Only available if WiredTiger is configured
+ with --enable-diagnostic. Options are given as a list, such as
+ <code>"diagnostic_timing_stress=[checkpoint_slow]"</code>''',
+ type='list', undoc=True, choices=[
+ 'checkpoint_slow']),
Config('error_prefix', '', r'''
prefix string for error messages'''),
Config('eviction', '', r'''
@@ -1028,7 +1037,8 @@ methods = {
]),
'WT_SESSION.strerror' : Method([]),
'WT_SESSION.transaction_sync' : Method([
- Config('timeout_ms', '1200000', r'''
+ Config('timeout_ms', '1200000', # !!! Must match WT_SESSION_BG_SYNC_MSEC
+ r'''
maximum amount of time to wait for background sync to complete in
milliseconds. A value of zero disables the timeout and returns
immediately''',
@@ -1077,6 +1087,9 @@ methods = {
priority of the transaction for resolving conflicts.
Transactions with higher values are less likely to abort''',
min='-100', max='100'),
+ Config('read_timestamp', '', r'''
+ read using the specified timestamp, see
+ @ref transaction_timestamps'''),
Config('snapshot', '', r'''
use a named, in-memory snapshot, see
@ref transaction_named_snapshots'''),
@@ -1087,6 +1100,9 @@ methods = {
]),
'WT_SESSION.commit_transaction' : Method([
+ Config('commit_timestamp', '', r'''
+ set the commit timestamp for the current transaction, see
+ @ref transaction_timestamps'''),
Config('sync', '', r'''
override whether to sync log records when the transaction commits,
inherited from ::wiredtiger_open \c transaction_sync.
@@ -1097,6 +1113,13 @@ methods = {
\c on setting forces log records to be written to the storage device''',
choices=['background', 'off', 'on']),
]),
+
+'WT_SESSION.timestamp_transaction' : Method([
+ Config('commit_timestamp', '', r'''
+ set the commit timestamp for the current transaction, see
+ @ref transaction_timestamps'''),
+]),
+
'WT_SESSION.rollback_transaction' : Method([]),
'WT_SESSION.checkpoint' : Method([
@@ -1117,6 +1140,9 @@ methods = {
Config('name', '', r'''
if set, specify a name for the checkpoint (note that checkpoints
including LSM trees may not be named)'''),
+ Config('read_timestamp', '', r'''
+ if set, create the checkpoint as of the specified timestamp''',
+ undoc=True),
Config('target', '', r'''
if non-empty, checkpoint the list of objects''', type='list'),
]),
@@ -1204,6 +1230,22 @@ methods = {
'WT_CONNECTION.open_session' : Method(session_config),
+'WT_CONNECTION.query_timestamp' : Method([
+ Config('get', 'all_committed', r'''
+ specify which timestamp to query: \c all_committed returns the largest
+ timestamp such that all earlier timestamps have committed. See @ref
+ transaction_timestamps''',
+ choices=['all_committed']),
+ # We also support "oldest_reader" as an internal-only choice.
+]),
+
+'WT_CONNECTION.set_timestamp' : Method([
+ Config('oldest_timestamp', '', r'''
+ future commits and queries will be no earlier than the specified
+ timestamp. Supplied values must be monotonically increasing.
+ see @ref transaction_timestamps'''),
+]),
+
'WT_SESSION.reconfigure' : Method(session_config),
# There are 4 variants of the wiredtiger_open configurations.
diff --git a/src/third_party/wiredtiger/dist/filelist b/src/third_party/wiredtiger/dist/filelist
index 6b6e617c4b1..a81d693cb4e 100644
--- a/src/third_party/wiredtiger/dist/filelist
+++ b/src/third_party/wiredtiger/dist/filelist
@@ -198,3 +198,4 @@ src/txn/txn_ext.c
src/txn/txn_log.c
src/txn/txn_nsnap.c
src/txn/txn_recover.c
+src/txn/txn_timestamp.c
diff --git a/src/third_party/wiredtiger/dist/flags.py b/src/third_party/wiredtiger/dist/flags.py
index 8edabd69648..43db7a67054 100644
--- a/src/third_party/wiredtiger/dist/flags.py
+++ b/src/third_party/wiredtiger/dist/flags.py
@@ -8,6 +8,9 @@ flags = {
###################################################
# Internal routine flag declarations
###################################################
+ 'diagnostic_timing_stress' : [
+ 'TIMING_STRESS_CHECKPOINT_SLOW',
+ ],
'log_scan' : [
'LOGSCAN_FIRST',
'LOGSCAN_FROM_CKP',
diff --git a/src/third_party/wiredtiger/dist/package/wiredtiger.spec b/src/third_party/wiredtiger/dist/package/wiredtiger.spec
index 9d9bdd3949c..f4cb78183d0 100644
--- a/src/third_party/wiredtiger/dist/package/wiredtiger.spec
+++ b/src/third_party/wiredtiger/dist/package/wiredtiger.spec
@@ -1,5 +1,5 @@
Name: wiredtiger
-Version: 2.9.3
+Version: 3.0.0
Release: 1%{?dist}
Summary: WiredTiger data storage engine
diff --git a/src/third_party/wiredtiger/dist/s_string.ok b/src/third_party/wiredtiger/dist/s_string.ok
index 4ddb64297f4..e0899bfeedf 100644
--- a/src/third_party/wiredtiger/dist/s_string.ok
+++ b/src/third_party/wiredtiger/dist/s_string.ok
@@ -832,6 +832,7 @@ isrc
isspace
isupper
isxdigit
+iszero
iter
iteratively
iters
@@ -1101,6 +1102,7 @@ runtime
rwlock
sH
sHQ
+sT
scalability
sched
scr
@@ -1177,7 +1179,9 @@ testutil
th
tid
timestamp
+timestamps
tmp
+todo
tokenizer
toklen
tokname
diff --git a/src/third_party/wiredtiger/examples/c/Makefile.am b/src/third_party/wiredtiger/examples/c/Makefile.am
index 20936661e06..41a9bcdc6bb 100644
--- a/src/third_party/wiredtiger/examples/c/Makefile.am
+++ b/src/third_party/wiredtiger/examples/c/Makefile.am
@@ -1,5 +1,7 @@
-LDADD = $(top_builddir)/libwiredtiger.la
+LDADD = $(top_builddir)/test/utility/libtest_util.la
+LDADD += $(top_builddir)/libwiredtiger.la
AM_CPPFLAGS = -I$(top_srcdir)/src/include
+AM_CPPFLAGS +=-I$(top_srcdir)/test/utility
noinst_PROGRAMS = \
ex_access \
@@ -20,6 +22,7 @@ noinst_PROGRAMS = \
ex_pack \
ex_process \
ex_schema \
+ ex_smoke \
ex_stat \
ex_sync \
ex_thread
diff --git a/src/third_party/wiredtiger/examples/c/ex_access.c b/src/third_party/wiredtiger/examples/c/ex_access.c
index 6f24139182d..df8b0b499df 100644
--- a/src/third_party/wiredtiger/examples/c/ex_access.c
+++ b/src/third_party/wiredtiger/examples/c/ex_access.c
@@ -28,16 +28,12 @@
* ex_access.c
* demonstrates how to create and access a simple table.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
-int
-main(void)
+static void
+access_example(void)
{
/*! [access example connection] */
WT_CONNECTION *conn;
@@ -46,54 +42,51 @@ main(void)
const char *key, *value;
int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
-
/* Open a connection to the database, creating it if necessary. */
- if ((ret = wiredtiger_open(home, NULL, "create", &conn)) != 0 ||
- (ret = conn->open_session(conn, NULL, NULL, &session)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
+
+ /* Open a session handle for the database. */
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/*! [access example connection] */
/*! [access example table create] */
- ret = session->create(session,
- "table:access", "key_format=S,value_format=S");
+ error_check(session->create(
+ session, "table:access", "key_format=S,value_format=S"));
/*! [access example table create] */
/*! [access example cursor open] */
- ret = session->open_cursor(session,
- "table:access", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:access", NULL, NULL, &cursor));
/*! [access example cursor open] */
/*! [access example cursor insert] */
cursor->set_key(cursor, "key1"); /* Insert a record. */
cursor->set_value(cursor, "value1");
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
/*! [access example cursor insert] */
/*! [access example cursor list] */
- ret = cursor->reset(cursor); /* Restart the scan. */
+ error_check(cursor->reset(cursor)); /* Restart the scan. */
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &key);
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->get_key(cursor, &key));
+ error_check(cursor->get_value(cursor, &value));
printf("Got record: %s : %s\n", key, value);
}
+ scan_end_check(ret == WT_NOTFOUND); /* Check for end-of-table. */
/*! [access example cursor list] */
/*! [access example close] */
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL)); /* Close all handles. */
/*! [access example close] */
+}
+
+int
+main(int argc, char *argv[])
+{
+ home = example_setup(argc, argv);
+
+ access_example();
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_all.c b/src/third_party/wiredtiger/examples/c/ex_all.c
index 5e1fa4bbcc5..7dce4744db3 100644
--- a/src/third_party/wiredtiger/examples/c/ex_all.c
+++ b/src/third_party/wiredtiger/examples/c/ex_all.c
@@ -32,38 +32,23 @@
* method. This file is used to populate the API reference with code
* fragments.
*/
+#include <test_util.h>
-#include <sys/stat.h>
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#include "windows_shim.h"
-#endif
-
-#include <wiredtiger.h>
-
-int add_collator(WT_CONNECTION *conn);
-int add_extractor(WT_CONNECTION *conn);
-int backup(WT_SESSION *session);
-int checkpoint_ops(WT_SESSION *session);
-int connection_ops(WT_CONNECTION *conn);
-int cursor_ops(WT_SESSION *session);
-int cursor_search_near(WT_CURSOR *cursor);
-int cursor_statistics(WT_SESSION *session);
-int pack_ops(WT_SESSION *session);
-int named_snapshot_ops(WT_SESSION *session);
-int session_ops(WT_SESSION *session);
-int transaction_ops(WT_CONNECTION *conn, WT_SESSION *session);
-
-static const char * const progname = "ex_all";
static const char *home;
+void add_collator(WT_CONNECTION *conn);
+void add_extractor(WT_CONNECTION *conn);
+void backup(WT_SESSION *session);
+void checkpoint_ops(WT_SESSION *session);
+void connection_ops(WT_CONNECTION *conn);
+int cursor_ops(WT_SESSION *session);
+void cursor_search_near(WT_CURSOR *cursor);
+void cursor_statistics(WT_SESSION *session);
+void named_snapshot_ops(WT_SESSION *session);
+void pack_ops(WT_SESSION *session);
+void session_ops(WT_SESSION *session);
+void transaction_ops(WT_CONNECTION *conn, WT_SESSION *session);
+
int
cursor_ops(WT_SESSION *session)
{
@@ -71,72 +56,73 @@ cursor_ops(WT_SESSION *session)
int ret;
/*! [Open a cursor] */
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
/*! [Open a cursor] */
/*! [Open a cursor on the metadata] */
- ret = session->open_cursor(
- session, "metadata:", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "metadata:", NULL, NULL, &cursor));
/*! [Open a cursor on the metadata] */
{
WT_CURSOR *duplicate;
const char *key = "some key";
/*! [Duplicate a cursor] */
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
cursor->set_key(cursor, key);
- ret = cursor->search(cursor);
+ error_check(cursor->search(cursor));
/* Duplicate the cursor. */
- ret = session->open_cursor(session, NULL, cursor, NULL, &duplicate);
+ error_check(
+ session->open_cursor(session, NULL, cursor, NULL, &duplicate));
/*! [Duplicate a cursor] */
}
{
const char *key = "some key", *value = "some value";
/*! [Reconfigure a cursor] */
- ret = session->open_cursor(
- session, "table:mytable", NULL, "overwrite=false", &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite=false", &cursor));
cursor->set_key(cursor, key);
cursor->set_value(cursor, value);
/* Reconfigure the cursor to overwrite the record. */
- ret = cursor->reconfigure(cursor, "overwrite=true");
- ret = cursor->insert(cursor);
+ error_check(cursor->reconfigure(cursor, "overwrite=true"));
+ error_check(cursor->insert(cursor));
/*! [Reconfigure a cursor] */
}
{
/*! [boolean configuration string example] */
- ret = session->open_cursor(session, "table:mytable", NULL,
- "overwrite", &cursor);
- ret = session->open_cursor(session, "table:mytable", NULL,
- "overwrite=true", &cursor);
- ret = session->open_cursor(session, "table:mytable", NULL,
- "overwrite=1", &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite", &cursor));
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite=true", &cursor));
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite=1", &cursor));
/*! [boolean configuration string example] */
}
{
/*! [open a named checkpoint] */
- ret = session->open_cursor(session,
- "table:mytable", NULL, "checkpoint=midnight", &cursor);
+ error_check(session->open_cursor(session,
+ "table:mytable", NULL, "checkpoint=midnight", &cursor));
/*! [open a named checkpoint] */
}
{
/*! [open the default checkpoint] */
- ret = session->open_cursor(session,
- "table:mytable", NULL, "checkpoint=WiredTigerCheckpoint", &cursor);
+ error_check(session->open_cursor(session,
+ "table:mytable", NULL, "checkpoint=WiredTigerCheckpoint", &cursor));
/*! [open the default checkpoint] */
}
{
/*! [Get the cursor's string key] */
const char *key; /* Get the cursor's string key. */
- ret = cursor->get_key(cursor, &key);
+ error_check(cursor->get_key(cursor, &key));
/*! [Get the cursor's string key] */
}
@@ -151,7 +137,7 @@ cursor_ops(WT_SESSION *session)
{
/*! [Get the cursor's record number key] */
uint64_t recno; /* Get the cursor's record number key. */
- ret = cursor->get_key(cursor, &recno);
+ error_check(cursor->get_key(cursor, &recno));
/*! [Get the cursor's record number key] */
}
@@ -168,7 +154,7 @@ cursor_ops(WT_SESSION *session)
const char *first;
int32_t second;
uint16_t third;
- ret = cursor->get_key(cursor, &first, &second, &third);
+ error_check(cursor->get_key(cursor, &first, &second, &third));
/*! [Get the cursor's composite key] */
}
@@ -182,7 +168,7 @@ cursor_ops(WT_SESSION *session)
{
/*! [Get the cursor's string value] */
const char *value; /* Get the cursor's string value. */
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->get_value(cursor, &value));
/*! [Get the cursor's string value] */
}
@@ -197,7 +183,7 @@ cursor_ops(WT_SESSION *session)
{
/*! [Get the cursor's raw value] */
WT_ITEM value; /* Get the cursor's raw value. */
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->get_value(cursor, &value));
/*! [Get the cursor's raw value] */
}
@@ -211,22 +197,22 @@ cursor_ops(WT_SESSION *session)
}
/*! [Return the next record] */
- ret = cursor->next(cursor);
+ error_check(cursor->next(cursor));
/*! [Return the next record] */
/*! [Return the previous record] */
- ret = cursor->prev(cursor);
+ error_check(cursor->prev(cursor));
/*! [Return the previous record] */
/*! [Reset the cursor] */
- ret = cursor->reset(cursor);
+ error_check(cursor->reset(cursor));
/*! [Reset the cursor] */
{
WT_CURSOR *other = NULL;
/*! [Cursor comparison] */
int compare;
- ret = cursor->compare(cursor, other, &compare);
+ error_check(cursor->compare(cursor, other, &compare));
if (compare == 0) {
/* Cursors reference the same key */
} else if (compare < 0) {
@@ -241,7 +227,7 @@ cursor_ops(WT_SESSION *session)
WT_CURSOR *other = NULL;
/*! [Cursor equality] */
int equal;
- ret = cursor->equals(cursor, other, &equal);
+ error_check(cursor->equals(cursor, other, &equal));
if (equal) {
/* Cursors reference the same key */
} else {
@@ -254,21 +240,21 @@ cursor_ops(WT_SESSION *session)
/*! [Search for an exact match] */
const char *key = "some key";
cursor->set_key(cursor, key);
- ret = cursor->search(cursor);
+ error_check(cursor->search(cursor));
/*! [Search for an exact match] */
}
- ret = cursor_search_near(cursor);
+ cursor_search_near(cursor);
{
/*! [Insert a new record or overwrite an existing record] */
/* Insert a new record or overwrite an existing record. */
const char *key = "some key", *value = "some value";
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
cursor->set_key(cursor, key);
cursor->set_value(cursor, value);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
/*! [Insert a new record or overwrite an existing record] */
}
@@ -276,11 +262,11 @@ cursor_ops(WT_SESSION *session)
/*! [Insert a new record and fail if the record exists] */
/* Insert a new record and fail if the record exists. */
const char *key = "some key", *value = "some value";
- ret = session->open_cursor(
- session, "table:mytable", NULL, "overwrite=false", &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite=false", &cursor));
cursor->set_key(cursor, key);
cursor->set_value(cursor, value);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
/*! [Insert a new record and fail if the record exists] */
}
@@ -289,22 +275,21 @@ cursor_ops(WT_SESSION *session)
/* Insert a new record and assign a record number. */
uint64_t recno;
const char *value = "some value";
- ret = session->open_cursor(
- session, "table:mytable", NULL, "append", &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "append", &cursor));
cursor->set_value(cursor, value);
- ret = cursor->insert(cursor);
- if (ret == 0)
- ret = cursor->get_key(cursor, &recno);
+ error_check(cursor->insert(cursor));
+ error_check(cursor->get_key(cursor, &recno));
/*! [Insert a new record and assign a record number] */
}
{
/*! [Reserve a record] */
const char *key = "some key";
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
cursor->set_key(cursor, key);
- ret = cursor->reserve(cursor);
+ error_check(cursor->reserve(cursor));
/*! [Reserve a record] */
}
@@ -312,12 +297,12 @@ cursor_ops(WT_SESSION *session)
/*! [Modify an existing record] */
WT_MODIFY entries[3];
const char *key = "some key";
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
/* Position the cursor. */
cursor->set_key(cursor, key);
- ret = cursor->search(cursor);
+ error_check(cursor->search(cursor));
/* Replace 20 bytes starting at byte offset 5. */
entries[0].data.data = "some data";
@@ -337,49 +322,49 @@ cursor_ops(WT_SESSION *session)
entries[2].offset = 10;
entries[2].size = 2;
- ret = cursor->modify(cursor, entries, 3);
+ error_check(cursor->modify(cursor, entries, 3));
/*! [Modify an existing record] */
}
{
/*! [Update an existing record or insert a new record] */
const char *key = "some key", *value = "some value";
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
cursor->set_key(cursor, key);
cursor->set_value(cursor, value);
- ret = cursor->update(cursor);
+ error_check(cursor->update(cursor));
/*! [Update an existing record or insert a new record] */
}
{
/*! [Update an existing record and fail if DNE] */
const char *key = "some key", *value = "some value";
- ret = session->open_cursor(
- session, "table:mytable", NULL, "overwrite=false", &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite=false", &cursor));
cursor->set_key(cursor, key);
cursor->set_value(cursor, value);
- ret = cursor->update(cursor);
+ error_check(cursor->update(cursor));
/*! [Update an existing record and fail if DNE] */
}
{
/*! [Remove a record] */
const char *key = "some key";
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
cursor->set_key(cursor, key);
- ret = cursor->remove(cursor);
+ error_check(cursor->remove(cursor));
/*! [Remove a record] */
}
{
/*! [Remove a record and fail if DNE] */
const char *key = "some key";
- ret = session->open_cursor(
- session, "table:mytable", NULL, "overwrite=false", &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, "overwrite=false", &cursor));
cursor->set_key(cursor, key);
- ret = cursor->remove(cursor);
+ error_check(cursor->remove(cursor));
/*! [Remove a record and fail if DNE] */
}
@@ -409,13 +394,13 @@ cursor_ops(WT_SESSION *session)
}
/*! [Close the cursor] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Close the cursor] */
- return (ret);
+ return (0);
}
-int
+void
cursor_search_near(WT_CURSOR *cursor)
{
int exact, ret;
@@ -423,96 +408,92 @@ cursor_search_near(WT_CURSOR *cursor)
/*! [Search for an exact or adjacent match] */
cursor->set_key(cursor, key);
- ret = cursor->search_near(cursor, &exact);
- if (ret == 0) {
- if (exact == 0) {
- /* an exact match */
- } else if (exact < 0) {
- /* returned smaller key */
- } else if (exact > 0) {
- /* returned larger key */
- }
+ error_check(cursor->search_near(cursor, &exact));
+ if (exact == 0) {
+ /* an exact match */
+ } else if (exact < 0) {
+ /* returned smaller key */
+ } else if (exact > 0) {
+ /* returned larger key */
}
/*! [Search for an exact or adjacent match] */
/*! [Forward scan greater than or equal] */
cursor->set_key(cursor, key);
- ret = cursor->search_near(cursor, &exact);
- if (ret == 0 && exact >= 0) {
+ error_check(cursor->search_near(cursor, &exact));
+ if (exact >= 0) {
/* include first key returned in the scan */
}
while ((ret = cursor->next(cursor)) == 0) {
/* the rest of the scan */
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Forward scan greater than or equal] */
/*! [Backward scan less than] */
cursor->set_key(cursor, key);
- ret = cursor->search_near(cursor, &exact);
- if (ret == 0 && exact < 0) {
+ error_check(cursor->search_near(cursor, &exact));
+ if (exact < 0) {
/* include first key returned in the scan */
}
while ((ret = cursor->prev(cursor)) == 0) {
/* the rest of the scan */
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Backward scan less than] */
-
- return (ret);
}
-int
+void
checkpoint_ops(WT_SESSION *session)
{
- int ret;
-
/*! [Checkpoint examples] */
/* Checkpoint the database. */
- ret = session->checkpoint(session, NULL);
+ error_check(session->checkpoint(session, NULL));
/* Checkpoint of the database, creating a named snapshot. */
- ret = session->checkpoint(session, "name=June01");
+ error_check(session->checkpoint(session, "name=June01"));
/*
* Checkpoint a list of objects.
* JSON parsing requires quoting the list of target URIs.
*/
- ret = session->
- checkpoint(session, "target=(\"table:table1\",\"table:table2\")");
+ error_check(session->checkpoint(
+ session, "target=(\"table:table1\",\"table:table2\")"));
/*
* Checkpoint a list of objects, creating a named snapshot.
* JSON parsing requires quoting the list of target URIs.
*/
- ret = session->
- checkpoint(session, "target=(\"table:mytable\"),name=midnight");
+ error_check(session->checkpoint(
+ session, "target=(\"table:mytable\"),name=midnight"));
/* Checkpoint the database, discarding all previous snapshots. */
- ret = session->checkpoint(session, "drop=(from=all)");
+ error_check(session->checkpoint(session, "drop=(from=all)"));
/* Checkpoint the database, discarding the "midnight" snapshot. */
- ret = session->checkpoint(session, "drop=(midnight)");
+ error_check(session->checkpoint(session, "drop=(midnight)"));
/*
* Checkpoint the database, discarding all snapshots after and
* including "noon".
*/
- ret = session->checkpoint(session, "drop=(from=noon)");
+ error_check(session->checkpoint(session, "drop=(from=noon)"));
/*
* Checkpoint the database, discarding all snapshots before and
* including "midnight".
*/
- ret = session->checkpoint(session, "drop=(to=midnight)");
+ error_check(session->checkpoint(session, "drop=(to=midnight)"));
/*
* Create a checkpoint of a table, creating the "July01" snapshot and
* discarding the "May01" and "June01" snapshots.
* JSON parsing requires quoting the list of target URIs.
*/
- ret = session->checkpoint(session,
- "target=(\"table:mytable\"),name=July01,drop=(May01,June01)");
+ error_check(session->checkpoint(session,
+ "target=(\"table:mytable\"),name=July01,drop=(May01,June01)"));
/*! [Checkpoint examples] */
/*! [JSON quoting example] */
@@ -520,119 +501,107 @@ checkpoint_ops(WT_SESSION *session)
* Checkpoint a list of objects.
* JSON parsing requires quoting the list of target URIs.
*/
- ret = session->
- checkpoint(session, "target=(\"table:table1\",\"table:table2\")");
+ error_check(session->checkpoint(
+ session, "target=(\"table:table1\",\"table:table2\")"));
/*! [JSON quoting example] */
-
- return (ret);
}
-int
+void
cursor_statistics(WT_SESSION *session)
{
WT_CURSOR *cursor;
- int ret;
/*! [Statistics cursor database] */
- ret = session->open_cursor(
- session, "statistics:", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "statistics:", NULL, NULL, &cursor));
/*! [Statistics cursor database] */
/*! [Statistics cursor table] */
- ret = session->open_cursor(
- session, "statistics:table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "statistics:table:mytable", NULL, NULL, &cursor));
/*! [Statistics cursor table] */
/*! [Statistics cursor table fast] */
- ret = session->open_cursor(session,
- "statistics:table:mytable", NULL, "statistics=(fast)", &cursor);
+ error_check(session->open_cursor(session,
+ "statistics:table:mytable", NULL, "statistics=(fast)", &cursor));
/*! [Statistics cursor table fast] */
/*! [Statistics clear configuration] */
- ret = session->open_cursor(session,
- "statistics:", NULL, "statistics=(fast,clear)", &cursor);
+ error_check(session->open_cursor(session,
+ "statistics:", NULL, "statistics=(fast,clear)", &cursor));
/*! [Statistics clear configuration] */
/*! [Statistics cursor clear configuration] */
- ret = session->open_cursor(session,
+ error_check(session->open_cursor(session,
"statistics:table:mytable",
- NULL, "statistics=(all,clear)", &cursor);
+ NULL, "statistics=(all,clear)", &cursor));
/*! [Statistics cursor clear configuration] */
-
- return (ret);
}
-int
+void
named_snapshot_ops(WT_SESSION *session)
{
- int ret;
-
/*! [Snapshot examples] */
-
/* Create a named snapshot */
- ret = session->snapshot(session, "name=June01");
+ error_check(session->snapshot(session, "name=June01"));
/* Open a transaction at a given snapshot */
- ret = session->begin_transaction(session, "snapshot=June01");
+ error_check(session->begin_transaction(session, "snapshot=June01"));
/* Drop all named snapshots */
- ret = session->snapshot(session, "drop=(all)");
+ error_check(session->snapshot(session, "drop=(all)"));
/*! [Snapshot examples] */
-
- return (ret);
}
-int
+void
session_ops(WT_SESSION *session)
{
- int ret;
-
/*! [Reconfigure a session] */
- ret = session->reconfigure(session, "isolation=snapshot");
+ error_check(session->reconfigure(session, "isolation=snapshot"));
/*! [Reconfigure a session] */
/*! [Create a table] */
- ret = session->create(session,
- "table:mytable", "key_format=S,value_format=S");
+ error_check(session->create(session,
+ "table:mytable", "key_format=S,value_format=S"));
/*! [Create a table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a column-store table] */
- ret = session->create(session,
- "table:mytable", "key_format=r,value_format=S");
+ error_check(session->create(session,
+ "table:mytable", "key_format=r,value_format=S"));
/*! [Alter a table] */
- ret = session->alter(session,
- "table:mytable", "access_pattern_hint=random");
+ error_check(session->alter(session,
+ "table:mytable", "access_pattern_hint=random"));
/*! [Alter a table] */
/*! [Create a column-store table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a table with columns] */
/*
* Create a table with columns: keys are record numbers, values are
* (string, signed 32-bit integer, unsigned 16-bit integer).
*/
- ret = session->create(session, "table:mytable",
+ error_check(session->create(session, "table:mytable",
"key_format=r,value_format=SiH,"
- "columns=(id,department,salary,year-started)");
+ "columns=(id,department,salary,year-started)"));
/*! [Create a table with columns] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a table and configure the page size] */
- ret = session->create(session,
+ error_check(session->create(session,
"table:mytable", "key_format=S,value_format=S,"
- "internal_page_max=16KB,leaf_page_max=1MB,leaf_value_max=64KB");
+ "internal_page_max=16KB,leaf_page_max=1MB,leaf_value_max=64KB"));
/*! [Create a table and configure the page size] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a table and configure a large leaf value max] */
- ret = session->create(session,
+ error_check(session->create(session,
"table:mytable", "key_format=S,value_format=S,"
- "leaf_page_max=16KB,leaf_value_max=256KB");
+ "leaf_page_max=16KB,leaf_value_max=256KB"));
/*! [Create a table and configure a large leaf value max] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*
* This example code gets run, and the compression libraries might not
@@ -641,109 +610,115 @@ session_ops(WT_SESSION *session)
*/
#ifdef MIGHT_NOT_RUN
/*! [Create a lz4 compressed table] */
- ret = session->create(session,
+ error_check(session->create(session,
"table:mytable",
- "block_compressor=lz4,key_format=S,value_format=S");
+ "block_compressor=lz4,key_format=S,value_format=S"));
/*! [Create a lz4 compressed table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a snappy compressed table] */
- ret = session->create(session,
+ error_check(session->create(session,
"table:mytable",
- "block_compressor=snappy,key_format=S,value_format=S");
+ "block_compressor=snappy,key_format=S,value_format=S"));
/*! [Create a snappy compressed table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a zlib compressed table] */
- ret = session->create(session,
+ error_check(session->create(session,
"table:mytable",
- "block_compressor=zlib,key_format=S,value_format=S");
+ "block_compressor=zlib,key_format=S,value_format=S"));
/*! [Create a zlib compressed table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a zstd compressed table] */
- ret = session->create(session,
+ error_check(session->create(session,
"table:mytable",
- "block_compressor=zstd,key_format=S,value_format=S");
+ "block_compressor=zstd,key_format=S,value_format=S"));
/*! [Create a zstd compressed table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
#endif
/*! [Configure checksums to uncompressed] */
- ret = session->create(session, "table:mytable",
- "key_format=S,value_format=S,checksum=uncompressed");
+ error_check(session->create(session, "table:mytable",
+ "key_format=S,value_format=S,checksum=uncompressed"));
/*! [Configure checksums to uncompressed] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Configure dictionary compression on] */
- ret = session->create(session, "table:mytable",
- "key_format=S,value_format=S,dictionary=1000");
+ error_check(session->create(session, "table:mytable",
+ "key_format=S,value_format=S,dictionary=1000"));
/*! [Configure dictionary compression on] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Configure key prefix compression on] */
- ret = session->create(session, "table:mytable",
- "key_format=S,value_format=S,prefix_compression=true");
+ error_check(session->create(session, "table:mytable",
+ "key_format=S,value_format=S,prefix_compression=true"));
/*! [Configure key prefix compression on] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
#ifdef MIGHT_NOT_RUN
/* Requires sync_file_range */
/*! [os_cache_dirty_max configuration] */
- ret = session->create(
- session, "table:mytable", "os_cache_dirty_max=500MB");
+ error_check(session->create(
+ session, "table:mytable", "os_cache_dirty_max=500MB"));
/*! [os_cache_dirty_max configuration] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/* Requires posix_fadvise */
/*! [os_cache_max configuration] */
- ret = session->create(session, "table:mytable", "os_cache_max=1GB");
+ error_check(session->create(
+ session, "table:mytable", "os_cache_max=1GB"));
/*! [os_cache_max configuration] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
#endif
/*! [Configure block_allocation] */
- ret = session->create(session, "table:mytable",
- "key_format=S,value_format=S,block_allocation=first");
+ error_check(session->create(session, "table:mytable",
+ "key_format=S,value_format=S,block_allocation=first"));
/*! [Configure block_allocation] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Create a cache-resident object] */
- ret = session->create(session,
- "table:mytable", "key_format=r,value_format=S,cache_resident=true");
+ error_check(session->create(
+ session, "table:mytable",
+ "key_format=r,value_format=S,cache_resident=true"));
/*! [Create a cache-resident object] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
{
/* Create a table for the session operations. */
- ret = session->create(
- session, "table:mytable", "key_format=S,value_format=S");
+ error_check(session->create(
+ session, "table:mytable", "key_format=S,value_format=S"));
/*! [Compact a table] */
- ret = session->compact(session, "table:mytable", NULL);
+ error_check(session->compact(session, "table:mytable", NULL));
/*! [Compact a table] */
/*! [Rebalance a table] */
- ret = session->rebalance(session, "table:mytable", NULL);
+ error_check(session->rebalance(session, "table:mytable", NULL));
/*! [Rebalance a table] */
+ error_check(session->create(
+ session, "table:old",
+ "key_format=r,value_format=S,cache_resident=true"));
/*! [Rename a table] */
- ret = session->rename(session, "table:old", "table:new", NULL);
+ error_check(session->rename(session, "table:old", "table:new", NULL));
/*! [Rename a table] */
/*! [Salvage a table] */
- ret = session->salvage(session, "table:mytable", NULL);
+ error_check(session->salvage(session, "table:mytable", NULL));
/*! [Salvage a table] */
/*! [Truncate a table] */
- ret = session->truncate(session, "table:mytable", NULL, NULL, NULL);
+ error_check(session->truncate(
+ session, "table:mytable", NULL, NULL, NULL));
/*! [Truncate a table] */
/*! [Transaction sync] */
- ret = session->transaction_sync(session, NULL);
+ error_check(session->transaction_sync(session, NULL));
/*! [Transaction sync] */
/*! [Reset the session] */
- ret = session->reset(session);
+ error_check(session->reset(session));
/*! [Reset the session] */
{
@@ -751,60 +726,59 @@ session_ops(WT_SESSION *session)
* Insert a pair of keys so we can truncate a range.
*/
WT_CURSOR *cursor;
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
cursor->set_key(cursor, "June01");
cursor->set_value(cursor, "value");
- ret = cursor->update(cursor);
+ error_check(cursor->update(cursor));
cursor->set_key(cursor, "June30");
cursor->set_value(cursor, "value");
- ret = cursor->update(cursor);
- ret = cursor->close(cursor);
+ error_check(cursor->update(cursor));
+ error_check(cursor->close(cursor));
{
/*! [Truncate a range] */
WT_CURSOR *start, *stop;
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &start);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &start));
start->set_key(start, "June01");
- ret = start->search(start);
+ error_check(start->search(start));
- ret = session->open_cursor(
- session, "table:mytable", NULL, NULL, &stop);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &stop));
stop->set_key(stop, "June30");
- ret = stop->search(stop);
+ error_check(stop->search(stop));
- ret = session->truncate(session, NULL, start, stop, NULL);
+ error_check(session->truncate(session, NULL, start, stop, NULL));
/*! [Truncate a range] */
+ error_check(stop->close(stop));
+ error_check(start->close(start));
}
}
/*! [Upgrade a table] */
- ret = session->upgrade(session, "table:mytable", NULL);
+ error_check(session->upgrade(session, "table:mytable", NULL));
/*! [Upgrade a table] */
/*! [Verify a table] */
- ret = session->verify(session, "table:mytable", NULL);
+ error_check(session->verify(session, "table:mytable", NULL));
/*! [Verify a table] */
/*! [Drop a table] */
- ret = session->drop(session, "table:mytable", NULL);
+ error_check(session->drop(session, "table:mytable", NULL));
/*! [Drop a table] */
}
/*! [Close a session] */
- ret = session->close(session, NULL);
+ error_check(session->close(session, NULL));
/*! [Close a session] */
-
- return (ret);
}
-int
+void
transaction_ops(WT_CONNECTION *conn, WT_SESSION *session)
{
WT_CURSOR *cursor;
- int ret;
/*! [transaction commit/rollback] */
/*
@@ -813,15 +787,15 @@ transaction_ops(WT_CONNECTION *conn, WT_SESSION *session)
* Opening cursors before the transaction begins allows applications to
* cache cursors and use them for multiple operations.
*/
- ret =
- session->open_cursor(session, "table:mytable", NULL, NULL, &cursor);
- ret = session->begin_transaction(session, NULL);
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
+ error_check(session->begin_transaction(session, NULL));
cursor->set_key(cursor, "key");
cursor->set_value(cursor, "value");
- switch (ret = cursor->update(cursor)) {
+ switch (cursor->update(cursor)) {
case 0: /* Update success */
- ret = session->commit_transaction(session, NULL);
+ error_check(session->commit_transaction(session, NULL));
/*
* If commit_transaction succeeds, cursors remain positioned; if
* commit_transaction fails, the transaction was rolled-back and
@@ -830,7 +804,7 @@ transaction_ops(WT_CONNECTION *conn, WT_SESSION *session)
break;
case WT_ROLLBACK: /* Update conflict */
default: /* Other error */
- ret = session->rollback_transaction(session, NULL);
+ error_check(session->rollback_transaction(session, NULL));
/* The rollback_transaction call resets all cursors. */
break;
}
@@ -839,28 +813,28 @@ transaction_ops(WT_CONNECTION *conn, WT_SESSION *session)
* Cursors remain open and may be used for multiple transactions.
*/
/*! [transaction commit/rollback] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [transaction isolation] */
/* A single transaction configured for snapshot isolation. */
- ret =
- session->open_cursor(session, "table:mytable", NULL, NULL, &cursor);
- ret = session->begin_transaction(session, "isolation=snapshot");
+ error_check(session->open_cursor(
+ session, "table:mytable", NULL, NULL, &cursor));
+ error_check(session->begin_transaction(session, "isolation=snapshot"));
cursor->set_key(cursor, "some-key");
cursor->set_value(cursor, "some-value");
- ret = cursor->update(cursor);
- ret = session->commit_transaction(session, NULL);
+ error_check(cursor->update(cursor));
+ error_check(session->commit_transaction(session, NULL));
/*! [transaction isolation] */
/*! [session isolation configuration] */
/* Open a session configured for read-uncommitted isolation. */
- ret = conn->open_session(
- conn, NULL, "isolation=read_uncommitted", &session);
+ error_check(conn->open_session(
+ conn, NULL, "isolation=read_uncommitted", &session));
/*! [session isolation configuration] */
/*! [session isolation re-configuration] */
/* Re-configure a session for snapshot isolation. */
- ret = session->reconfigure(session, "isolation=snapshot");
+ error_check(session->reconfigure(session, "isolation=snapshot"));
/*! [session isolation re-configuration] */
{
@@ -868,11 +842,30 @@ transaction_ops(WT_CONNECTION *conn, WT_SESSION *session)
/* Check the transaction ID range pinned by the session handle. */
uint64_t range;
- ret = session->transaction_pinned_range(session, &range);
+ error_check(session->transaction_pinned_range(session, &range));
/*! [transaction pinned range] */
}
- return (ret);
+ /*! [transaction timestamp] */
+ error_check(
+ session->timestamp_transaction(session, "commit_timestamp=2a"));
+ /*! [transaction timestamp] */
+
+ {
+#ifndef WT_TIMESTAMP_SIZE
+#define WT_TIMESTAMP_SIZE 8
+#endif
+ /*! [query timestamp] */
+ char timestamp_buf[2 * WT_TIMESTAMP_SIZE + 1];
+
+ error_check(conn->query_timestamp(
+ conn, timestamp_buf, "get=all_committed"));
+ /*! [query timestamp] */
+ }
+
+ /*! [set oldest timestamp] */
+ error_check(conn->set_timestamp(conn, "oldest_timestamp=2a"));
+ /*! [set oldest timestamp] */
}
/*! [Implement WT_COLLATOR] */
@@ -899,17 +892,14 @@ my_compare(WT_COLLATOR *collator, WT_SESSION *session,
}
/*! [Implement WT_COLLATOR] */
-int
+void
add_collator(WT_CONNECTION *conn)
{
- int ret;
-
/*! [WT_COLLATOR register] */
static WT_COLLATOR my_collator = { my_compare, NULL, NULL };
- ret = conn->add_collator(conn, "my_collator", &my_collator, NULL);
+ error_check(conn->add_collator(
+ conn, "my_collator", &my_collator, NULL));
/*! [WT_COLLATOR register] */
-
- return (ret);
}
/*! [WT_EXTRACTOR] */
@@ -928,40 +918,35 @@ my_extract(WT_EXTRACTOR *extractor, WT_SESSION *session,
}
/*! [WT_EXTRACTOR] */
-int
+void
add_extractor(WT_CONNECTION *conn)
{
- int ret;
-
/*! [WT_EXTRACTOR register] */
static WT_EXTRACTOR my_extractor = {my_extract, NULL, NULL};
- ret = conn->add_extractor(conn, "my_extractor", &my_extractor, NULL);
+ error_check(conn->add_extractor(
+ conn, "my_extractor", &my_extractor, NULL));
/*! [WT_EXTRACTOR register] */
-
- return (ret);
}
-int
+void
connection_ops(WT_CONNECTION *conn)
{
- int ret;
-
#ifdef MIGHT_NOT_RUN
/*! [Load an extension] */
- ret = conn->load_extension(conn, "my_extension.dll", NULL);
+ error_check(conn->load_extension(conn, "my_extension.dll", NULL));
- ret = conn->load_extension(conn,
+ error_check(conn->load_extension(conn,
"datasource/libdatasource.so",
- "config=[device=/dev/sd1,alignment=64]");
+ "config=[device=/dev/sd1,alignment=64]"));
/*! [Load an extension] */
#endif
- ret = add_collator(conn);
- ret = add_extractor(conn);
+ add_collator(conn);
+ add_extractor(conn);
/*! [Reconfigure a connection] */
- ret = conn->reconfigure(conn, "eviction_target=75");
+ error_check(conn->reconfigure(conn, "eviction_target=75"));
/*! [Reconfigure a connection] */
/*! [Get the database home directory] */
@@ -984,17 +969,17 @@ connection_ops(WT_CONNECTION *conn)
* period and the method name (for example, session create would be
* "WT_SESSION.create" and cursor close would be WT_CURSOR.close").
*/
- ret = wiredtiger_config_validate(
- NULL, NULL, "WT_SESSION.create", "allocation_size=32KB");
+ error_check(wiredtiger_config_validate(
+ NULL, NULL, "WT_SESSION.create", "allocation_size=32KB"));
/*! [Validate a configuration string] */
{
/*! [Open a session] */
WT_SESSION *session;
- ret = conn->open_session(conn, NULL, NULL, &session);
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/*! [Open a session] */
- ret = session_ops(session);
+ session_ops(session);
}
/*! [Configure method configuration] */
@@ -1006,43 +991,40 @@ connection_ops(WT_CONNECTION *conn)
* The method being configured is specified using a concatenation of the
* handle name, a period and the method name.
*/
- ret = conn->configure_method(conn,
+ error_check(conn->configure_method(conn,
"WT_SESSION.open_cursor",
- "my_data:", "entries=5", "int", "min=1,max=10");
+ "my_data:", "entries=5", "int", "min=1,max=10"));
/*
* Applications opening a cursor for the data-source object "my_data"
* have an additional configuration option "devices", which is a list
* of strings.
*/
- ret = conn->configure_method(conn,
- "WT_SESSION.open_cursor", "my_data:", "devices", "list", NULL);
+ error_check(conn->configure_method(conn,
+ "WT_SESSION.open_cursor", "my_data:", "devices", "list", NULL));
/*! [Configure method configuration] */
/*! [Close a connection] */
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Close a connection] */
-
- return (ret);
}
-int
+void
pack_ops(WT_SESSION *session)
{
- int ret;
-
{
/*! [Get the packed size] */
size_t size;
- ret = wiredtiger_struct_size(session, &size, "iSh", 42, "hello", -3);
+ error_check(wiredtiger_struct_size(
+ session, &size, "iSh", 42, "hello", -3));
/*! [Get the packed size] */
}
{
/*! [Pack fields into a buffer] */
char buf[100];
- ret = wiredtiger_struct_pack(
- session, buf, sizeof(buf), "iSh", 42, "hello", -3);
+ error_check(wiredtiger_struct_pack(
+ session, buf, sizeof(buf), "iSh", 42, "hello", -3));
/*! [Pack fields into a buffer] */
{
@@ -1050,16 +1032,14 @@ pack_ops(WT_SESSION *session)
int i;
char *s;
short h;
- ret = wiredtiger_struct_unpack(
- session, buf, sizeof(buf), "iSh", &i, &s, &h);
+ error_check(wiredtiger_struct_unpack(
+ session, buf, sizeof(buf), "iSh", &i, &s, &h));
/*! [Unpack fields from a buffer] */
}
}
-
- return (ret);
}
-int
+void
backup(WT_SESSION *session)
{
char buf[1024];
@@ -1070,66 +1050,51 @@ backup(WT_SESSION *session)
int ret;
/* Create the backup directory. */
- ret = mkdir("/path/database.backup", 077);
+ error_check(mkdir("/path/database.backup", 077));
/* Open the backup data source. */
- ret = session->open_cursor(session, "backup:", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "backup:", NULL, NULL, &cursor));
/* Copy the list of files. */
- while (
- (ret = cursor->next(cursor)) == 0 &&
- (ret = cursor->get_key(cursor, &filename)) == 0) {
+ while ((ret = cursor->next(cursor)) == 0) {
+ error_check(cursor->get_key(cursor, &filename));
(void)snprintf(buf, sizeof(buf),
"cp /path/database/%s /path/database.backup/%s",
filename, filename);
- ret = system(buf);
+ error_check(system(buf));
}
- if (ret == WT_NOTFOUND)
- ret = 0;
- if (ret != 0)
- fprintf(stderr, "%s: cursor next(backup:) failed: %s\n",
- progname, session->strerror(session, ret));
+ scan_end_check(ret == WT_NOTFOUND);
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [backup]*/
/*! [incremental backup]*/
/* Open the backup data source for incremental backup. */
- ret = session->open_cursor(
- session, "backup:", NULL, "target=(\"log:\")", &cursor);
+ error_check(session->open_cursor(
+ session, "backup:", NULL, "target=(\"log:\")", &cursor));
/*! [incremental backup]*/
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [backup of a checkpoint]*/
- ret = session->checkpoint(session, "drop=(from=June01),name=June01");
+ error_check(session->checkpoint(
+ session, "drop=(from=June01),name=June01"));
/*! [backup of a checkpoint]*/
-
- return (ret);
}
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
- int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/*! [Open a connection] */
- ret = wiredtiger_open(home, NULL,
- "create,cache_size=5GB,log=(enabled,recover=on)", &conn);
+ error_check(wiredtiger_open(home, NULL,
+ "create,cache_size=5GB,log=(enabled,recover=on)", &conn));
/*! [Open a connection] */
- if (ret == 0)
- ret = connection_ops(conn);
+ connection_ops(conn);
/*
* The connection has been closed.
*/
@@ -1141,54 +1106,48 @@ main(void)
* the code snippets, use #ifdef's to avoid running it.
*/
/*! [Configure lz4 extension] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,"
- "extensions=[/usr/local/lib/libwiredtiger_lz4.so]", &conn);
+ "extensions=[/usr/local/lib/libwiredtiger_lz4.so]", &conn));
/*! [Configure lz4 extension] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Configure snappy extension] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,"
- "extensions=[/usr/local/lib/libwiredtiger_snappy.so]", &conn);
+ "extensions=[/usr/local/lib/libwiredtiger_snappy.so]", &conn));
/*! [Configure snappy extension] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Configure zlib extension] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,"
- "extensions=[/usr/local/lib/libwiredtiger_zlib.so]", &conn);
+ "extensions=[/usr/local/lib/libwiredtiger_zlib.so]", &conn));
/*! [Configure zlib extension] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Configure zlib extension with compression level] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,"
"extensions=[/usr/local/lib/"
- "libwiredtiger_zlib.so=[config=[compression_level=3]]]", &conn);
+ "libwiredtiger_zlib.so=[config=[compression_level=3]]]", &conn));
/*! [Configure zlib extension with compression level] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Configure zstd extension] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,"
- "extensions=[/usr/local/lib/libwiredtiger_zstd.so]", &conn);
+ "extensions=[/usr/local/lib/libwiredtiger_zstd.so]", &conn));
/*! [Configure zstd extension] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Configure zstd extension with compression level] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,"
"extensions=[/usr/local/lib/"
- "libwiredtiger_zstd.so=[config=[compression_level=9]]]", &conn);
+ "libwiredtiger_zstd.so=[config=[compression_level=9]]]", &conn));
/*! [Configure zstd extension with compression level] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*
* This example code gets run, and direct I/O might not be available,
@@ -1197,82 +1156,74 @@ main(void)
*/
/* Might Not Run: direct I/O may not be available. */
/*! [Configure direct_io for data files] */
- ret = wiredtiger_open(home, NULL, "create,direct_io=[data]", &conn);
+ error_check(wiredtiger_open(
+ home, NULL, "create,direct_io=[data]", &conn));
/*! [Configure direct_io for data files] */
- if (ret == 0)
- (void)conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
#endif
/*! [Configure file_extend] */
- ret = wiredtiger_open(
- home, NULL, "create,file_extend=(data=16MB)", &conn);
+ error_check(wiredtiger_open(
+ home, NULL, "create,file_extend=(data=16MB)", &conn));
/*! [Configure file_extend] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Eviction configuration] */
/*
* Configure eviction to begin at 90% full, and run until the cache
* is only 75% dirty.
*/
- ret = wiredtiger_open(home, NULL,
- "create,eviction_trigger=90,eviction_dirty_target=75", &conn);
+ error_check(wiredtiger_open(home, NULL,
+ "create,eviction_trigger=90,eviction_dirty_target=75", &conn));
/*! [Eviction configuration] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Eviction worker configuration] */
/* Configure up to four eviction threads */
- ret = wiredtiger_open(home, NULL,
- "create,eviction_trigger=90,eviction=(threads_max=4)", &conn);
+ error_check(wiredtiger_open(home, NULL,
+ "create,eviction_trigger=90,eviction=(threads_max=4)", &conn));
/*! [Eviction worker configuration] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Statistics configuration] */
- ret = wiredtiger_open(home, NULL, "create,statistics=(all)", &conn);
+ error_check(wiredtiger_open(
+ home, NULL, "create,statistics=(all)", &conn));
/*! [Statistics configuration] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [Statistics logging] */
- ret = wiredtiger_open(
- home, NULL, "create,statistics_log=(wait=30)", &conn);
+ error_check(wiredtiger_open(
+ home, NULL, "create,statistics_log=(wait=30)", &conn));
/*! [Statistics logging] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
#ifdef MIGHT_NOT_RUN
/*
* Don't run this code, statistics logging doesn't yet support tables.
*/
/*! [Statistics logging with a table] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create, statistics_log=("
- "sources=(\"table:table1\",\"table:table2\"), wait=5)",
- &conn);
+ "sources=(\"table:table1\",\"table:table2\"), wait=5)", &conn));
/*! [Statistics logging with a table] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*
* Don't run this code, statistics logging doesn't yet support indexes.
*/
/*! [Statistics logging with a source type] */
- ret = wiredtiger_open(home, NULL,
- "create, statistics_log=(sources=(\"index:\"), wait=5)",
- &conn);
+ error_check(wiredtiger_open(home, NULL,
+ "create, statistics_log=(sources=(\"index:\"), wait=5)", &conn));
/*! [Statistics logging with a source type] */
- if (ret == 0)
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*
* Don't run this code, because memory checkers get very upset when we
* leak memory.
*/
- (void)wiredtiger_open(home, NULL, "create", &conn);
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
/*! [Connection close leaking memory] */
- ret = conn->close(conn, "leak_memory=true");
+ error_check(conn->close(conn, "leak_memory=true"));
/*! [Connection close leaking memory] */
#endif
@@ -1289,5 +1240,5 @@ main(void)
/*! [Get the WiredTiger library version #2] */
}
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_async.c b/src/third_party/wiredtiger/examples/c/ex_async.c
index 83cddc2824d..3c7f5f55cd8 100644
--- a/src/third_party/wiredtiger/examples/c/ex_async.c
+++ b/src/third_party/wiredtiger/examples/c/ex_async.c
@@ -28,19 +28,9 @@
* ex_async.c
* demonstrates how to use the asynchronous API.
*/
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#include "windows_shim.h"
-#endif
+#include <test_util.h>
-#include <wiredtiger.h>
+static const char *home;
#if defined(_lint)
#define ATOMIC_ADD(v, val) ((v) += (val), (v))
@@ -67,12 +57,9 @@ async_callback(WT_ASYNC_CALLBACK *cb,
WT_ITEM k, v;
const char *key, *value;
uint64_t id;
- int ret;
(void)flags; /* Unused */
- ret = 0;
-
/*! [async get type] */
/* Retrieve the operation's WT_ASYNC_OPTYPE type. */
type = op->get_type(op);
@@ -96,17 +83,17 @@ async_callback(WT_ASYNC_CALLBACK *cb,
/* If doing a search, retrieve the key/value pair. */
if (type == WT_AOP_SEARCH) {
/*! [async get the operation's string key] */
- ret = op->get_key(op, &k);
+ error_check(op->get_key(op, &k));
key = k.data;
/*! [async get the operation's string key] */
/*! [async get the operation's string value] */
- ret = op->get_value(op, &v);
+ error_check(op->get_value(op, &v));
value = v.data;
/*! [async get the operation's string value] */
ATOMIC_ADD(asynckey->num_keys, 1);
printf("Id %" PRIu64 " got record: %s : %s\n", id, key, value);
}
- return (ret);
+ return (0);
}
/*! [async example callback implementation] */
@@ -115,35 +102,26 @@ static ASYNC_KEYS ex_asynckeys = { {async_callback}, 0 };
#define MAX_KEYS 15
int
-main(void)
+main(int argc, char *argv[])
{
WT_ASYNC_OP *op;
WT_CONNECTION *conn;
WT_SESSION *session;
int i, ret;
- const char *home;
char k[MAX_KEYS][16], v[MAX_KEYS][16];
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/*! [async example connection] */
- ret = wiredtiger_open(home, NULL,
+ error_check(wiredtiger_open(home, NULL,
"create,cache_size=100MB,"
- "async=(enabled=true,ops_max=20,threads=2)", &conn);
+ "async=(enabled=true,ops_max=20,threads=2)", &conn));
/*! [async example connection] */
/*! [async example table create] */
- ret = conn->open_session(conn, NULL, NULL, &session);
- ret = session->create(
- session, "table:async", "key_format=S,value_format=S");
+ error_check(conn->open_session(conn, NULL, NULL, &session));
+ error_check(session->create(
+ session, "table:async", "key_format=S,value_format=S"));
/*! [async example table create] */
/* Insert a set of keys asynchronously. */
@@ -179,22 +157,22 @@ main(void)
op->set_value(op, v[i]);
/*! [async set the operation's string value] */
- ret = op->insert(op);
+ error_check(op->insert(op));
/*! [async insert] */
}
/*! [async flush] */
/* Wait for all outstanding operations to complete. */
- ret = conn->async_flush(conn);
+ error_check(conn->async_flush(conn));
/*! [async flush] */
/*! [async compaction] */
/*
* Compact a table asynchronously, limiting the run-time to 5 minutes.
*/
- ret = conn->async_new_op(
- conn, "table:async", "timeout=300", &ex_asynckeys.iface, &op);
- ret = op->compact(op);
+ error_check(conn->async_new_op(
+ conn, "table:async", "timeout=300", &ex_asynckeys.iface, &op));
+ error_check(op->compact(op));
/*! [async compaction] */
/* Search for the keys we just inserted, asynchronously. */
@@ -220,7 +198,7 @@ main(void)
*/
(void)snprintf(k[i], sizeof(k), "key%d", i);
op->set_key(op, k[i]);
- ret = op->search(op);
+ error_check(op->search(op));
/*! [async search] */
}
@@ -228,9 +206,9 @@ main(void)
* Connection close automatically does an async_flush so it will wait
* for all queued search operations to complete.
*/
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
printf("Searched for %" PRIu32 " keys\n", ex_asynckeys.num_keys);
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_backup.c b/src/third_party/wiredtiger/examples/c/ex_backup.c
index ff7d979f286..9cd9d5cf2a0 100644
--- a/src/third_party/wiredtiger/examples/c/ex_backup.c
+++ b/src/third_party/wiredtiger/examples/c/ex_backup.c
@@ -28,18 +28,7 @@
* ex_backup.c
* demonstrates how to use incremental backup and log files.
*/
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#else
-/* snprintf is not supported on <= VS2013 */
-#define snprintf _snprintf
-#endif
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char * const home = "WT_HOME_LOG";
static const char * const home_full = "WT_HOME_LOG_FULL";
@@ -78,14 +67,14 @@ compare_backups(int i)
(void)snprintf(buf, sizeof(buf),
"../../wt -R -h %s.%d dump logtest > %s.%d",
home_full, i, full_out, i);
- ret = system(buf);
+ error_check(system(buf));
/*
* Now run dump on the incremental directory.
*/
(void)snprintf(buf, sizeof(buf),
"../../wt -R -h %s.%d dump logtest > %s.%d",
home_incr, i, incr_out, i);
- ret = system(buf);
+ error_check(system(buf));
/*
* Compare the files.
@@ -110,7 +99,7 @@ compare_backups(int i)
(void)snprintf(buf, sizeof(buf),
"rm -rf %s.%d %s.%d %s.%d %s.%d",
home_full, i, home_incr, i, full_out, i, incr_out, i);
- ret = system(buf);
+ error_check(system(buf));
}
return (ret);
}
@@ -120,10 +109,10 @@ compare_backups(int i)
* directory for each iteration and an incremental backup for each iteration.
* That way we can compare the full and incremental each time through.
*/
-static int
+static void
setup_directories(void)
{
- int i, ret;
+ int i;
char buf[1024];
for (i = 0; i < MAX_ITERATIONS; i++) {
@@ -133,10 +122,7 @@ setup_directories(void)
*/
(void)snprintf(buf, sizeof(buf),
"rm -rf %s.%d && mkdir %s.%d", home_incr, i, home_incr, i);
- if ((ret = system(buf)) != 0) {
- fprintf(stderr, "%s: failed ret %d\n", buf, ret);
- return (ret);
- }
+ error_check(system(buf));
if (i == 0)
continue;
/*
@@ -144,22 +130,18 @@ setup_directories(void)
*/
(void)snprintf(buf, sizeof(buf),
"rm -rf %s.%d && mkdir %s.%d", home_full, i, home_full, i);
- if ((ret = system(buf)) != 0) {
- fprintf(stderr, "%s: failed ret %d\n", buf, ret);
- return (ret);
- }
+ error_check(system(buf));
}
- return (0);
}
-static int
+static void
add_work(WT_SESSION *session, int iter)
{
WT_CURSOR *cursor;
- int i, ret;
+ int i;
char k[32], v[32];
- ret = session->open_cursor(session, uri, NULL, NULL, &cursor);
+ error_check(session->open_cursor(session, uri, NULL, NULL, &cursor));
/*
* Perform some operations with individual auto-commit transactions.
*/
@@ -168,13 +150,12 @@ add_work(WT_SESSION *session, int iter)
(void)snprintf(v, sizeof(v), "value.%d.%d", iter, i);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = cursor->close(cursor);
- return (ret);
+ error_check(cursor->close(cursor));
}
-static int
+static void
take_full_backup(WT_SESSION *session, int i)
{
WT_CURSOR *cursor;
@@ -191,10 +172,11 @@ take_full_backup(WT_SESSION *session, int i)
hdir = h;
} else
hdir = home_incr;
- ret = session->open_cursor(session, "backup:", NULL, NULL, &cursor);
+ error_check(
+ session->open_cursor(session, "backup:", NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &filename);
+ error_check(cursor->get_key(cursor, &filename));
if (i == 0)
/*
* Take a full backup into each incremental directory.
@@ -205,23 +187,20 @@ take_full_backup(WT_SESSION *session, int i)
(void)snprintf(buf, sizeof(buf),
"cp %s/%s %s/%s",
home, filename, h, filename);
- ret = system(buf);
+ error_check(system(buf));
}
else {
(void)snprintf(h, sizeof(h), "%s.%d", home_full, i);
(void)snprintf(buf, sizeof(buf), "cp %s/%s %s/%s",
home, filename, hdir, filename);
- ret = system(buf);
+ error_check(system(buf));
}
}
- if (ret != WT_NOTFOUND)
- fprintf(stderr,
- "WT_CURSOR.next: %s\n", session->strerror(session, ret));
- ret = cursor->close(cursor);
- return (ret);
+ scan_end_check(ret == WT_NOTFOUND);
+ error_check(cursor->close(cursor));
}
-static int
+static void
take_incr_backup(WT_SESSION *session, int i)
{
WT_CURSOR *cursor;
@@ -229,11 +208,11 @@ take_incr_backup(WT_SESSION *session, int i)
char buf[1024], h[256];
const char *filename;
- ret = session->open_cursor(session, "backup:",
- NULL, "target=(\"log:\")", &cursor);
+ error_check(session->open_cursor(
+ session, "backup:", NULL, "target=(\"log:\")", &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &filename);
+ error_check(cursor->get_key(cursor, &filename));
/*
* Copy into the 0 incremental directory and then each of the
* incremental directories for this iteration and later.
@@ -241,90 +220,84 @@ take_incr_backup(WT_SESSION *session, int i)
(void)snprintf(h, sizeof(h), "%s.0", home_incr);
(void)snprintf(buf, sizeof(buf), "cp %s/%s %s/%s",
home, filename, h, filename);
- ret = system(buf);
+ error_check(system(buf));
for (j = i; j < MAX_ITERATIONS; j++) {
(void)snprintf(h, sizeof(h), "%s.%d", home_incr, j);
(void)snprintf(buf, sizeof(buf), "cp %s/%s %s/%s",
home, filename, h, filename);
- ret = system(buf);
+ error_check(system(buf));
}
}
- if (ret != WT_NOTFOUND)
- fprintf(stderr,
- "WT_CURSOR.next: %s\n", session->strerror(session, ret));
- ret = 0;
+ scan_end_check(ret == WT_NOTFOUND);
+
/*
* With an incremental cursor, we want to truncate on the backup
* cursor to archive the logs. Only do this if the copy process
* was entirely successful.
*/
- ret = session->truncate(session, "log:", cursor, NULL, NULL);
- ret = cursor->close(cursor);
- return (ret);
+ error_check(session->truncate(session, "log:", cursor, NULL, NULL));
+ error_check(cursor->close(cursor));
}
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *wt_conn;
WT_SESSION *session;
- int i, ret;
+ int i;
char cmd_buf[256];
+ (void)argc; /* Unused variable */
+ (void)testutil_set_progname(argv);
+
(void)snprintf(cmd_buf, sizeof(cmd_buf),
"rm -rf %s && mkdir %s", home, home);
- if ((ret = system(cmd_buf)) != 0) {
- fprintf(stderr, "%s: failed ret %d\n", cmd_buf, ret);
- return (EXIT_FAILURE);
- }
- if ((ret = wiredtiger_open(home, NULL, CONN_CONFIG, &wt_conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(system(cmd_buf));
+ error_check(wiredtiger_open(home, NULL, CONN_CONFIG, &wt_conn));
- ret = setup_directories();
- ret = wt_conn->open_session(wt_conn, NULL, NULL, &session);
- ret = session->create(session, uri, "key_format=S,value_format=S");
+ setup_directories();
+ error_check(wt_conn->open_session(wt_conn, NULL, NULL, &session));
+ error_check(session->create(
+ session, uri, "key_format=S,value_format=S"));
printf("Adding initial data\n");
- ret = add_work(session, 0);
+ add_work(session, 0);
printf("Taking initial backup\n");
- ret = take_full_backup(session, 0);
+ take_full_backup(session, 0);
- ret = session->checkpoint(session, NULL);
+ error_check(session->checkpoint(session, NULL));
for (i = 1; i < MAX_ITERATIONS; i++) {
printf("Iteration %d: adding data\n", i);
- ret = add_work(session, i);
- ret = session->checkpoint(session, NULL);
+ add_work(session, i);
+ error_check(session->checkpoint(session, NULL));
/*
* The full backup here is only needed for testing and
* comparison purposes. A normal incremental backup
* procedure would not include this.
*/
printf("Iteration %d: taking full backup\n", i);
- ret = take_full_backup(session, i);
+ take_full_backup(session, i);
/*
* Taking the incremental backup also calls truncate
* to archive the log files, if the copies were successful.
* See that function for details on that call.
*/
printf("Iteration %d: taking incremental backup\n", i);
- ret = take_incr_backup(session, i);
+ take_incr_backup(session, i);
printf("Iteration %d: dumping and comparing data\n", i);
- ret = compare_backups(i);
+ error_check(compare_backups(i));
}
/*
* Close the connection. We're done and want to run the final
* comparison between the incremental and original.
*/
- ret = wt_conn->close(wt_conn, NULL);
+ error_check(wt_conn->close(wt_conn, NULL));
printf("Final comparison: dumping and comparing data\n");
- ret = compare_backups(0);
+ error_check(compare_backups(0));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_call_center.c b/src/third_party/wiredtiger/examples/c/ex_call_center.c
index 4483e8b1603..e4e4ab0b9cf 100644
--- a/src/third_party/wiredtiger/examples/c/ex_call_center.c
+++ b/src/third_party/wiredtiger/examples/c/ex_call_center.c
@@ -29,13 +29,7 @@
* This is an example application that demonstrates how to map a
* moderately complex SQL application into WiredTiger.
*/
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
@@ -76,9 +70,9 @@ typedef struct {
/*! [call-center decl] */
int
-main(void)
+main(int argc, char *argv[])
{
- int count, exact, ret;
+ int count, exact;
WT_CONNECTION *conn;
WT_SESSION *session;
WT_CURSOR *cursor;
@@ -95,84 +89,70 @@ main(void)
{ 0, 0, 0, 0, NULL, NULL }
};
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
-
- if ((ret = wiredtiger_open(home, NULL, "create", &conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
- /* Note: further error checking omitted for clarity. */
+ home = example_setup(argc, argv);
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
/*! [call-center work] */
- ret = conn->open_session(conn, NULL, NULL, &session);
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/*
* Create the customers table, give names and types to the columns.
* The columns will be stored in two groups: "main" and "address",
* created below.
*/
- ret = session->create(session, "table:customers",
+ error_check(session->create(session, "table:customers",
"key_format=r,"
"value_format=SSS,"
"columns=(id,name,address,phone),"
- "colgroups=(main,address)");
+ "colgroups=(main,address)"));
/* Create the main column group with value columns except address. */
- ret = session->create(session,
- "colgroup:customers:main", "columns=(name,phone)");
+ error_check(session->create(session,
+ "colgroup:customers:main", "columns=(name,phone)"));
/* Create the address column group with just the address. */
- ret = session->create(session,
- "colgroup:customers:address", "columns=(address)");
+ error_check(session->create(session,
+ "colgroup:customers:address", "columns=(address)"));
/* Create an index on the customer table by phone number. */
- ret = session->create(session,
- "index:customers:phone", "columns=(phone)");
+ error_check(session->create(session,
+ "index:customers:phone", "columns=(phone)"));
/* Populate the customers table with some data. */
- ret = session->open_cursor(
- session, "table:customers", NULL, "append", &cursor);
+ error_check(session->open_cursor(
+ session, "table:customers", NULL, "append", &cursor));
for (custp = cust_sample; custp->name != NULL; custp++) {
cursor->set_value(cursor,
custp->name, custp->address, custp->phone);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*
* Create the calls table, give names and types to the columns. All the
* columns will be stored together, so no column groups are declared.
*/
- ret = session->create(session, "table:calls",
+ error_check(session->create(session, "table:calls",
"key_format=r,"
"value_format=qrrSS,"
- "columns=(id,call_date,cust_id,emp_id,call_type,notes)");
+ "columns=(id,call_date,cust_id,emp_id,call_type,notes)"));
/*
* Create an index on the calls table with a composite key of cust_id
* and call_date.
*/
- ret = session->create(session, "index:calls:cust_date",
- "columns=(cust_id,call_date)");
+ error_check(session->create(session,
+ "index:calls:cust_date", "columns=(cust_id,call_date)"));
/* Populate the calls table with some data. */
- ret = session->open_cursor(
- session, "table:calls", NULL, "append", &cursor);
+ error_check(session->open_cursor(
+ session, "table:calls", NULL, "append", &cursor));
for (callp = call_sample; callp->call_type != NULL; callp++) {
cursor->set_value(cursor, callp->call_date, callp->cust_id,
callp->emp_id, callp->call_type, callp->notes);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*
* First query: a call arrives. In SQL:
@@ -187,16 +167,14 @@ main(void)
* Specify the columns we want: the customer ID and the name. This
* means the cursor's value format will be "rS".
*/
- ret = session->open_cursor(session,
- "index:customers:phone(id,name)", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "index:customers:phone(id,name)", NULL, NULL, &cursor));
cursor->set_key(cursor, "123-456-7890");
- ret = cursor->search(cursor);
- if (ret == 0) {
- ret = cursor->get_value(cursor, &cust.id, &cust.name);
- printf("Read customer record for %s (ID %" PRIu64 ")\n",
- cust.name, cust.id);
- }
- ret = cursor->close(cursor);
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &cust.id, &cust.name));
+ printf("Read customer record for %s (ID %" PRIu64 ")\n",
+ cust.name, cust.id);
+ error_check(cursor->close(cursor));
/*
* Next query: get the recent order history. In SQL:
@@ -211,9 +189,9 @@ main(void)
* all covered by the index, the primary would not have to be accessed.)
* Stop after getting 3 records.
*/
- ret = session->open_cursor(session,
+ error_check(session->open_cursor(session,
"index:calls:cust_date(cust_id,call_type,notes)",
- NULL, NULL, &cursor);
+ NULL, NULL, &cursor));
/*
* The keys in the index are (cust_id,call_date) -- we want the largest
@@ -222,7 +200,7 @@ main(void)
*/
cust.id = 1;
cursor->set_key(cursor, cust.id + 1, 0);
- ret = cursor->search_near(cursor, &exact);
+ error_check(cursor->search_near(cursor, &exact));
/*
* If the table is empty, search_near will return WT_NOTFOUND, else the
@@ -230,20 +208,20 @@ main(void)
* adjacent key if one does not. If the positioned key is equal to or
* larger than the search key, go back one.
*/
- if (ret == 0 && exact >= 0)
- ret = cursor->prev(cursor);
- for (count = 0; ret == 0 && count < 3; ++count) {
- ret = cursor->get_value(cursor,
- &call.cust_id, &call.call_type, &call.notes);
+ if (exact >= 0)
+ error_check(cursor->prev(cursor));
+ for (count = 0; count < 3; ++count) {
+ error_check(cursor->get_value(cursor,
+ &call.cust_id, &call.call_type, &call.notes));
if (call.cust_id != cust.id)
break;
printf("Call record: customer %" PRIu64 " (%s: %s)\n",
call.cust_id, call.call_type, call.notes);
- ret = cursor->prev(cursor);
+ error_check(cursor->prev(cursor));
}
/*! [call-center work] */
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_config_parse.c b/src/third_party/wiredtiger/examples/c/ex_config_parse.c
index c9720325129..8d418ffa186 100644
--- a/src/third_party/wiredtiger/examples/c/ex_config_parse.c
+++ b/src/third_party/wiredtiger/examples/c/ex_config_parse.c
@@ -29,44 +29,30 @@
* This is an example demonstrating how to parse WiredTiger compatible
* configuration strings.
*/
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
int
-main(void)
+main(int argc, char *argv[])
{
int ret;
+ (void)argc; /* Unused variable */
+ (void)testutil_set_progname(argv);
+
+ {
/*! [Create a configuration parser] */
WT_CONFIG_ITEM k, v;
WT_CONFIG_PARSER *parser;
const char *config_string =
"path=/dev/loop,page_size=1024,log=(archive=true,file_max=20MB)";
- if ((ret = wiredtiger_config_parser_open(
- NULL, config_string, strlen(config_string), &parser)) != 0) {
- fprintf(stderr, "Error creating configuration parser: %s\n",
- wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
- if ((ret = parser->close(parser)) != 0) {
- fprintf(stderr, "Error closing configuration parser: %s\n",
- wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser));
+ error_check(parser->close(parser));
/*! [Create a configuration parser] */
- if ((ret = wiredtiger_config_parser_open(
- NULL, config_string, strlen(config_string), &parser)) != 0) {
- fprintf(stderr, "Error creating configuration parser: %s\n",
- wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser));
{
/*! [get] */
@@ -74,26 +60,17 @@ main(void)
/*
* Retrieve the value of the integer configuration string "page_size".
*/
- if ((ret = parser->get(parser, "page_size", &v)) != 0) {
- fprintf(stderr,
- "page_size configuration: %s", wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(parser->get(parser, "page_size", &v));
my_page_size = v.val;
/*! [get] */
- ret = parser->close(parser);
-
- (void)my_page_size;
+ error_check(parser->close(parser));
+ (void)my_page_size; /* Unused variable */
}
{
- if ((ret = wiredtiger_config_parser_open(
- NULL, config_string, strlen(config_string), &parser)) != 0) {
- fprintf(stderr, "Error creating configuration parser: %s\n",
- wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser));
/*! [next] */
/*
* Retrieve and print the values of the configuration strings.
@@ -105,16 +82,13 @@ main(void)
else
printf("%.*s\n", (int)v.len, v.str);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [next] */
- ret = parser->close(parser);
+ error_check(parser->close(parser));
}
- if ((ret = wiredtiger_config_parser_open(
- NULL, config_string, strlen(config_string), &parser)) != 0) {
- fprintf(stderr, "Error creating configuration parser: %s\n",
- wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser));
/*! [nested get] */
/*
@@ -123,21 +97,13 @@ main(void)
* conversion of value strings into an integer.
*/
v.type = WT_CONFIG_ITEM_NUM;
- if ((ret = parser->get(parser, "log.file_max", &v)) != 0) {
- fprintf(stderr,
- "log.file_max configuration: %s", wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(parser->get(parser, "log.file_max", &v));
printf("log file max: %" PRId64 "\n", v.val);
/*! [nested get] */
- ret = parser->close(parser);
+ error_check(parser->close(parser));
- if ((ret = wiredtiger_config_parser_open(
- NULL, config_string, strlen(config_string), &parser)) != 0) {
- fprintf(stderr, "Error creating configuration parser: %s\n",
- wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_config_parser_open(
+ NULL, config_string, strlen(config_string), &parser));
/*! [nested traverse] */
{
WT_CONFIG_PARSER *sub_parser;
@@ -145,23 +111,20 @@ main(void)
if (v.type == WT_CONFIG_ITEM_STRUCT) {
printf("Found nested configuration: %.*s\n",
(int)k.len, k.str);
- if ((ret = wiredtiger_config_parser_open(
- NULL, v.str, v.len, &sub_parser)) != 0) {
- fprintf(stderr,
- "Error creating nested configuration "
- "parser: %s\n",
- wiredtiger_strerror(ret));
- break;
- }
+ error_check(wiredtiger_config_parser_open(
+ NULL, v.str, v.len, &sub_parser));
while ((ret =
sub_parser->next(sub_parser, &k, &v)) == 0)
printf("\t%.*s\n", (int)k.len, k.str);
- ret = sub_parser->close(sub_parser);
+ scan_end_check(ret == WT_NOTFOUND);
+ error_check(sub_parser->close(sub_parser));
}
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [nested traverse] */
- ret = parser->close(parser);
+ error_check(parser->close(parser));
+ }
}
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_cursor.c b/src/third_party/wiredtiger/examples/c/ex_cursor.c
index 0982aa43073..3a8700fb83c 100644
--- a/src/third_party/wiredtiger/examples/c/ex_cursor.c
+++ b/src/third_party/wiredtiger/examples/c/ex_cursor.c
@@ -28,12 +28,7 @@
* ex_cursor.c
* This is an example demonstrating some cursor types and operations.
*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
int cursor_reset(WT_CURSOR *cursor);
int cursor_forward_scan(WT_CURSOR *cursor);
@@ -54,10 +49,12 @@ cursor_forward_scan(WT_CURSOR *cursor)
int ret;
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &key);
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->get_key(cursor, &key));
+ error_check(cursor->get_value(cursor, &value));
}
- return (ret);
+ scan_end_check(ret == WT_NOTFOUND);
+
+ return (0);
}
/*! [cursor next] */
@@ -69,10 +66,12 @@ cursor_reverse_scan(WT_CURSOR *cursor)
int ret;
while ((ret = cursor->prev(cursor)) == 0) {
- ret = cursor->get_key(cursor, &key);
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->get_key(cursor, &key));
+ error_check(cursor->get_value(cursor, &value));
}
- return (ret);
+ scan_end_check(ret == WT_NOTFOUND);
+
+ return (0);
}
/*! [cursor prev] */
@@ -89,14 +88,13 @@ int
cursor_search(WT_CURSOR *cursor)
{
const char *value;
- int ret;
cursor->set_key(cursor, "foo");
- if ((ret = cursor->search(cursor)) == 0)
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &value));
- return (ret);
+ return (0);
}
/*! [cursor search] */
@@ -105,26 +103,24 @@ int
cursor_search_near(WT_CURSOR *cursor)
{
const char *key, *value;
- int exact, ret;
+ int exact;
cursor->set_key(cursor, "foo");
- if ((ret = cursor->search_near(cursor, &exact)) == 0) {
- switch (exact) {
- case -1: /* Returned key smaller than search key */
- ret = cursor->get_key(cursor, &key);
- break;
- case 0: /* Exact match found */
- break;
- case 1: /* Returned key larger than search key */
- ret = cursor->get_key(cursor, &key);
- break;
- }
-
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->search_near(cursor, &exact));
+ switch (exact) {
+ case -1: /* Returned key smaller than search key */
+ error_check(cursor->get_key(cursor, &key));
+ break;
+ case 0: /* Exact match found */
+ break;
+ case 1: /* Returned key larger than search key */
+ error_check(cursor->get_key(cursor, &key));
+ break;
}
+ error_check(cursor->get_value(cursor, &value));
- return (ret);
+ return (0);
}
/*! [cursor search near] */
@@ -160,71 +156,57 @@ cursor_remove(WT_CURSOR *cursor)
/*! [cursor remove] */
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_CURSOR *cursor;
WT_SESSION *session;
- int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/* Open a connection to the database, creating it if necessary. */
- if ((ret = wiredtiger_open(
- home, NULL, "create,statistics=(fast)", &conn)) != 0)
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
+ error_check(wiredtiger_open(
+ home, NULL, "create,statistics=(fast)", &conn));
/* Open a session for the current thread's work. */
- if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
- fprintf(stderr, "Error opening a session on %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
+ error_check(conn->open_session(conn, NULL, NULL, &session));
- ret = session->create(session, "table:world",
+ error_check(session->create(session, "table:world",
"key_format=r,value_format=5sii,"
- "columns=(id,country,population,area)");
+ "columns=(id,country,population,area)"));
/*! [open cursor #1] */
- ret = session->open_cursor(session, "table:world", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:world", NULL, NULL, &cursor));
/*! [open cursor #1] */
/*! [open cursor #2] */
- ret = session->open_cursor(session,
- "table:world(country,population)", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "table:world(country,population)", NULL, NULL, &cursor));
/*! [open cursor #2] */
/*! [open cursor #3] */
- ret = session->open_cursor(session, "statistics:", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "statistics:", NULL, NULL, &cursor));
/*! [open cursor #3] */
/* Create a simple string table to illustrate basic operations. */
- ret = session->create(session, "table:map",
- "key_format=S,value_format=S");
- ret = session->open_cursor(session, "table:map", NULL, NULL, &cursor);
- ret = cursor_insert(cursor);
- ret = cursor_reset(cursor);
- ret = cursor_forward_scan(cursor);
- ret = cursor_reset(cursor);
- ret = cursor_reverse_scan(cursor);
- ret = cursor_search_near(cursor);
- ret = cursor_update(cursor);
- ret = cursor_remove(cursor);
- ret = cursor->close(cursor);
+ error_check(session->create(
+ session, "table:map", "key_format=S,value_format=S"));
+ error_check(session->open_cursor(
+ session, "table:map", NULL, NULL, &cursor));
+ error_check(cursor_insert(cursor));
+ error_check(cursor_reset(cursor));
+ error_check(cursor_forward_scan(cursor));
+ error_check(cursor_reset(cursor));
+ error_check(cursor_reverse_scan(cursor));
+ error_check(cursor_search_near(cursor));
+ error_check(cursor_update(cursor));
+ error_check(cursor_remove(cursor));
+ error_check(cursor->close(cursor));
/* Note: closing the connection implicitly closes open session(s). */
- if ((ret = conn->close(conn, NULL)) != 0) {
- fprintf(stderr, "Error closing %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->close(conn, NULL));
return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_data_source.c b/src/third_party/wiredtiger/examples/c/ex_data_source.c
index d40008e0a0e..59cfde7313a 100644
--- a/src/third_party/wiredtiger/examples/c/ex_data_source.c
+++ b/src/third_party/wiredtiger/examples/c/ex_data_source.c
@@ -28,11 +28,7 @@
* ex_data_source.c
* demonstrates how to create and access a data source
*/
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <wiredtiger.h>
+#include <test_util.h>
/*! [WT_EXTENSION_API declaration] */
#include <wiredtiger_ext.h>
@@ -194,7 +190,6 @@ static int my_cursor_search_near(WT_CURSOR *wtcursor, int *exactp)
static int my_cursor_insert(WT_CURSOR *wtcursor)
{
WT_SESSION *session = NULL;
- int ret;
/* Unused parameters */
(void)wtcursor;
@@ -233,7 +228,7 @@ static int my_cursor_insert(WT_CURSOR *wtcursor)
/*! [WT_EXTENSION transaction notify] */
WT_TXN_NOTIFY handler;
handler.notify = data_source_notify;
- ret = wt_api->transaction_notify(wt_api, session, &handler);
+ error_check(wt_api->transaction_notify(wt_api, session, &handler));
/*! [WT_EXTENSION transaction notify] */
}
@@ -260,7 +255,8 @@ static int my_cursor_insert(WT_CURSOR *wtcursor)
second.data = key2;
second.size = key2_len;
- ret = wt_api->collate(wt_api, session, collator, &first, &second, &cmp);
+ error_check(wt_api->collate(
+ wt_api, session, collator, &first, &second, &cmp));
if (cmp == 0)
printf("key1 collates identically to key2\n");
else if (cmp < 0)
@@ -270,7 +266,7 @@ static int my_cursor_insert(WT_CURSOR *wtcursor)
/*! [WT_EXTENSION collate] */
}
- return (ret);
+ return (0);
}
static int my_cursor_update(WT_CURSOR *wtcursor)
@@ -296,6 +292,7 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
const char *uri, WT_CONFIG_ARG *config, WT_CURSOR **new_cursor)
{
MY_CURSOR *cursor;
+ int ret;
/* Allocate and initialize a WiredTiger cursor. */
if ((cursor = calloc(1, sizeof(*cursor))) == NULL)
@@ -320,7 +317,6 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
/*! [WT_DATA_SOURCE open_cursor] */
{
- int ret = 0;
(void)dsrc; /* Unused parameters */
(void)session;
(void)uri;
@@ -335,13 +331,8 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
* Retrieve the value of the boolean type configuration string
* "overwrite".
*/
- if ((ret = wt_api->config_get(
- wt_api, session, config, "overwrite", &v)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "overwrite configuration: %s",
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->config_get(
+ wt_api, session, config, "overwrite", &v));
my_data_source_overwrite = v.val != 0;
/*! [WT_EXTENSION_CONFIG boolean] */
@@ -357,13 +348,8 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
* Retrieve the value of the integer type configuration string
* "page_size".
*/
- if ((ret = wt_api->config_get(
- wt_api, session, config, "page_size", &v)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "page_size configuration: %s",
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->config_get(
+ wt_api, session, config, "page_size", &v));
my_data_source_page_size = v.val;
/*! [WT_EXTENSION_CONFIG integer] */
@@ -379,13 +365,8 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
* Retrieve the value of the string type configuration string
* "key_format".
*/
- if ((ret = wt_api->config_get(
- wt_api, session, config, "key_format", &v)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "key_format configuration: %s",
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->config_get(
+ wt_api, session, config, "key_format", &v));
/*
* Values returned from WT_EXTENSION_API::config in the str field are
@@ -407,20 +388,15 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
/*
* Configure the appropriate collator.
*/
- if ((ret = wt_api->collator_config(wt_api, session,
- "dsrc:", config, &collator, &collator_owned)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "collator configuration: %s",
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->collator_config(wt_api, session,
+ "dsrc:", config, &collator, &collator_owned));
/*! [WT_EXTENSION collator config] */
}
/*! [WT_DATA_SOURCE error message] */
/*
- * If an underlying function fails, log the error and then return an
- * error within WiredTiger's name space.
+ * If an underlying function fails, log the error and then return a
+ * non-zero value.
*/
if ((ret = data_source_cursor()) != 0) {
(void)wt_api->err_printf(wt_api,
@@ -437,12 +413,7 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
const char *key = "datasource_uri";
const char *value = "data source uri's record";
- if ((ret = wt_api->metadata_insert(wt_api, session, key, value)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "%s: metadata insert: %s", key,
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->metadata_insert(wt_api, session, key, value));
/*! [WT_EXTENSION metadata insert] */
}
@@ -453,12 +424,7 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
*/
const char *key = "datasource_uri";
- if ((ret = wt_api->metadata_remove(wt_api, session, key)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "%s: metadata remove: %s", key,
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->metadata_remove(wt_api, session, key));
/*! [WT_EXTENSION metadata remove] */
}
@@ -470,13 +436,7 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
const char *key = "datasource_uri";
char *value;
- if ((ret =
- wt_api->metadata_search(wt_api, session, key, &value)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "%s: metadata search: %s", key,
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->metadata_search(wt_api, session, key, &value));
printf("metadata: %s has a value of %s\n", key, value);
/*! [WT_EXTENSION metadata search] */
}
@@ -490,12 +450,7 @@ my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session,
const char *key = "datasource_uri";
const char *value = "data source uri's record";
- if ((ret = wt_api->metadata_update(wt_api, session, key, value)) != 0) {
- (void)wt_api->err_printf(wt_api, session,
- "%s: metadata update: %s", key,
- session->strerror(session, ret));
- return (ret);
- }
+ error_check(wt_api->metadata_update(wt_api, session, key, value));
/*! [WT_EXTENSION metadata update] */
}
@@ -604,16 +559,16 @@ my_terminate(WT_DATA_SOURCE *dsrc, WT_SESSION *session)
return (0);
}
+static const char *home;
+
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
- WT_SESSION *session;
- int ret;
- ret = wiredtiger_open(NULL, NULL, "create", &conn);
- ret = conn->open_session(conn, NULL, NULL, &session);
+ home = example_setup(argc, argv);
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
my_data_source_init(conn);
{
@@ -632,42 +587,43 @@ main(void)
my_checkpoint,
my_terminate
};
- ret = conn->add_data_source(conn, "dsrc:", &my_dsrc, NULL);
+ error_check(conn->add_data_source(conn, "dsrc:", &my_dsrc, NULL));
/*! [WT_DATA_SOURCE register] */
}
/*! [WT_DATA_SOURCE configure boolean] */
/* my_boolean defaults to true. */
- ret = conn->configure_method(conn,
- "WT_SESSION.open_cursor", NULL, "my_boolean=true", "boolean", NULL);
+ error_check(conn->configure_method(
+ conn, "WT_SESSION.open_cursor",
+ NULL, "my_boolean=true", "boolean", NULL));
/*! [WT_DATA_SOURCE configure boolean] */
/*! [WT_DATA_SOURCE configure integer] */
/* my_integer defaults to 5. */
- ret = conn->configure_method(conn,
- "WT_SESSION.open_cursor", NULL, "my_integer=5", "int", NULL);
+ error_check(conn->configure_method(conn,
+ "WT_SESSION.open_cursor", NULL, "my_integer=5", "int", NULL));
/*! [WT_DATA_SOURCE configure integer] */
/*! [WT_DATA_SOURCE configure string] */
/* my_string defaults to "name". */
- ret = conn->configure_method(conn,
- "WT_SESSION.open_cursor", NULL, "my_string=name", "string", NULL);
+ error_check(conn->configure_method(conn,
+ "WT_SESSION.open_cursor", NULL, "my_string=name", "string", NULL));
/*! [WT_DATA_SOURCE configure string] */
/*! [WT_DATA_SOURCE configure list] */
/* my_list defaults to "first" and "second". */
- ret = conn->configure_method(conn,
- "WT_SESSION.open_cursor",
- NULL, "my_list=[first, second]", "list", NULL);
+ error_check(conn->configure_method(
+ conn, "WT_SESSION.open_cursor",
+ NULL, "my_list=[first, second]", "list", NULL));
/*! [WT_DATA_SOURCE configure list] */
/*! [WT_DATA_SOURCE configure integer with checking] */
/*
* Limit the number of devices to between 1 and 30; the default is 5.
*/
- ret = conn->configure_method(conn,
+ error_check(conn->configure_method(conn,
"WT_SESSION.open_cursor",
- NULL, "devices=5", "int", "min=1, max=30");
+ NULL, "devices=5", "int", "min=1, max=30"));
/*! [WT_DATA_SOURCE configure integer with checking] */
/*! [WT_DATA_SOURCE configure string with checking] */
@@ -675,9 +631,9 @@ main(void)
* Limit the target string to one of /device, /home or /target; default
* to /home.
*/
- ret = conn->configure_method(conn,
+ error_check(conn->configure_method(conn,
"WT_SESSION.open_cursor", NULL, "target=/home", "string",
- "choices=[/device, /home, /target]");
+ "choices=[/device, /home, /target]"));
/*! [WT_DATA_SOURCE configure string with checking] */
/*! [WT_DATA_SOURCE configure list with checking] */
@@ -685,16 +641,16 @@ main(void)
* Limit the paths list to one or more of /device, /home, /mnt or
* /target; default to /mnt.
*/
- ret = conn->configure_method(conn,
+ error_check(conn->configure_method(conn,
"WT_SESSION.open_cursor", NULL, "paths=[/mnt]", "list",
- "choices=[/device, /home, /mnt, /target]");
+ "choices=[/device, /home, /mnt, /target]"));
/*! [WT_DATA_SOURCE configure list with checking] */
/*! [WT_EXTENSION_API default_session] */
(void)wt_api->msg_printf(wt_api, NULL, "configuration complete");
/*! [WT_EXTENSION_API default_session] */
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_encrypt.c b/src/third_party/wiredtiger/examples/c/ex_encrypt.c
index 1710d5af16f..b6277ede084 100644
--- a/src/third_party/wiredtiger/examples/c/ex_encrypt.c
+++ b/src/third_party/wiredtiger/examples/c/ex_encrypt.c
@@ -28,20 +28,7 @@
* ex_encrypt.c
* demonstrates how to use the encryption API.
*/
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#else
-#include "windows_shim.h"
-#endif
-
-#include <wiredtiger.h>
-#include <wiredtiger_ext.h>
+#include <test_util.h>
#ifdef _WIN32
/*
@@ -270,11 +257,12 @@ rotate_customize(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
my_crypto->keyid = my_crypto->password = NULL;
/*
- * Stash the keyid and the (optional) secret key
- * from the configuration string.
+ * Stash the keyid and the (optional) secret key from the configuration
+ * string.
*/
- if ((ret = extapi->config_get(extapi, session, encrypt_config,
- "keyid", &keyid)) == 0 && keyid.len != 0) {
+ error_check(extapi->config_get(
+ extapi, session, encrypt_config, "keyid", &keyid));
+ if (keyid.len != 0) {
if ((my_crypto->keyid = malloc(keyid.len + 1)) == NULL) {
ret = errno;
goto err;
@@ -283,8 +271,9 @@ rotate_customize(WT_ENCRYPTOR *encryptor, WT_SESSION *session,
my_crypto->keyid[keyid.len] = '\0';
}
- if ((ret = extapi->config_get(extapi, session, encrypt_config,
- "secretkey", &secret)) == 0 && secret.len != 0) {
+ ret = extapi->config_get(
+ extapi, session, encrypt_config, "secretkey", &secret);
+ if (ret == 0 && secret.len != 0) {
if ((my_crypto->password = malloc(secret.len + 1)) == NULL) {
ret = errno;
goto err;
@@ -357,7 +346,6 @@ add_my_encryptors(WT_CONNECTION *connection)
{
MY_CRYPTO *m;
WT_ENCRYPTOR *wt;
- int ret;
/*
* Initialize our top level encryptor.
@@ -371,9 +359,8 @@ add_my_encryptors(WT_CONNECTION *connection)
wt->customize = rotate_customize;
wt->terminate = rotate_terminate;
m->num_calls = 0;
- if ((ret = connection->add_encryptor(
- connection, "rotn", (WT_ENCRYPTOR *)m, NULL)) != 0)
- return (ret);
+ error_check(connection->add_encryptor(
+ connection, "rotn", (WT_ENCRYPTOR *)m, NULL));
return (0);
}
@@ -384,7 +371,7 @@ add_my_encryptors(WT_CONNECTION *connection)
* We wrote text messages into the log. Print them.
* This verifies we're decrypting properly.
*/
-static int
+static void
simple_walk_log(WT_SESSION *session)
{
WT_CURSOR *cursor;
@@ -393,13 +380,14 @@ simple_walk_log(WT_SESSION *session)
uint32_t fileid, log_file, log_offset, opcount, optype, rectype;
int found, ret;
- ret = session->open_cursor(session, "log:", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session, "log:", NULL, NULL, &cursor));
found = 0;
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &log_file, &log_offset, &opcount);
- ret = cursor->get_value(cursor, &txnid,
- &rectype, &optype, &fileid, &logrec_key, &logrec_value);
+ error_check(cursor->get_key(
+ cursor, &log_file, &log_offset, &opcount));
+ error_check(cursor->get_value(cursor, &txnid,
+ &rectype, &optype, &fileid, &logrec_key, &logrec_value));
if (rectype == WT_LOGREC_MESSAGE) {
found = 1;
@@ -407,14 +395,13 @@ simple_walk_log(WT_SESSION *session)
(char *)logrec_value.data);
}
}
- if (ret == WT_NOTFOUND)
- ret = 0;
- ret = cursor->close(cursor);
+ scan_end_check(ret == WT_NOTFOUND);
+
+ error_check(cursor->close(cursor));
if (found == 0) {
fprintf(stderr, "Did not find log messages.\n");
exit(EXIT_FAILURE);
}
- return (ret);
}
#define MAX_KEYS 20
@@ -434,7 +421,7 @@ simple_walk_log(WT_SESSION *session)
#define COMP_C "CCCCCCCCCCCCCCCCCC"
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_CURSOR *c1, *c2, *nc;
@@ -443,46 +430,37 @@ main(void)
char keybuf[16], valbuf[16];
char *key1, *key2, *key3, *val1, *val2, *val3;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
-
- ret = wiredtiger_open(home, NULL, WT_OPEN_CONFIG_GOOD, &conn);
+ home = example_setup(argc, argv);
- ret = conn->open_session(conn, NULL, NULL, &session);
+ error_check(wiredtiger_open(home, NULL, WT_OPEN_CONFIG_GOOD, &conn));
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/*
* Write a log record that is larger than the base 128 bytes and
* also should compress well.
*/
- ret = session->log_printf(session,
+ error_check(session->log_printf(session,
COMP_A COMP_B COMP_C COMP_A COMP_B COMP_C
COMP_A COMP_B COMP_C COMP_A COMP_B COMP_C
- "The quick brown fox jumps over the lazy dog ");
- ret = simple_walk_log(session);
+ "The quick brown fox jumps over the lazy dog "));
+ simple_walk_log(session);
/*
* Create and open some encrypted and not encrypted tables.
* Also use column store and compression for some tables.
*/
- ret = session->create(session, "table:crypto1",
+ error_check(session->create(session, "table:crypto1",
"encryption=(name=rotn,keyid=" USER1_KEYID"),"
"columns=(key0,value0),"
- "key_format=S,value_format=S");
- ret = session->create(session, "index:crypto1:byvalue",
+ "key_format=S,value_format=S"));
+ error_check(session->create(session, "index:crypto1:byvalue",
"encryption=(name=rotn,keyid=" USER1_KEYID"),"
- "columns=(value0,key0)");
- ret = session->create(session, "table:crypto2",
+ "columns=(value0,key0)"));
+ error_check(session->create(session, "table:crypto2",
"encryption=(name=rotn,keyid=" USER2_KEYID"),"
- "key_format=S,value_format=S");
- ret = session->create(session, "table:nocrypto",
- "key_format=S,value_format=S");
+ "key_format=S,value_format=S"));
+ error_check(session->create(session, "table:nocrypto",
+ "key_format=S,value_format=S"));
/*
* Send in an unknown keyid. WiredTiger will try to add in the
@@ -497,9 +475,12 @@ main(void)
exit(EXIT_FAILURE);
}
- ret = session->open_cursor(session, "table:crypto1", NULL, NULL, &c1);
- ret = session->open_cursor(session, "table:crypto2", NULL, NULL, &c2);
- ret = session->open_cursor(session, "table:nocrypto", NULL, NULL, &nc);
+ error_check(session->open_cursor(
+ session, "table:crypto1", NULL, NULL, &c1));
+ error_check(session->open_cursor(
+ session, "table:crypto2", NULL, NULL, &c2));
+ error_check(session->open_cursor(
+ session, "table:nocrypto", NULL, NULL, &nc));
/*
* Insert a set of keys and values. Insert the same data into
@@ -517,24 +498,25 @@ main(void)
c2->set_value(c2, valbuf);
nc->set_value(nc, valbuf);
- ret = c1->insert(c1);
- ret = c2->insert(c2);
- ret = nc->insert(nc);
+ error_check(c1->insert(c1));
+ error_check(c2->insert(c2));
+ error_check(nc->insert(nc));
if (i % 5 == 0)
- ret = session->log_printf(session,
- "Wrote %d records", i);
+ error_check(session->log_printf(
+ session, "Wrote %d records", i));
}
- ret = session->log_printf(session, "Done. Wrote %d total records", i);
+ error_check(session->log_printf(
+ session, "Done. Wrote %d total records", i));
while (c1->next(c1) == 0) {
- ret = c1->get_key(c1, &key1);
- ret = c1->get_value(c1, &val1);
+ error_check(c1->get_key(c1, &key1));
+ error_check(c1->get_value(c1, &val1));
printf("Read key %s; value %s\n", key1, val1);
}
- ret = simple_walk_log(session);
+ simple_walk_log(session);
printf("CLOSE\n");
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*
* We want to close and reopen so that we recreate the cache
@@ -542,29 +524,32 @@ main(void)
*/
printf("REOPEN and VERIFY encrypted data\n");
- ret = wiredtiger_open(home, NULL, WT_OPEN_CONFIG_GOOD, &conn);
+ error_check(wiredtiger_open(home, NULL, WT_OPEN_CONFIG_GOOD, &conn));
- ret = conn->open_session(conn, NULL, NULL, &session);
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/*
* Verify we can read the encrypted log after restart.
*/
- ret = simple_walk_log(session);
- ret = session->open_cursor(session, "table:crypto1", NULL, NULL, &c1);
- ret = session->open_cursor(session, "table:crypto2", NULL, NULL, &c2);
- ret = session->open_cursor(session, "table:nocrypto", NULL, NULL, &nc);
+ simple_walk_log(session);
+ error_check(session->open_cursor(
+ session, "table:crypto1", NULL, NULL, &c1));
+ error_check(session->open_cursor(
+ session, "table:crypto2", NULL, NULL, &c2));
+ error_check(session->open_cursor(
+ session, "table:nocrypto", NULL, NULL, &nc));
/*
* Read the same data from each cursor. All should be identical.
*/
while (c1->next(c1) == 0) {
- ret = c2->next(c2);
- ret = nc->next(nc);
- ret = c1->get_key(c1, &key1);
- ret = c1->get_value(c1, &val1);
- ret = c2->get_key(c2, &key2);
- ret = c2->get_value(c2, &val2);
- ret = nc->get_key(nc, &key3);
- ret = nc->get_value(nc, &val3);
+ error_check(c2->next(c2));
+ error_check(nc->next(nc));
+ error_check(c1->get_key(c1, &key1));
+ error_check(c1->get_value(c1, &val1));
+ error_check(c2->get_key(c2, &key2));
+ error_check(c2->get_value(c2, &val2));
+ error_check(nc->get_key(nc, &key3));
+ error_check(nc->get_value(nc, &val3));
if (strcmp(key1, key2) != 0)
fprintf(stderr, "Key1 %s and Key2 %s do not match\n",
@@ -588,7 +573,7 @@ main(void)
printf("Verified key %s; value %s\n", key1, val1);
}
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_event_handler.c b/src/third_party/wiredtiger/examples/c/ex_event_handler.c
index acd9d9beecc..d9ac4851bf7 100644
--- a/src/third_party/wiredtiger/examples/c/ex_event_handler.c
+++ b/src/third_party/wiredtiger/examples/c/ex_event_handler.c
@@ -27,13 +27,8 @@
*
* ex_event_handler.c
* Demonstrate how to use the WiredTiger event handler mechanism.
- *
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
@@ -94,12 +89,11 @@ handle_wiredtiger_message(
}
/*! [Function event_handler] */
-static int
+static void
config_event_handler(void)
{
WT_CONNECTION *conn;
WT_SESSION *session;
- int ret;
/*! [Configure event_handler] */
CUSTOM_EVENT_HANDLER event_handler;
@@ -111,35 +105,25 @@ config_event_handler(void)
event_handler.h.handle_close = NULL;
event_handler.app_id = "example_event_handler";
- ret = wiredtiger_open(home,
- (WT_EVENT_HANDLER *)&event_handler, "create", &conn);
+ error_check(wiredtiger_open(home,
+ (WT_EVENT_HANDLER *)&event_handler, "create", &conn));
/*! [Configure event_handler] */
/* Make an invalid API call, to ensure the event handler works. */
- printf("ex_event_handler: expect an error message to follow\n");
- ret = conn->open_session(conn, NULL, "isolation=invalid", &session);
-
- ret = conn->close(conn, NULL);
+ fprintf(stderr,
+ "ex_event_handler: expect an error message to follow:\n");
+ (void)conn->open_session(conn, NULL, "isolation=invalid", &session);
+ fprintf(stderr, "ex_event_handler: end of error message\n");
- return (ret);
+ error_check(conn->close(conn, NULL));
}
int
-main(void)
+main(int argc, char *argv[])
{
- int ret;
-
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
- ret = config_event_handler();
+ config_event_handler();
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_extending.c b/src/third_party/wiredtiger/examples/c/ex_extending.c
index 7364fa4bc9e..7a845c1f6ad 100644
--- a/src/third_party/wiredtiger/examples/c/ex_extending.c
+++ b/src/third_party/wiredtiger/examples/c/ex_extending.c
@@ -29,16 +29,7 @@
* This is an example demonstrating ways to extend WiredTiger with
* extractors, collators and loadable modules.
*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
-
-#ifdef _WIN32
-#define strcasecmp stricmp
-#endif
+#include <test_util.h>
static const char *home;
@@ -51,8 +42,8 @@ __compare_nocase(WT_COLLATOR *collator, WT_SESSION *session,
const char *s1 = (const char *)v1->data;
const char *s2 = (const char *)v2->data;
- (void)session; /* unused */
- (void)collator; /* unused */
+ (void)session; /* unused variable */
+ (void)collator; /* unused variable */
*cmp = strcasecmp(s1, s2);
return (0);
@@ -89,42 +80,29 @@ static PREFIX_COLLATOR pcoll10 = { {__compare_prefixes, NULL, NULL}, 10 };
/*! [n character comparator] */
int
-main(void)
+main(int argc, char *argv[])
{
- int ret;
WT_CONNECTION *conn;
WT_SESSION *session;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/* Open a connection to the database, creating it if necessary. */
- if ((ret = wiredtiger_open(home, NULL, "create", &conn)) != 0)
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
/*! [add collator nocase] */
- ret = conn->add_collator(conn, "nocase", &nocasecoll, NULL);
+ error_check(conn->add_collator(conn, "nocase", &nocasecoll, NULL));
/*! [add collator nocase] */
/*! [add collator prefix10] */
- ret = conn->add_collator(conn, "prefix10", &pcoll10.iface, NULL);
+ error_check(conn->add_collator(conn, "prefix10", &pcoll10.iface, NULL));
/* Open a session for the current thread's work. */
- if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0)
- fprintf(stderr, "Error opening a session on %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/* Do some work... */
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
/*! [add collator prefix10] */
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_extractor.c b/src/third_party/wiredtiger/examples/c/ex_extractor.c
index 3aaaf90ac90..245d279ca4b 100644
--- a/src/third_party/wiredtiger/examples/c/ex_extractor.c
+++ b/src/third_party/wiredtiger/examples/c/ex_extractor.c
@@ -28,18 +28,7 @@
* ex_extractor.c
* Example of how to use a WiredTiger custom index extractor extension.
*/
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <wiredtiger.h>
-
-#define RET_OK(ret) ((ret) == 0 || (ret) == WT_NOTFOUND)
-
-int add_extractor(WT_CONNECTION *conn);
+#include <test_util.h>
static const char *home;
@@ -73,19 +62,17 @@ static int
my_extract(WT_EXTRACTOR *extractor, WT_SESSION *session,
const WT_ITEM *key, const WT_ITEM *value, WT_CURSOR *result_cursor)
{
- char *last_name, *first_name;
uint16_t term_end, term_start, year;
- int ret;
+ char *last_name, *first_name;
/* Unused parameters */
(void)extractor;
(void)key;
/* Unpack the value. */
- if ((ret = wiredtiger_struct_unpack(
+ error_check(wiredtiger_struct_unpack(
session, value->data, value->size, "SSHH",
- &last_name, &first_name, &term_start, &term_end)) != 0)
- return (ret);
+ &last_name, &first_name, &term_start, &term_end));
/*
* We have overlapping years, so multiple records may share the same
@@ -103,12 +90,7 @@ my_extract(WT_EXTRACTOR *extractor, WT_SESSION *session,
"EXTRACTOR: index op for year %" PRIu16 ": %s %s\n",
year, first_name, last_name);
result_cursor->set_key(result_cursor, year);
- if ((ret = result_cursor->insert(result_cursor)) != 0) {
- fprintf(stderr,
- "EXTRACTOR: op year %" PRIu16 ": error %d\n",
- year, ret);
- return (ret);
- }
+ error_check(result_cursor->insert(result_cursor));
}
return (0);
}
@@ -126,23 +108,20 @@ my_extract_terminate(WT_EXTRACTOR *extractor, WT_SESSION *session)
return (0);
}
-int
+static void
add_extractor(WT_CONNECTION *conn)
{
- int ret;
-
static WT_EXTRACTOR my_extractor = {
my_extract, NULL, my_extract_terminate
};
- ret = conn->add_extractor(conn, "my_extractor", &my_extractor, NULL);
-
- return (ret);
+ error_check(conn->add_extractor(
+ conn, "my_extractor", &my_extractor, NULL));
}
/*
* Read the index by year and print out who was in office that year.
*/
-static int
+static void
read_index(WT_SESSION *session)
{
WT_CURSOR *cursor;
@@ -152,96 +131,90 @@ read_index(WT_SESSION *session)
year = 0;
srand((unsigned int)getpid());
- ret = session->open_cursor(
- session, "index:presidents:term", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "index:presidents:term", NULL, NULL, &cursor));
+
/*
* Pick 10 random years and read the data.
*/
- for (i = 0; i < 10 && RET_OK(ret); i++) {
+ for (i = 0; i < 10; i++) {
year = (uint16_t)((rand() % YEAR_SPAN) + YEAR_BASE);
printf("Year %" PRIu16 ":\n", year);
cursor->set_key(cursor, year);
- if ((ret = cursor->search(cursor)) != 0)
- break;
- if ((ret = cursor->get_key(cursor, &rec_year)) != 0)
- break;
- if ((ret = cursor->get_value(cursor,
- &last_name, &first_name, &term_start, &term_end)) != 0)
- break;
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_key(cursor, &rec_year));
+ error_check(cursor->get_value(cursor,
+ &last_name, &first_name, &term_start, &term_end));
/* Report all presidents that served during the chosen year */
+ ret = 0;
while (term_start <= year &&
year <= term_end && year == rec_year) {
printf("\t%s %s\n", first_name, last_name);
if ((ret = cursor->next(cursor)) != 0)
break;
- if ((ret = cursor->get_key(cursor, &rec_year)) != 0)
- break;
- if ((ret = cursor->get_value(cursor, &last_name,
- &first_name, &term_start, &term_end)) != 0)
- break;
+ error_check(cursor->get_key(cursor, &rec_year));
+ error_check(cursor->get_value(cursor,
+ &last_name, &first_name, &term_start, &term_end));
}
+ scan_end_check(ret == 0 || ret == WT_NOTFOUND);
}
- if (!RET_OK(ret))
- fprintf(stderr, "Error %d for year %" PRIu16 "\n", ret, year);
- ret = cursor->close(cursor);
- return (ret);
+ error_check(cursor->close(cursor));
}
/*
* Remove some items from the primary table.
*/
-static int
+static void
remove_items(WT_SESSION *session)
{
WT_CURSOR *cursor;
struct president_data p;
- int i, ret;
+ int i;
/*
* Removing items from the primary table will call the extractor
* for the index and allow our custom extractor code to handle
* each custom key.
*/
- ret = session->open_cursor(
- session, "table:presidents", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:presidents", NULL, NULL, &cursor));
/*
* Just remove the first few items.
*/
for (i = 0; example_data[i].last_name != NULL && i < 2; i++) {
p = example_data[i];
cursor->set_key(cursor, p.id);
- ret = cursor->remove(cursor);
+ error_check(cursor->remove(cursor));
}
- return (ret);
}
/*
* Set up the table and index of the data.
*/
-static int
+static void
setup_table(WT_SESSION *session)
{
WT_CURSOR *cursor;
struct president_data p;
- int i, ret;
+ int i;
/* Create the primary table. It has a key of the unique ID. */
- ret = session->create(session, "table:presidents",
+ error_check(session->create(session, "table:presidents",
"key_format=I,value_format=SSHH,"
- "columns=(ID,last_name,first_name,term_begin,term_end)");
+ "columns=(ID,last_name,first_name,term_begin,term_end)"));
/*
* Create the index that is generated with an extractor. The index
* will generate an entry in the index for each year a president
* was in office.
*/
- ret = session->create(session, "index:presidents:term",
- "key_format=H,columns=(term),extractor=my_extractor");
+ error_check(session->create(session, "index:presidents:term",
+ "key_format=H,columns=(term),extractor=my_extractor"));
- ret = session->open_cursor(
- session, "table:presidents", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "table:presidents", NULL, NULL, &cursor));
for (i = 0; example_data[i].last_name != NULL; i++) {
p = example_data[i];
cursor->set_key(cursor, p.id);
@@ -251,37 +224,28 @@ setup_table(WT_SESSION *session)
"SETUP: table insert %" PRIu16 "-%" PRIu16 ": %s %s\n",
p.term_start, p.term_end,
p.first_name, p.last_name);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- return (ret);
}
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_SESSION *session;
- int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
- ret = wiredtiger_open(home, NULL, "create,cache_size=500M", &conn);
- ret = add_extractor(conn);
- ret = conn->open_session(conn, NULL, NULL, &session);
+ error_check(
+ wiredtiger_open(home, NULL, "create,cache_size=500M", &conn));
+ add_extractor(conn);
+ error_check(conn->open_session(conn, NULL, NULL, &session));
- ret = setup_table(session);
- ret = read_index(session);
- ret = remove_items(session);
+ setup_table(session);
+ read_index(session);
+ remove_items(session);
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_file_system.c b/src/third_party/wiredtiger/examples/c/ex_file_system.c
index e454d228c39..27807f452e6 100644
--- a/src/third_party/wiredtiger/examples/c/ex_file_system.c
+++ b/src/third_party/wiredtiger/examples/c/ex_file_system.c
@@ -28,22 +28,7 @@
* ex_file_system.c
* demonstrates how to use the custom file system interface
*/
-
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <queue.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef _WIN32
-#include <pthread.h>
-#else
-#include "windows_shim.h"
-#endif
-
-#include <wiredtiger.h>
-#include <wiredtiger_ext.h>
+#include <test_util.h>
/*
* This example code uses pthread functions for portable locking, we ignore
@@ -52,25 +37,25 @@
static void
allocate_file_system_lock(pthread_rwlock_t *lockp)
{
- assert(pthread_rwlock_init(lockp, NULL) == 0);
+ error_check(pthread_rwlock_init(lockp, NULL));
}
static void
destroy_file_system_lock(pthread_rwlock_t *lockp)
{
- assert(pthread_rwlock_destroy(lockp) == 0);
+ error_check(pthread_rwlock_destroy(lockp));
}
static void
lock_file_system(pthread_rwlock_t *lockp)
{
- assert(pthread_rwlock_wrlock(lockp) == 0);
+ error_check(pthread_rwlock_wrlock(lockp));
}
static void
unlock_file_system(pthread_rwlock_t *lockp)
{
- assert(pthread_rwlock_unlock(lockp) == 0);
+ error_check(pthread_rwlock_unlock(lockp));
}
/*
diff --git a/src/third_party/wiredtiger/examples/c/ex_hello.c b/src/third_party/wiredtiger/examples/c/ex_hello.c
index 616049aaddb..fe21ff8057f 100644
--- a/src/third_party/wiredtiger/examples/c/ex_hello.c
+++ b/src/third_party/wiredtiger/examples/c/ex_hello.c
@@ -29,54 +29,28 @@
* This is an example demonstrating how to create and connect to a
* database.
*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_SESSION *session;
- int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/* Open a connection to the database, creating it if necessary. */
- if ((ret = wiredtiger_open(home, NULL, "create", &conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
/* Open a session for the current thread's work. */
- if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) {
- fprintf(stderr, "Error opening a session on %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/* Do some work... */
/* Note: closing the connection implicitly closes open session(s). */
- if ((ret = conn->close(conn, NULL)) != 0) {
- fprintf(stderr, "Error closing %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->close(conn, NULL));
return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_log.c b/src/third_party/wiredtiger/examples/c/ex_log.c
index d4de195ddee..3cf6ff6df23 100644
--- a/src/third_party/wiredtiger/examples/c/ex_log.c
+++ b/src/third_party/wiredtiger/examples/c/ex_log.c
@@ -28,18 +28,7 @@
* ex_log.c
* demonstrates how to use logging and log cursors.
*/
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#else
-/* snprintf is not supported on <= VS2013 */
-#define snprintf _snprintf
-#endif
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home1 = "WT_HOME_LOG_1";
static const char *home2 = "WT_HOME_LOG_2";
@@ -49,61 +38,50 @@ static const char * const uri = "table:logtest";
#define CONN_CONFIG "create,cache_size=100MB,log=(archive=false,enabled=true)"
#define MAX_KEYS 10
-static int
+static void
setup_copy(WT_CONNECTION **wt_connp, WT_SESSION **sessionp)
{
- int ret;
+ error_check(wiredtiger_open(home2, NULL, CONN_CONFIG, wt_connp));
- if ((ret = wiredtiger_open(home2, NULL, CONN_CONFIG, wt_connp)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home1, wiredtiger_strerror(ret));
- return (ret);
- }
-
- ret = (*wt_connp)->open_session(*wt_connp, NULL, NULL, sessionp);
- ret = (*sessionp)->create(*sessionp, uri,
- "key_format=S,value_format=S");
- return (ret);
+ error_check((*wt_connp)->open_session(*wt_connp, NULL, NULL, sessionp));
+ error_check((*sessionp)->create(
+ *sessionp, uri, "key_format=S,value_format=S"));
}
-static int
+static void
compare_tables(WT_SESSION *session, WT_SESSION *sess_copy)
{
WT_CURSOR *cursor, *curs_copy;
int ret;
const char *key, *key_copy, *value, *value_copy;
- ret = session->open_cursor(session, uri, NULL, NULL, &cursor);
- ret = sess_copy->open_cursor(sess_copy, uri, NULL, NULL, &curs_copy);
+ error_check(session->open_cursor(session, uri, NULL, NULL, &cursor));
+ error_check(
+ sess_copy->open_cursor(sess_copy, uri, NULL, NULL, &curs_copy));
while ((ret = cursor->next(cursor)) == 0) {
- ret = curs_copy->next(curs_copy);
- ret = cursor->get_key(cursor, &key);
- ret = cursor->get_value(cursor, &value);
- ret = curs_copy->get_key(curs_copy, &key_copy);
- ret = curs_copy->get_value(curs_copy, &value_copy);
+ error_check(curs_copy->next(curs_copy));
+ error_check(cursor->get_key(cursor, &key));
+ error_check(cursor->get_value(cursor, &value));
+ error_check(curs_copy->get_key(curs_copy, &key_copy));
+ error_check(curs_copy->get_value(curs_copy, &value_copy));
if (strcmp(key, key_copy) != 0 ||
strcmp(value, value_copy) != 0) {
fprintf(stderr,
"Mismatched: key %s, key_copy %s "
"value %s value_copy %s\n",
key, key_copy, value, value_copy);
- return (1);
+ exit (1);
}
}
- if (ret != WT_NOTFOUND)
- fprintf(stderr,
- "WT_CURSOR.next: %s\n", session->strerror(session, ret));
- ret = cursor->close(cursor);
+ scan_end_check(ret == WT_NOTFOUND);
+
+ error_check(cursor->close(cursor));
ret = curs_copy->next(curs_copy);
- if (ret != WT_NOTFOUND)
- fprintf(stderr,
- "copy: WT_CURSOR.next: %s\n",
- session->strerror(session, ret));
- ret = curs_copy->close(curs_copy);
+ scan_end_check(ret == WT_NOTFOUND);
- return (ret);
+ error_check(curs_copy->close(curs_copy));
}
/*! [log cursor walk] */
@@ -127,7 +105,7 @@ print_record(uint32_t log_file, uint32_t log_offset, uint32_t opcount,
* simple_walk_log --
* A simple walk of the log.
*/
-static int
+static void
simple_walk_log(WT_SESSION *session, int count_min)
{
WT_CURSOR *cursor;
@@ -137,37 +115,37 @@ simple_walk_log(WT_SESSION *session, int count_min)
int count, ret;
/*! [log cursor open] */
- ret = session->open_cursor(session, "log:", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session, "log:", NULL, NULL, &cursor));
/*! [log cursor open] */
count = 0;
while ((ret = cursor->next(cursor)) == 0) {
count++;
/*! [log cursor get_key] */
- ret = cursor->get_key(cursor, &log_file, &log_offset, &opcount);
+ error_check(cursor->get_key(
+ cursor, &log_file, &log_offset, &opcount));
/*! [log cursor get_key] */
/*! [log cursor get_value] */
- ret = cursor->get_value(cursor, &txnid,
- &rectype, &optype, &fileid, &logrec_key, &logrec_value);
+ error_check(cursor->get_value(cursor, &txnid,
+ &rectype, &optype, &fileid, &logrec_key, &logrec_value));
/*! [log cursor get_value] */
print_record(log_file, log_offset, opcount,
rectype, optype, txnid, fileid, &logrec_key, &logrec_value);
}
- if (ret == WT_NOTFOUND)
- ret = 0;
- ret = cursor->close(cursor);
+ scan_end_check(ret == WT_NOTFOUND);
+ error_check(cursor->close(cursor));
+
if (count < count_min) {
fprintf(stderr,
"Expected minimum %d records, found %d\n",
count_min, count);
- abort();
+ exit (1);
}
- return (ret);
}
/*! [log cursor walk] */
-static int
+static void
walk_log(WT_SESSION *session)
{
WT_CONNECTION *wt_conn2;
@@ -179,15 +157,17 @@ walk_log(WT_SESSION *session)
uint32_t log_file, log_offset, save_file, save_offset;
int first, i, in_txn, ret;
- ret = setup_copy(&wt_conn2, &session2);
- ret = session->open_cursor(session, "log:", NULL, NULL, &cursor);
- ret = session2->open_cursor(session2, uri, NULL, "raw=true", &cursor2);
+ setup_copy(&wt_conn2, &session2);
+ error_check(session->open_cursor(session, "log:", NULL, NULL, &cursor));
+ error_check(session2->open_cursor(
+ session2, uri, NULL, "raw=true", &cursor2));
i = 0;
in_txn = 0;
txnid = 0;
save_file = save_offset = 0;
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &log_file, &log_offset, &opcount);
+ error_check(cursor->get_key(
+ cursor, &log_file, &log_offset, &opcount));
/*
* Save one of the LSNs we get back to search for it
* later. Pick a later one because we want to walk from
@@ -198,8 +178,8 @@ walk_log(WT_SESSION *session)
save_file = log_file;
save_offset = log_offset;
}
- ret = cursor->get_value(cursor, &txnid, &rectype,
- &optype, &fileid, &logrec_key, &logrec_value);
+ error_check(cursor->get_value(cursor, &txnid, &rectype,
+ &optype, &fileid, &logrec_key, &logrec_value));
print_record(log_file, log_offset, opcount,
rectype, optype, txnid, fileid, &logrec_key, &logrec_value);
@@ -209,7 +189,8 @@ walk_log(WT_SESSION *session)
* the previous one.
*/
if (in_txn && opcount == 0) {
- ret = session2->commit_transaction(session2, NULL);
+ error_check(
+ session2->commit_transaction(session2, NULL));
in_txn = 0;
}
@@ -223,41 +204,40 @@ walk_log(WT_SESSION *session)
if (fileid != 0 &&
rectype == WT_LOGREC_COMMIT && optype == WT_LOGOP_ROW_PUT) {
if (!in_txn) {
- ret = session2->begin_transaction(session2,
- NULL);
+ error_check(session2->begin_transaction(
+ session2, NULL));
in_txn = 1;
}
cursor2->set_key(cursor2, &logrec_key);
cursor2->set_value(cursor2, &logrec_value);
- ret = cursor2->insert(cursor2);
+ error_check(cursor2->insert(cursor2));
}
}
if (in_txn)
- ret = session2->commit_transaction(session2, NULL);
+ error_check(session2->commit_transaction(session2, NULL));
- ret = cursor2->close(cursor2);
+ error_check(cursor2->close(cursor2));
/*
* Compare the tables after replay. They should be identical.
*/
- if (compare_tables(session, session2))
- printf("compare failed\n");
- ret = session2->close(session2, NULL);
- ret = wt_conn2->close(wt_conn2, NULL);
+ compare_tables(session, session2);
+ error_check(session2->close(session2, NULL));
+ error_check(wt_conn2->close(wt_conn2, NULL));
- ret = cursor->reset(cursor);
+ error_check(cursor->reset(cursor));
/*! [log cursor set_key] */
cursor->set_key(cursor, save_file, save_offset, 0);
/*! [log cursor set_key] */
/*! [log cursor search] */
- ret = cursor->search(cursor);
+ error_check(cursor->search(cursor));
/*! [log cursor search] */
printf("Reset to saved...\n");
/*
* Walk all records starting with this key.
*/
- first = 1;
- while ((ret = cursor->get_key(cursor,
- &log_file, &log_offset, &opcount)) == 0) {
+ for (first = 1;;) {
+ error_check(cursor->get_key(
+ cursor, &log_file, &log_offset, &opcount));
if (first) {
first = 0;
if (save_file != log_file ||
@@ -267,8 +247,8 @@ walk_log(WT_SESSION *session)
exit (1);
}
}
- ret = cursor->get_value(cursor, &txnid, &rectype,
- &optype, &fileid, &logrec_key, &logrec_value);
+ error_check(cursor->get_value(cursor, &txnid, &rectype,
+ &optype, &fileid, &logrec_key, &logrec_value));
print_record(log_file, log_offset, opcount,
rectype, optype, txnid, fileid, &logrec_key, &logrec_value);
@@ -277,37 +257,36 @@ walk_log(WT_SESSION *session)
if (ret != 0)
break;
}
- ret = cursor->close(cursor);
- return (ret);
+ scan_end_check(ret == WT_NOTFOUND);
+
+ error_check(cursor->close(cursor));
}
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *wt_conn;
WT_CURSOR *cursor;
WT_SESSION *session;
- int count_min, i, record_count, ret;
+ int count_min, i, record_count;
char cmd_buf[256], k[16], v[16];
+ (void)argc; /* Unused variable */
+ (void)testutil_set_progname(argv);
+
count_min = 0;
+
(void)snprintf(cmd_buf, sizeof(cmd_buf),
"rm -rf %s %s && mkdir %s %s", home1, home2, home1, home2);
- if ((ret = system(cmd_buf)) != 0) {
- fprintf(stderr, "%s: failed ret %d\n", cmd_buf, ret);
- return (EXIT_FAILURE);
- }
- if ((ret = wiredtiger_open(home1, NULL, CONN_CONFIG, &wt_conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home1, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(system(cmd_buf));
+ error_check(wiredtiger_open(home1, NULL, CONN_CONFIG, &wt_conn));
- ret = wt_conn->open_session(wt_conn, NULL, NULL, &session);
- ret = session->create(session, uri, "key_format=S,value_format=S");
+ error_check(wt_conn->open_session(wt_conn, NULL, NULL, &session));
+ error_check(
+ session->create(session, uri, "key_format=S,value_format=S"));
count_min++;
- ret = session->open_cursor(session, uri, NULL, NULL, &cursor);
+ error_check(session->open_cursor(session, uri, NULL, NULL, &cursor));
/*
* Perform some operations with individual auto-commit transactions.
*/
@@ -316,10 +295,10 @@ main(void)
(void)snprintf(v, sizeof(v), "value%d", i);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
count_min++;
}
- ret = session->begin_transaction(session, NULL);
+ error_check(session->begin_transaction(session, NULL));
/*
* Perform some operations within a single transaction.
*/
@@ -328,33 +307,30 @@ main(void)
(void)snprintf(v, sizeof(v), "value%d", i);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = session->commit_transaction(session, NULL);
+ error_check(session->commit_transaction(session, NULL));
count_min++;
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [log cursor printf] */
- ret = session->log_printf(session, "Wrote %d records", record_count);
- count_min++;
+ error_check(
+ session->log_printf(session, "Wrote %d records", record_count));
/*! [log cursor printf] */
+ count_min++;
/*
* Close and reopen the connection so that the log ends up with
* a variety of records such as file sync and checkpoint. We
* have archiving turned off.
*/
- ret = wt_conn->close(wt_conn, NULL);
- if ((ret = wiredtiger_open(home1, NULL, CONN_CONFIG, &wt_conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home1, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wt_conn->close(wt_conn, NULL));
+ error_check(wiredtiger_open(home1, NULL, CONN_CONFIG, &wt_conn));
- ret = wt_conn->open_session(wt_conn, NULL, NULL, &session);
- ret = simple_walk_log(session, count_min);
- ret = walk_log(session);
- ret = wt_conn->close(wt_conn, NULL);
+ error_check(wt_conn->open_session(wt_conn, NULL, NULL, &session));
+ simple_walk_log(session, count_min);
+ walk_log(session);
+ error_check(wt_conn->close(wt_conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_pack.c b/src/third_party/wiredtiger/examples/c/ex_pack.c
index 37b864e62a4..98cd1510b92 100644
--- a/src/third_party/wiredtiger/examples/c/ex_pack.c
+++ b/src/third_party/wiredtiger/examples/c/ex_pack.c
@@ -28,68 +28,46 @@
* ex_pack.c
* This is an example demonstrating basic packing and unpacking of fields.
*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_SESSION *session;
- int i, j, k, ret;
+ int i, j, k;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/* Open a connection to the database, creating it if necessary. */
- if ((ret = wiredtiger_open(home, NULL, "create", &conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
/* Open a session for the current thread's work. */
- if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) {
- fprintf(stderr, "Error opening a session on %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->open_session(conn, NULL, NULL, &session));
{
/*! [packing] */
size_t size;
char buf[50];
- ret = wiredtiger_struct_size(session, &size, "iii", 42, 1000, -9);
+ error_check(
+ wiredtiger_struct_size(session, &size, "iii", 42, 1000, -9));
if (size > sizeof(buf)) {
/* Allocate a bigger buffer. */
}
- ret = wiredtiger_struct_pack(session, buf, size, "iii", 42, 1000, -9);
+ error_check(
+ wiredtiger_struct_pack(session, buf, size, "iii", 42, 1000, -9));
- ret = wiredtiger_struct_unpack(session, buf, size, "iii", &i, &j, &k);
+ error_check(
+ wiredtiger_struct_unpack(session, buf, size, "iii", &i, &j, &k));
/*! [packing] */
}
/* Note: closing the connection implicitly closes open session(s). */
- if ((ret = conn->close(conn, NULL)) != 0) {
- fprintf(stderr, "Error closing %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->close(conn, NULL));
return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_process.c b/src/third_party/wiredtiger/examples/c/ex_process.c
index 4bab6a1cd70..06a62d10d39 100644
--- a/src/third_party/wiredtiger/examples/c/ex_process.c
+++ b/src/third_party/wiredtiger/examples/c/ex_process.c
@@ -29,56 +29,29 @@
* This is an example demonstrating how to connect to a database from
* multiple processes.
*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
int
-main(void)
+main(int argc, char *argv[])
{
- int ret;
WT_CONNECTION *conn;
WT_SESSION *session;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
+ home = example_setup(argc, argv);
/*! [processes] */
/* Open a connection to the database, creating it if necessary. */
- if ((ret =
- wiredtiger_open(home, NULL, "create,multiprocess", &conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(wiredtiger_open(home, NULL, "create,multiprocess", &conn));
/* Open a session for the current thread's work. */
- if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) {
- fprintf(stderr, "Error opening a session on %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/* XXX Do some work... */
/* Note: closing the connection implicitly closes open session(s). */
- if ((ret = conn->close(conn, NULL)) != 0) {
- fprintf(stderr, "Error closing %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ error_check(conn->close(conn, NULL));
/*! [processes] */
return (EXIT_SUCCESS);
diff --git a/src/third_party/wiredtiger/examples/c/ex_schema.c b/src/third_party/wiredtiger/examples/c/ex_schema.c
index 9249ecc1e1a..f2ebd118104 100644
--- a/src/third_party/wiredtiger/examples/c/ex_schema.c
+++ b/src/third_party/wiredtiger/examples/c/ex_schema.c
@@ -29,13 +29,7 @@
* This is an example application demonstrating how to create and access
* tables using a schema.
*/
-
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
+#include <test_util.h>
static const char *home;
@@ -65,7 +59,7 @@ static POP_RECORD pop_data[] = {
/*! [schema declaration] */
int
-main(void)
+main(int argc, char *argv[])
{
POP_RECORD *p;
WT_CONNECTION *conn;
@@ -77,25 +71,12 @@ main(void)
uint16_t year;
int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
-
- if ((ret = wiredtiger_open(
- home, NULL, "create,statistics=(fast)", &conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
- /* Note: error checking omitted for clarity. */
+ home = example_setup(argc, argv);
+
+ error_check(wiredtiger_open(
+ home, NULL, "create,statistics=(fast)", &conn));
- ret = conn->open_session(conn, NULL, NULL, &session);
+ error_check(conn->open_session(conn, NULL, NULL, &session));
/*! [Create a table with column groups] */
/*
@@ -104,288 +85,296 @@ main(void)
* uint16_t, uint64_t).
* See ::wiredtiger_struct_pack for details of the format strings.
*/
- ret = session->create(session, "table:poptable",
+ error_check(session->create(session, "table:poptable",
"key_format=r,"
"value_format=5sHQ,"
"columns=(id,country,year,population),"
- "colgroups=(main,population)");
+ "colgroups=(main,population)"));
/*
* Create two column groups: a primary column group with the country
* code, year and population (named "main"), and a population column
* group with the population by itself (named "population").
*/
- ret = session->create(session,
- "colgroup:poptable:main", "columns=(country,year,population)");
- ret = session->create(session,
- "colgroup:poptable:population", "columns=(population)");
+ error_check(session->create(session,
+ "colgroup:poptable:main", "columns=(country,year,population)"));
+ error_check(session->create(session,
+ "colgroup:poptable:population", "columns=(population)"));
/*! [Create a table with column groups] */
/*! [Create an index] */
/* Create an index with a simple key. */
- ret = session->create(session,
- "index:poptable:country", "columns=(country)");
+ error_check(session->create(session,
+ "index:poptable:country", "columns=(country)"));
/*! [Create an index] */
/*! [Create an index with a composite key] */
/* Create an index with a composite key (country,year). */
- ret = session->create(session,
- "index:poptable:country_plus_year", "columns=(country,year)");
+ error_check(session->create(session,
+ "index:poptable:country_plus_year", "columns=(country,year)"));
/*! [Create an index with a composite key] */
/*! [Create an immutable index] */
/* Create an immutable index. */
- ret = session->create(session,
- "index:poptable:immutable_year", "columns=(year),immutable");
+ error_check(session->create(session,
+ "index:poptable:immutable_year", "columns=(year),immutable"));
/*! [Create an immutable index] */
/* Insert the records into the table. */
- ret = session->open_cursor(
- session, "table:poptable", NULL, "append", &cursor);
+ error_check(session->open_cursor(
+ session, "table:poptable", NULL, "append", &cursor));
for (p = pop_data; p->year != 0; p++) {
cursor->set_value(cursor, p->country, p->year, p->population);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/* Update records in the table. */
- ret = session->open_cursor(session,
- "table:poptable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "table:poptable", NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &recno);
- ret = cursor->get_value(cursor, &country, &year, &population);
+ error_check(cursor->get_key(cursor, &recno));
+ error_check(cursor->get_value(
+ cursor, &country, &year, &population));
cursor->set_value(cursor, country, year, population + 1);
- ret = cursor->update(cursor);
+ error_check(cursor->update(cursor));
}
- ret = cursor->close(cursor);
+ scan_end_check(ret == WT_NOTFOUND);
+ error_check(cursor->close(cursor));
/* List the records in the table. */
- ret = session->open_cursor(session,
- "table:poptable", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "table:poptable", NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &recno);
- ret = cursor->get_value(cursor, &country, &year, &population);
+ error_check(cursor->get_key(cursor, &recno));
+ error_check(cursor->get_value(
+ cursor, &country, &year, &population));
printf("ID %" PRIu64, recno);
printf(
": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
country, year, population);
}
- ret = cursor->close(cursor);
+ scan_end_check(ret == WT_NOTFOUND);
+ error_check(cursor->close(cursor));
/*! [List the records in the table using raw mode.] */
/* List the records in the table using raw mode. */
- ret = session->open_cursor(session,
- "table:poptable", NULL, "raw", &cursor);
+ error_check(session->open_cursor(session,
+ "table:poptable", NULL, "raw", &cursor));
while ((ret = cursor->next(cursor)) == 0) {
WT_ITEM key, value;
- ret = cursor->get_key(cursor, &key);
- ret = wiredtiger_struct_unpack(session,
- key.data, key.size, "r", &recno);
+ error_check(cursor->get_key(cursor, &key));
+ error_check(wiredtiger_struct_unpack(
+ session, key.data, key.size, "r", &recno));
printf("ID %" PRIu64, recno);
- ret = cursor->get_value(cursor, &value);
- ret = wiredtiger_struct_unpack(session,
+ error_check(cursor->get_value(cursor, &value));
+ error_check(wiredtiger_struct_unpack(session,
value.data, value.size,
- "5sHQ", &country, &year, &population);
+ "5sHQ", &country, &year, &population));
printf(
": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
country, year, population);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [List the records in the table using raw mode.] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Read population from the primary column group] */
/*
* Open a cursor on the main column group, and return the information
* for a particular country.
*/
- ret = session->open_cursor(
- session, "colgroup:poptable:main", NULL, NULL, &cursor);
+ error_check(session->open_cursor(
+ session, "colgroup:poptable:main", NULL, NULL, &cursor));
cursor->set_key(cursor, 2);
- if ((ret = cursor->search(cursor)) == 0) {
- ret = cursor->get_value(cursor, &country, &year, &population);
- printf(
- "ID 2: "
- "country %s, year %" PRIu16 ", population %" PRIu64 "\n",
- country, year, population);
- }
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &country, &year, &population));
+ printf(
+ "ID 2: country %s, year %" PRIu16 ", population %" PRIu64 "\n",
+ country, year, population);
/*! [Read population from the primary column group] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Read population from the standalone column group] */
/*
* Open a cursor on the population column group, and return the
* population of a particular country.
*/
- ret = session->open_cursor(session,
- "colgroup:poptable:population", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "colgroup:poptable:population", NULL, NULL, &cursor));
cursor->set_key(cursor, 2);
- if ((ret = cursor->search(cursor)) == 0) {
- ret = cursor->get_value(cursor, &population);
- printf("ID 2: population %" PRIu64 "\n", population);
- }
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &population));
+ printf("ID 2: population %" PRIu64 "\n", population);
/*! [Read population from the standalone column group] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Search in a simple index] */
/* Search in a simple index. */
- ret = session->open_cursor(session,
- "index:poptable:country", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "index:poptable:country", NULL, NULL, &cursor));
cursor->set_key(cursor, "AU\0\0\0");
- ret = cursor->search(cursor);
- ret = cursor->get_value(cursor, &country, &year, &population);
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &country, &year, &population));
printf("AU: country %s, year %" PRIu16 ", population %" PRIu64 "\n",
country, year, population);
/*! [Search in a simple index] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Search in a composite index] */
/* Search in a composite index. */
- ret = session->open_cursor(session,
- "index:poptable:country_plus_year", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "index:poptable:country_plus_year", NULL, NULL, &cursor));
cursor->set_key(cursor, "USA\0\0", (uint16_t)1900);
- ret = cursor->search(cursor);
- ret = cursor->get_value(cursor, &country, &year, &population);
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &country, &year, &population));
printf(
"US 1900: country %s, year %" PRIu16 ", population %" PRIu64 "\n",
country, year, population);
/*! [Search in a composite index] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Return a subset of values from the table] */
/*
* Use a projection to return just the table's country and year
* columns.
*/
- ret = session->open_cursor(session,
- "table:poptable(country,year)", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "table:poptable(country,year)", NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_value(cursor, &country, &year);
+ error_check(cursor->get_value(cursor, &country, &year));
printf("country %s, year %" PRIu16 "\n", country, year);
}
/*! [Return a subset of values from the table] */
- ret = cursor->close(cursor);
+ scan_end_check(ret == WT_NOTFOUND);
+ error_check(cursor->close(cursor));
/*! [Return a subset of values from the table using raw mode] */
/*
* Use a projection to return just the table's country and year
* columns, using raw mode.
*/
- ret = session->open_cursor(session,
- "table:poptable(country,year)", NULL, "raw", &cursor);
+ error_check(session->open_cursor(session,
+ "table:poptable(country,year)", NULL, "raw", &cursor));
while ((ret = cursor->next(cursor)) == 0) {
WT_ITEM value;
- ret = cursor->get_value(cursor, &value);
- ret = wiredtiger_struct_unpack(
- session, value.data, value.size, "5sH", &country, &year);
+ error_check(cursor->get_value(cursor, &value));
+ error_check(wiredtiger_struct_unpack(
+ session, value.data, value.size, "5sH", &country, &year));
printf("country %s, year %" PRIu16 "\n", country, year);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Return a subset of values from the table using raw mode] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Return the table's record number key using an index] */
/*
* Use a projection to return just the table's record number key
* from an index.
*/
- ret = session->open_cursor(session,
- "index:poptable:country_plus_year(id)", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "index:poptable:country_plus_year(id)", NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &country, &year);
- ret = cursor->get_value(cursor, &recno);
+ error_check(cursor->get_key(cursor, &country, &year));
+ error_check(cursor->get_value(cursor, &recno));
printf("row ID %" PRIu64 ": country %s, year %" PRIu16 "\n",
recno, country, year);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Return the table's record number key using an index] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Return a subset of the value columns from an index] */
/*
* Use a projection to return just the population column from an
* index.
*/
- ret = session->open_cursor(session,
+ error_check(session->open_cursor(session,
"index:poptable:country_plus_year(population)",
- NULL, NULL, &cursor);
+ NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &country, &year);
- ret = cursor->get_value(cursor, &population);
+ error_check(cursor->get_key(cursor, &country, &year));
+ error_check(cursor->get_value(cursor, &population));
printf("population %" PRIu64 ": country %s, year %" PRIu16 "\n",
population, country, year);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Return a subset of the value columns from an index] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Access only the index] */
/*
* Use a projection to avoid accessing any other column groups when
* using an index: supply an empty list of value columns.
*/
- ret = session->open_cursor(session,
- "index:poptable:country_plus_year()", NULL, NULL, &cursor);
+ error_check(session->open_cursor(session,
+ "index:poptable:country_plus_year()", NULL, NULL, &cursor));
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &country, &year);
+ error_check(cursor->get_key(cursor, &country, &year));
printf("country %s, year %" PRIu16 "\n", country, year);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Access only the index] */
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [Join cursors] */
/* Open cursors needed by the join. */
- ret = session->open_cursor(session,
- "join:table:poptable", NULL, NULL, &join_cursor);
- ret = session->open_cursor(session,
- "index:poptable:country", NULL, NULL, &country_cursor);
- ret = session->open_cursor(session,
- "index:poptable:immutable_year", NULL, NULL, &year_cursor);
+ error_check(session->open_cursor(session,
+ "join:table:poptable", NULL, NULL, &join_cursor));
+ error_check(session->open_cursor(session,
+ "index:poptable:country", NULL, NULL, &country_cursor));
+ error_check(session->open_cursor(session,
+ "index:poptable:immutable_year", NULL, NULL, &year_cursor));
/* select values WHERE country == "AU" AND year > 1900 */
country_cursor->set_key(country_cursor, "AU\0\0\0");
- ret = country_cursor->search(country_cursor);
- ret = session->join(session, join_cursor, country_cursor,
- "compare=eq,count=10");
+ error_check(country_cursor->search(country_cursor));
+ error_check(session->join(
+ session, join_cursor, country_cursor, "compare=eq,count=10"));
year_cursor->set_key(year_cursor, (uint16_t)1900);
- ret = year_cursor->search(year_cursor);
- ret = session->join(session, join_cursor, year_cursor,
- "compare=gt,count=10,strategy=bloom");
+ error_check(year_cursor->search(year_cursor));
+ error_check(session->join(session,
+ join_cursor, year_cursor, "compare=gt,count=10,strategy=bloom"));
/* List the values that are joined */
while ((ret = join_cursor->next(join_cursor)) == 0) {
- ret = join_cursor->get_key(join_cursor, &recno);
- ret = join_cursor->get_value(join_cursor, &country, &year,
- &population);
+ error_check(join_cursor->get_key(join_cursor, &recno));
+ error_check(join_cursor->get_value(
+ join_cursor, &country, &year, &population));
printf("ID %" PRIu64, recno);
printf(
": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
country, year, population);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Join cursors] */
/*! [Statistics cursor join cursor] */
- ret = session->open_cursor(session,
+ error_check(session->open_cursor(session,
"statistics:join",
- join_cursor, NULL, &stat_cursor);
+ join_cursor, NULL, &stat_cursor));
/*! [Statistics cursor join cursor] */
- ret = stat_cursor->close(stat_cursor);
- ret = join_cursor->close(join_cursor);
- ret = year_cursor->close(year_cursor);
- ret = country_cursor->close(country_cursor);
+ error_check(stat_cursor->close(stat_cursor));
+ error_check(join_cursor->close(join_cursor));
+ error_check(year_cursor->close(year_cursor));
+ error_check(country_cursor->close(country_cursor));
/*! [Complex join cursors] */
/* Open cursors needed by the join. */
- ret = session->open_cursor(session,
- "join:table:poptable", NULL, NULL, &join_cursor);
- ret = session->open_cursor(session,
- "join:table:poptable", NULL, NULL, &subjoin_cursor);
- ret = session->open_cursor(session,
- "index:poptable:country", NULL, NULL, &country_cursor);
- ret = session->open_cursor(session,
- "index:poptable:country", NULL, NULL, &country_cursor2);
- ret = session->open_cursor(session,
- "index:poptable:immutable_year", NULL, NULL, &year_cursor);
+ error_check(session->open_cursor(session,
+ "join:table:poptable", NULL, NULL, &join_cursor));
+ error_check(session->open_cursor(session,
+ "join:table:poptable", NULL, NULL, &subjoin_cursor));
+ error_check(session->open_cursor(session,
+ "index:poptable:country", NULL, NULL, &country_cursor));
+ error_check(session->open_cursor(session,
+ "index:poptable:country", NULL, NULL, &country_cursor2));
+ error_check(session->open_cursor(session,
+ "index:poptable:immutable_year", NULL, NULL, &year_cursor));
/*
* select values WHERE (country == "AU" OR country == "UK")
@@ -394,40 +383,41 @@ main(void)
* First, set up the join representing the country clause.
*/
country_cursor->set_key(country_cursor, "AU\0\0\0");
- ret = country_cursor->search(country_cursor);
- ret = session->join(session, subjoin_cursor, country_cursor,
- "operation=or,compare=eq,count=10");
+ error_check(country_cursor->search(country_cursor));
+ error_check(session->join(session, subjoin_cursor,
+ country_cursor, "operation=or,compare=eq,count=10"));
country_cursor2->set_key(country_cursor2, "UK\0\0\0");
- ret = country_cursor2->search(country_cursor2);
- ret = session->join(session, subjoin_cursor, country_cursor2,
- "operation=or,compare=eq,count=10");
+ error_check(country_cursor2->search(country_cursor2));
+ error_check(session->join(session, subjoin_cursor,
+ country_cursor2, "operation=or,compare=eq,count=10"));
/* Join that to the top join, and add the year clause */
- ret = session->join(session, join_cursor, subjoin_cursor, NULL);
+ error_check(session->join(session, join_cursor, subjoin_cursor, NULL));
year_cursor->set_key(year_cursor, (uint16_t)1900);
- ret = year_cursor->search(year_cursor);
- ret = session->join(session, join_cursor, year_cursor,
- "compare=gt,count=10,strategy=bloom");
+ error_check(year_cursor->search(year_cursor));
+ error_check(session->join(session,
+ join_cursor, year_cursor, "compare=gt,count=10,strategy=bloom"));
/* List the values that are joined */
while ((ret = join_cursor->next(join_cursor)) == 0) {
- ret = join_cursor->get_key(join_cursor, &recno);
- ret = join_cursor->get_value(join_cursor, &country, &year,
- &population);
+ error_check(join_cursor->get_key(join_cursor, &recno));
+ error_check(join_cursor->get_value(
+ join_cursor, &country, &year, &population));
printf("ID %" PRIu64, recno);
printf(
": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
country, year, population);
}
+ scan_end_check(ret == WT_NOTFOUND);
/*! [Complex join cursors] */
- ret = join_cursor->close(join_cursor);
- ret = subjoin_cursor->close(subjoin_cursor);
- ret = country_cursor->close(country_cursor);
- ret = country_cursor2->close(country_cursor2);
- ret = year_cursor->close(year_cursor);
+ error_check(join_cursor->close(join_cursor));
+ error_check(subjoin_cursor->close(subjoin_cursor));
+ error_check(country_cursor->close(country_cursor));
+ error_check(country_cursor2->close(country_cursor2));
+ error_check(year_cursor->close(year_cursor));
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_smoke.c b/src/third_party/wiredtiger/examples/c/ex_smoke.c
new file mode 100644
index 00000000000..ab4e085d2f0
--- /dev/null
+++ b/src/third_party/wiredtiger/examples/c/ex_smoke.c
@@ -0,0 +1,67 @@
+/*-
+ * Public Domain 2014-2017 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.
+ *
+ * ex_smoke.c
+ * A simple program you can build to prove include files and libraries
+ * are linking correctly.
+ */
+#include <stdlib.h>
+
+#include <wiredtiger.h>
+
+int
+main(int argc, char *argv[])
+{
+ WT_CONNECTION *conn;
+ int ret;
+
+ (void)argc; /* Unused variable */
+
+ /*
+ * This code deliberately doesn't use the standard test_util macros,
+ * we don't want to link against that code to smoke-test a build.
+ */
+ (void)system("rm -rf WT_HOME && mkdir WT_HOME");
+
+ /* Open a connection to the database, creating it if necessary. */
+ if ((ret = wiredtiger_open("WT_HOME", NULL, "create", &conn)) != 0) {
+ fprintf(stderr,
+ "%s: wiredtiger_open: %s\n",
+ argv[0], wiredtiger_strerror(ret));
+ return (EXIT_FAILURE);
+ }
+
+ /* Close the connection to the database. */
+ if ((ret = conn->close(conn, NULL)) != 0) {
+ fprintf(stderr,
+ "%s: WT_CONNECTION.close: %s\n",
+ argv[0], wiredtiger_strerror(ret));
+ return (EXIT_FAILURE);
+ }
+
+ return (EXIT_SUCCESS);
+}
diff --git a/src/third_party/wiredtiger/examples/c/ex_stat.c b/src/third_party/wiredtiger/examples/c/ex_stat.c
index 7097b53a060..992f335c25e 100644
--- a/src/third_party/wiredtiger/examples/c/ex_stat.c
+++ b/src/third_party/wiredtiger/examples/c/ex_stat.c
@@ -28,164 +28,138 @@
* ex_stat.c
* This is an example demonstrating how to query database statistics.
*/
+#include <test_util.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <wiredtiger.h>
-
-int print_cursor(WT_CURSOR *);
-int print_database_stats(WT_SESSION *);
-int print_file_stats(WT_SESSION *);
-int print_join_cursor_stats(WT_SESSION *);
-int print_overflow_pages(WT_SESSION *);
-int get_stat(WT_CURSOR *cursor, int stat_field, uint64_t *valuep);
-int print_derived_stats(WT_SESSION *);
+void get_stat(WT_CURSOR *cursor, int stat_field, uint64_t *valuep);
+void print_cursor(WT_CURSOR *);
+void print_database_stats(WT_SESSION *);
+void print_derived_stats(WT_SESSION *);
+void print_file_stats(WT_SESSION *);
+void print_join_cursor_stats(WT_SESSION *);
+void print_overflow_pages(WT_SESSION *);
static const char *home;
/*! [statistics display function] */
-int
+void
print_cursor(WT_CURSOR *cursor)
{
const char *desc, *pvalue;
uint64_t value;
int ret;
- while ((ret = cursor->next(cursor)) == 0 &&
- (ret = cursor->get_value(cursor, &desc, &pvalue, &value)) == 0)
+ while ((ret = cursor->next(cursor)) == 0) {
+ error_check(cursor->get_value(cursor, &desc, &pvalue, &value));
if (value != 0)
printf("%s=%s\n", desc, pvalue);
-
- return (ret == WT_NOTFOUND ? 0 : ret);
+ }
+ scan_end_check(ret == WT_NOTFOUND);
}
/*! [statistics display function] */
-int
+void
print_database_stats(WT_SESSION *session)
{
WT_CURSOR *cursor;
- int ret;
/*! [statistics database function] */
- if ((ret = session->open_cursor(session,
- "statistics:", NULL, NULL, &cursor)) != 0)
- return (ret);
+ error_check(session->open_cursor(
+ session, "statistics:", NULL, NULL, &cursor));
- ret = print_cursor(cursor);
- ret = cursor->close(cursor);
+ print_cursor(cursor);
+ error_check(cursor->close(cursor));
/*! [statistics database function] */
-
- return (ret);
}
-int
+void
print_file_stats(WT_SESSION *session)
{
WT_CURSOR *cursor;
- int ret;
/*! [statistics table function] */
- if ((ret = session->open_cursor(session,
- "statistics:table:access", NULL, NULL, &cursor)) != 0)
- return (ret);
+ error_check(session->open_cursor(
+ session, "statistics:table:access", NULL, NULL, &cursor));
- ret = print_cursor(cursor);
- ret = cursor->close(cursor);
+ print_cursor(cursor);
+ error_check(cursor->close(cursor));
/*! [statistics table function] */
-
- return (ret);
}
-int
+void
print_join_cursor_stats(WT_SESSION *session)
{
WT_CURSOR *idx_cursor, *join_cursor, *stat_cursor;
- int ret;
- ret = session->create(
- session, "index:access:idx", "columns=(v)");
- ret = session->open_cursor(
- session, "index:access:idx", NULL, NULL, &idx_cursor);
- ret = idx_cursor->next(idx_cursor);
- ret = session->open_cursor(
- session, "join:table:access", NULL, NULL, &join_cursor);
- ret = session->join(session, join_cursor, idx_cursor, "compare=gt");
- ret = join_cursor->next(join_cursor);
+ error_check(session->create(
+ session, "index:access:idx", "columns=(v)"));
+ error_check(session->open_cursor(
+ session, "index:access:idx", NULL, NULL, &idx_cursor));
+ error_check(idx_cursor->next(idx_cursor));
+ error_check(session->open_cursor(
+ session, "join:table:access", NULL, NULL, &join_cursor));
+ error_check(session->join(
+ session, join_cursor, idx_cursor, "compare=gt"));
+ print_cursor(join_cursor);
/*! [statistics join cursor function] */
- if ((ret = session->open_cursor(session,
- "statistics:join", join_cursor, NULL, &stat_cursor)) != 0)
- return (ret);
+ error_check(session->open_cursor(session,
+ "statistics:join", join_cursor, NULL, &stat_cursor));
- ret = print_cursor(stat_cursor);
- ret = stat_cursor->close(stat_cursor);
+ print_cursor(stat_cursor);
+ error_check(stat_cursor->close(stat_cursor));
/*! [statistics join cursor function] */
- ret = join_cursor->close(join_cursor);
- ret = idx_cursor->close(idx_cursor);
-
- return (ret);
+ error_check(join_cursor->close(join_cursor));
+ error_check(idx_cursor->close(idx_cursor));
}
-int
+void
print_overflow_pages(WT_SESSION *session)
{
/*! [statistics retrieve by key] */
WT_CURSOR *cursor;
const char *desc, *pvalue;
uint64_t value;
- int ret;
- if ((ret = session->open_cursor(session,
- "statistics:table:access", NULL, NULL, &cursor)) != 0)
- return (ret);
+ error_check(session->open_cursor(session,
+ "statistics:table:access", NULL, NULL, &cursor));
cursor->set_key(cursor, WT_STAT_DSRC_BTREE_OVERFLOW);
- ret = cursor->search(cursor);
- ret = cursor->get_value(cursor, &desc, &pvalue, &value);
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &desc, &pvalue, &value));
printf("%s=%s\n", desc, pvalue);
- ret = cursor->close(cursor);
+ error_check(cursor->close(cursor));
/*! [statistics retrieve by key] */
-
- return (ret);
}
/*! [statistics calculation helper function] */
-int
+void
get_stat(WT_CURSOR *cursor, int stat_field, uint64_t *valuep)
{
const char *desc, *pvalue;
- int ret;
cursor->set_key(cursor, stat_field);
- if ((ret = cursor->search(cursor)) != 0)
- return (ret);
-
- return (cursor->get_value(cursor, &desc, &pvalue, valuep));
+ error_check(cursor->search(cursor));
+ error_check(cursor->get_value(cursor, &desc, &pvalue, valuep));
}
/*! [statistics calculation helper function] */
-int
+void
print_derived_stats(WT_SESSION *session)
{
WT_CURSOR *cursor;
- int ret;
/*! [statistics calculate open table stats] */
- if ((ret = session->open_cursor(session,
- "statistics:table:access", NULL, NULL, &cursor)) != 0)
- return (ret);
+ error_check(session->open_cursor(session,
+ "statistics:table:access", NULL, NULL, &cursor));
/*! [statistics calculate open table stats] */
{
/*! [statistics calculate table fragmentation] */
uint64_t ckpt_size, file_size, percent;
- ret = get_stat(cursor, WT_STAT_DSRC_BLOCK_CHECKPOINT_SIZE, &ckpt_size);
- ret = get_stat(cursor, WT_STAT_DSRC_BLOCK_SIZE, &file_size);
+ get_stat(cursor, WT_STAT_DSRC_BLOCK_CHECKPOINT_SIZE, &ckpt_size);
+ get_stat(cursor, WT_STAT_DSRC_BLOCK_SIZE, &file_size);
percent = 0;
if (file_size != 0)
@@ -198,11 +172,11 @@ print_derived_stats(WT_SESSION *session)
/*! [statistics calculate write amplification] */
uint64_t app_insert, app_remove, app_update, fs_writes;
- ret = get_stat(cursor, WT_STAT_DSRC_CURSOR_INSERT_BYTES, &app_insert);
- ret = get_stat(cursor, WT_STAT_DSRC_CURSOR_REMOVE_BYTES, &app_remove);
- ret = get_stat(cursor, WT_STAT_DSRC_CURSOR_UPDATE_BYTES, &app_update);
+ get_stat(cursor, WT_STAT_DSRC_CURSOR_INSERT_BYTES, &app_insert);
+ get_stat(cursor, WT_STAT_DSRC_CURSOR_REMOVE_BYTES, &app_remove);
+ get_stat(cursor, WT_STAT_DSRC_CURSOR_UPDATE_BYTES, &app_update);
- ret = get_stat(cursor, WT_STAT_DSRC_CACHE_BYTES_WRITE, &fs_writes);
+ get_stat(cursor, WT_STAT_DSRC_CACHE_BYTES_WRITE, &fs_writes);
if (app_insert + app_remove + app_update != 0)
printf("Write amplification is %.2lf\n",
@@ -210,54 +184,44 @@ print_derived_stats(WT_SESSION *session)
/*! [statistics calculate write amplification] */
}
- ret = cursor->close(cursor);
-
- return (ret);
+ error_check(cursor->close(cursor));
}
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_CURSOR *cursor;
WT_SESSION *session;
- int ret;
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
-
- ret = wiredtiger_open(home, NULL, "create,statistics=(all)", &conn);
- ret = conn->open_session(conn, NULL, NULL, &session);
- ret = session->create(session,
- "table:access", "key_format=S,value_format=S,columns=(k,v)");
-
- ret = session->open_cursor(
- session, "table:access", NULL, NULL, &cursor);
+ home = example_setup(argc, argv);
+
+ error_check(
+ wiredtiger_open(home, NULL, "create,statistics=(all)", &conn));
+ error_check(conn->open_session(conn, NULL, NULL, &session));
+ error_check(session->create(session,
+ "table:access", "key_format=S,value_format=S,columns=(k,v)"));
+
+ error_check(session->open_cursor(
+ session, "table:access", NULL, NULL, &cursor));
cursor->set_key(cursor, "key");
cursor->set_value(cursor, "value");
- ret = cursor->insert(cursor);
- ret = cursor->close(cursor);
+ error_check(cursor->insert(cursor));
+ error_check(cursor->close(cursor));
- ret = session->checkpoint(session, NULL);
+ error_check(session->checkpoint(session, NULL));
- ret = print_database_stats(session);
+ print_database_stats(session);
- ret = print_file_stats(session);
+ print_file_stats(session);
- ret = print_join_cursor_stats(session);
+ print_join_cursor_stats(session);
- ret = print_overflow_pages(session);
+ print_overflow_pages(session);
- ret = print_derived_stats(session);
+ print_derived_stats(session);
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_sync.c b/src/third_party/wiredtiger/examples/c/ex_sync.c
index c333ac42e1e..2dcd332c51f 100644
--- a/src/third_party/wiredtiger/examples/c/ex_sync.c
+++ b/src/third_party/wiredtiger/examples/c/ex_sync.c
@@ -28,87 +28,70 @@
* ex_sync.c
* demonstrates how to use the transaction sync configuration.
*/
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifndef _WIN32
-#include <unistd.h>
-#else
-/* snprintf is not supported on <= VS2013 */
-#define snprintf _snprintf
-#endif
+#include <test_util.h>
-#include <wiredtiger.h>
-
-static const char *home = "WT_HOME";
-
-static const char * const uri = "table:test";
+static const char *home;
+static const char *const uri = "table:test";
#define CONN_CONFIG "create,cache_size=100MB,log=(archive=false,enabled=true)"
#define MAX_KEYS 100
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *wt_conn;
WT_CURSOR *cursor;
WT_SESSION *session;
int i, record_count, ret;
- char cmd_buf[256], k[16], v[16];
+ char k[16], v[16];
const char *conf;
- (void)snprintf(cmd_buf, sizeof(cmd_buf),
- "rm -rf %s && mkdir %s", home, home);
- if ((ret = system(cmd_buf)) != 0) {
- fprintf(stderr, "%s: failed ret %d\n", cmd_buf, ret);
- return (EXIT_FAILURE);
- }
- if ((ret = wiredtiger_open(home, NULL, CONN_CONFIG, &wt_conn)) != 0) {
- fprintf(stderr, "Error connecting to %s: %s\n",
- home, wiredtiger_strerror(ret));
- return (EXIT_FAILURE);
- }
+ home = example_setup(argc, argv);
+ error_check(wiredtiger_open(home, NULL, CONN_CONFIG, &wt_conn));
- ret = wt_conn->open_session(wt_conn, NULL, NULL, &session);
- ret = session->create(session, uri, "key_format=S,value_format=S");
+ error_check(wt_conn->open_session(wt_conn, NULL, NULL, &session));
+ error_check(session->create(
+ session, uri, "key_format=S,value_format=S"));
- ret = session->open_cursor(session, uri, NULL, NULL, &cursor);
+ error_check(session->open_cursor(session, uri, NULL, NULL, &cursor));
/*
* Perform some operations with individual auto-commit transactions.
*/
- ret = session->begin_transaction(session, NULL);
+ error_check(session->begin_transaction(session, NULL));
for (record_count = 0, i = 0; i < MAX_KEYS; i++, record_count++) {
if (i == MAX_KEYS/2) {
- ret = session->commit_transaction(
- session, "sync=background");
+ error_check(session->commit_transaction(
+ session, "sync=background"));
ret = session->transaction_sync(
session, "timeout_ms=0");
if (ret == ETIMEDOUT)
printf("Transactions not yet stable\n");
- else if (ret != 0)
- printf("Got error %d\n", ret);
- ret = session->begin_transaction(session, NULL);
+ else if (ret != 0) {
+ fprintf(stderr,
+ "session.transaction_sync: error %s\n",
+ session->strerror(session, ret));
+ exit (1);
+ }
+ error_check(session->begin_transaction(session, NULL));
} else {
if ((record_count % 3) == 0)
conf = "sync=background";
else
conf = "sync=off";
- ret = session->commit_transaction(session, conf);
- ret = session->begin_transaction(session, NULL);
+ error_check(session->commit_transaction(session, conf));
+ error_check(session->begin_transaction(session, NULL));
}
(void)snprintf(k, sizeof(k), "key%d", i);
(void)snprintf(v, sizeof(v), "value%d", i);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = session->commit_transaction(session, "sync=background");
+ error_check(session->commit_transaction(session, "sync=background"));
printf("Wait forever until stable\n");
- ret = session->transaction_sync(session, NULL);
+ error_check(session->transaction_sync(session, NULL));
printf("Transactions now stable\n");
- ret = session->begin_transaction(session, NULL);
+ error_check(session->begin_transaction(session, NULL));
/*
* Perform some operations within a single transaction.
*/
@@ -117,14 +100,11 @@ main(void)
(void)snprintf(v, sizeof(v), "value%d", i);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = session->commit_transaction(session, "sync=on");
- ret = session->transaction_sync(session, "timeout_ms=0");
- if (ret != 0)
- fprintf(stderr,
- "Unexpected error %d from WT_SESSION::transaction_sync\n",
- ret);
+ error_check(session->commit_transaction(session, "sync=on"));
+ error_check(session->transaction_sync(session, "timeout_ms=0"));
+
/*
* Demonstrate using log_flush to force the log to disk.
*/
@@ -133,22 +113,22 @@ main(void)
(void)snprintf(v, sizeof(v), "value%d", record_count);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = session->log_flush(session, "sync=on");
+ error_check(session->log_flush(session, "sync=on"));
for (i = 0; i < MAX_KEYS; i++, record_count++) {
(void)snprintf(k, sizeof(k), "key%d", record_count);
(void)snprintf(v, sizeof(v), "value%d", record_count);
cursor->set_key(cursor, k);
cursor->set_value(cursor, v);
- ret = cursor->insert(cursor);
+ error_check(cursor->insert(cursor));
}
- ret = cursor->close(cursor);
- ret = session->log_flush(session, "sync=off");
- ret = session->log_flush(session, "sync=on");
+ error_check(cursor->close(cursor));
+ error_check(session->log_flush(session, "sync=off"));
+ error_check(session->log_flush(session, "sync=on"));
- ret = wt_conn->close(wt_conn, NULL);
+ error_check(wt_conn->close(wt_conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
diff --git a/src/third_party/wiredtiger/examples/c/ex_thread.c b/src/third_party/wiredtiger/examples/c/ex_thread.c
index ad2ff7f68a0..fe14d67e44b 100644
--- a/src/third_party/wiredtiger/examples/c/ex_thread.c
+++ b/src/third_party/wiredtiger/examples/c/ex_thread.c
@@ -30,11 +30,7 @@
* table from multiple threads.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "wt_internal.h"
+#include "test_util.h"
static const char *home;
@@ -47,18 +43,18 @@ scan_thread(void *conn_arg)
WT_CONNECTION *conn;
WT_CURSOR *cursor;
WT_SESSION *session;
- const char *key, *value;
int ret;
+ const char *key, *value;
conn = conn_arg;
- ret = conn->open_session(conn, NULL, NULL, &session);
- ret = session->open_cursor(
- session, "table:access", NULL, NULL, &cursor);
+ error_check(conn->open_session(conn, NULL, NULL, &session));
+ error_check(session->open_cursor(
+ session, "table:access", NULL, NULL, &cursor));
/* Show all records. */
while ((ret = cursor->next(cursor)) == 0) {
- ret = cursor->get_key(cursor, &key);
- ret = cursor->get_value(cursor, &value);
+ error_check(cursor->get_key(cursor, &key));
+ error_check(cursor->get_value(cursor, &value));
printf("Got record: %s : %s\n", key, value);
}
@@ -72,47 +68,37 @@ scan_thread(void *conn_arg)
/*! [thread main] */
int
-main(void)
+main(int argc, char *argv[])
{
WT_CONNECTION *conn;
WT_SESSION *session;
WT_CURSOR *cursor;
wt_thread_t threads[NUM_THREADS];
- int i, ret;
-
- /*
- * Create a clean test directory for this run of the test program if the
- * environment variable isn't already set (as is done by make check).
- */
- if (getenv("WIREDTIGER_HOME") == NULL) {
- home = "WT_HOME";
- ret = system("rm -rf WT_HOME && mkdir WT_HOME");
- } else
- home = NULL;
-
- if ((ret = wiredtiger_open(home, NULL, "create", &conn)) != 0)
- fprintf(stderr, "Error connecting to %s: %s\n",
- home == NULL ? "." : home, wiredtiger_strerror(ret));
- /* Note: further error checking omitted for clarity. */
-
- ret = conn->open_session(conn, NULL, NULL, &session);
- ret = session->create(session, "table:access",
- "key_format=S,value_format=S");
- ret = session->open_cursor(session, "table:access", NULL,
- "overwrite", &cursor);
+ int i;
+
+ home = example_setup(argc, argv);
+
+ error_check(wiredtiger_open(home, NULL, "create", &conn));
+
+ error_check(conn->open_session(conn, NULL, NULL, &session));
+ error_check(session->create(session, "table:access",
+ "key_format=S,value_format=S"));
+ error_check(session->open_cursor(
+ session, "table:access", NULL, "overwrite", &cursor));
cursor->set_key(cursor, "key1");
cursor->set_value(cursor, "value1");
- ret = cursor->insert(cursor);
- ret = session->close(session, NULL);
+ error_check(cursor->insert(cursor));
+ error_check(session->close(session, NULL));
for (i = 0; i < NUM_THREADS; i++)
- ret = __wt_thread_create(NULL, &threads[i], scan_thread, conn);
+ error_check(
+ __wt_thread_create(NULL, &threads[i], scan_thread, conn));
for (i = 0; i < NUM_THREADS; i++)
- ret = __wt_thread_join(NULL, threads[i]);
+ error_check(__wt_thread_join(NULL, threads[i]));
- ret = conn->close(conn, NULL);
+ error_check(conn->close(conn, NULL));
- return (ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+ return (EXIT_SUCCESS);
}
/*! [thread main] */
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data
index 1dc28162933..e6068334d42 100644
--- a/src/third_party/wiredtiger/import.data
+++ b/src/third_party/wiredtiger/import.data
@@ -1,5 +1,5 @@
{
- "commit": "f59321a3726bfd0caa71b6c653f7972e9e076682",
+ "commit": "ff10db881161bbd1bc23e40ac385ff0de18f68ff",
"github": "wiredtiger/wiredtiger.git",
"vendor": "wiredtiger",
"branch": "mongodb-3.6"
diff --git a/src/third_party/wiredtiger/lang/java/java_doc.i b/src/third_party/wiredtiger/lang/java/java_doc.i
index f9e017ee43a..a1efb1b63a8 100644
--- a/src/third_party/wiredtiger/lang/java/java_doc.i
+++ b/src/third_party/wiredtiger/lang/java/java_doc.i
@@ -49,6 +49,7 @@ COPYDOC(__wt_session, WT_SESSION, verify)
COPYDOC(__wt_session, WT_SESSION, begin_transaction)
COPYDOC(__wt_session, WT_SESSION, commit_transaction)
COPYDOC(__wt_session, WT_SESSION, rollback_transaction)
+COPYDOC(__wt_session, WT_SESSION, timestamp_transaction)
COPYDOC(__wt_session, WT_SESSION, checkpoint)
COPYDOC(__wt_session, WT_SESSION, snapshot)
COPYDOC(__wt_session, WT_SESSION, transaction_pinned_range)
@@ -60,6 +61,8 @@ COPYDOC(__wt_connection, WT_CONNECTION, reconfigure)
COPYDOC(__wt_connection, WT_CONNECTION, configure_method)
COPYDOC(__wt_connection, WT_CONNECTION, is_new)
COPYDOC(__wt_connection, WT_CONNECTION, open_session)
+COPYDOC(__wt_connection, WT_CONNECTION, query_timestamp)
+COPYDOC(__wt_connection, WT_CONNECTION, set_timestamp)
COPYDOC(__wt_connection, WT_CONNECTION, load_extension)
COPYDOC(__wt_connection, WT_CONNECTION, add_data_source)
COPYDOC(__wt_connection, WT_CONNECTION, add_collator)
diff --git a/src/third_party/wiredtiger/lang/python/wiredtiger.i b/src/third_party/wiredtiger/lang/python/wiredtiger.i
index 61c7fc62c43..8c737341979 100644
--- a/src/third_party/wiredtiger/lang/python/wiredtiger.i
+++ b/src/third_party/wiredtiger/lang/python/wiredtiger.i
@@ -509,6 +509,7 @@ COMPARE_NOTFOUND_OK(__wt_cursor::_search_near)
%exception wiredtiger_strerror;
%exception wiredtiger_version;
%exception diagnostic_build;
+%exception timestamp_build;
%exception verbose_build;
/* WT_ASYNC_OP customization. */
@@ -556,6 +557,13 @@ OVERRIDE_METHOD(__wt_cursor, WT_CURSOR, search_near, (self))
%typemap(frearg) (uint64_t *recnop) "";
%typemap(argout) (uint64_t *recnop) { $result = PyLong_FromUnsignedLongLong(*$1); }
+/* Handle returned hexadecimal timestamps. */
+%typemap(in,numinputs=0) (char *hex_timestamp) (char tsbuf[2 * WT_TIMESTAMP_SIZE + 1]) { $1 = tsbuf; }
+%typemap(argout) (char *hex_timestamp) {
+ if (*$1)
+ $result = SWIG_FromCharPtr($1);
+}
+
%{
typedef int int_void;
%}
@@ -1001,6 +1009,10 @@ int diagnostic_build() {
#endif
}
+int timestamp_build() {
+ return WT_TIMESTAMP_SIZE > 0;
+}
+
int verbose_build() {
#ifdef HAVE_VERBOSE
return 1;
@@ -1010,6 +1022,7 @@ int verbose_build() {
}
%}
int diagnostic_build();
+int timestamp_build();
int verbose_build();
/* Remove / rename parts of the C API that we don't want in Python. */
diff --git a/src/third_party/wiredtiger/src/btree/bt_curnext.c b/src/third_party/wiredtiger/src/btree/bt_curnext.c
index 7b92a58991d..cb59bff8f75 100644
--- a/src/third_party/wiredtiger/src/btree/bt_curnext.c
+++ b/src/third_party/wiredtiger/src/btree/bt_curnext.c
@@ -143,7 +143,7 @@ new_page: if (cbt->ins == NULL)
if ((upd = __wt_txn_read(session, cbt->ins->upd)) == NULL)
continue;
if (upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
@@ -206,7 +206,7 @@ new_page: /* Find the matching WT_COL slot. */
NULL : __wt_txn_read(session, cbt->ins->upd);
if (upd != NULL) {
if (upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
@@ -326,7 +326,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
if ((upd = __wt_txn_read(session, ins->upd)) == NULL)
continue;
if (upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
@@ -359,7 +359,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
rip = &page->pg_row[cbt->slot];
upd = __wt_txn_read(session, WT_ROW_UPDATE(page, rip));
if (upd != NULL && upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_curprev.c b/src/third_party/wiredtiger/src/btree/bt_curprev.c
index 55b5095fe91..6e49f4df68c 100644
--- a/src/third_party/wiredtiger/src/btree/bt_curprev.c
+++ b/src/third_party/wiredtiger/src/btree/bt_curprev.c
@@ -289,7 +289,7 @@ new_page: if (cbt->ins == NULL)
if ((upd = __wt_txn_read(session, cbt->ins->upd)) == NULL)
continue;
if (upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
@@ -353,7 +353,7 @@ new_page: if (cbt->recno < cbt->ref->ref_recno)
NULL : __wt_txn_read(session, cbt->ins->upd);
if (upd != NULL) {
if (upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
@@ -483,7 +483,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
if ((upd = __wt_txn_read(session, ins->upd)) == NULL)
continue;
if (upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
@@ -518,7 +518,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
rip = &page->pg_row[cbt->slot];
upd = __wt_txn_read(session, WT_ROW_UPDATE(page, rip));
if (upd != NULL && upd->type == WT_UPDATE_DELETED) {
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
++cbt->page_deleted_count;
continue;
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_delete.c b/src/third_party/wiredtiger/src/btree/bt_delete.c
index 4a88b672d47..eac8994a5a4 100644
--- a/src/third_party/wiredtiger/src/btree/bt_delete.c
+++ b/src/third_party/wiredtiger/src/btree/bt_delete.c
@@ -242,8 +242,10 @@ __wt_delete_page_skip(WT_SESSION_IMPL *session, WT_REF *ref, bool visible_all)
return (false);
skip = ref->page_del == NULL || (visible_all ?
- __wt_txn_visible_all(session, ref->page_del->txnid) :
- __wt_txn_visible(session, ref->page_del->txnid));
+ __wt_txn_visible_all(session,
+ ref->page_del->txnid, WT_GET_TIMESTAMP(ref->page_del)):
+ __wt_txn_visible(session,
+ ref->page_del->txnid, WT_GET_TIMESTAMP(ref->page_del)));
/*
* The page_del structure can be freed as soon as the delete is stable:
@@ -252,7 +254,8 @@ __wt_delete_page_skip(WT_SESSION_IMPL *session, WT_REF *ref, bool visible_all)
* no longer need synchronization to check the ref.
*/
if (skip && ref->page_del != NULL && (visible_all ||
- __wt_txn_visible_all(session, ref->page_del->txnid))) {
+ __wt_txn_visible_all(session,
+ ref->page_del->txnid, WT_GET_TIMESTAMP(ref->page_del)))) {
__wt_free(session, ref->page_del->update_list);
__wt_free(session, ref->page_del);
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_ovfl.c b/src/third_party/wiredtiger/src/btree/bt_ovfl.c
index 3d09f655c65..76d1bfd121c 100644
--- a/src/third_party/wiredtiger/src/btree/bt_ovfl.c
+++ b/src/third_party/wiredtiger/src/btree/bt_ovfl.c
@@ -99,7 +99,7 @@ __ovfl_cache_col_visible(
*/
if (__wt_cell_rle(unpack) == 1 &&
upd != NULL && /* Sanity: upd should always be set. */
- __wt_txn_visible_all(session, upd->txnid))
+ __wt_txn_upd_visible_all(session, upd))
return (true);
return (false);
}
@@ -115,7 +115,7 @@ __ovfl_cache_row_visible(WT_SESSION_IMPL *session, WT_PAGE *page, WT_ROW *rip)
/* Check to see if there's a globally visible update. */
for (upd = WT_ROW_UPDATE(page, rip); upd != NULL; upd = upd->next)
- if (__wt_txn_visible_all(session, upd->txnid))
+ if (__wt_txn_upd_visible_all(session, upd))
return (true);
return (false);
diff --git a/src/third_party/wiredtiger/src/btree/bt_read.c b/src/third_party/wiredtiger/src/btree/bt_read.c
index 3f85e58f088..5f8cf3a45e1 100644
--- a/src/third_party/wiredtiger/src/btree/bt_read.c
+++ b/src/third_party/wiredtiger/src/btree/bt_read.c
@@ -18,8 +18,7 @@ int
__wt_las_remove_block(WT_SESSION_IMPL *session,
WT_CURSOR *cursor, uint32_t btree_id, const uint8_t *addr, size_t addr_size)
{
- WT_DECL_ITEM(las_addr);
- WT_DECL_ITEM(las_key);
+ WT_ITEM las_addr, las_key, las_timestamp;
WT_DECL_RET;
uint64_t las_counter, las_txnid, remove_cnt;
uint32_t las_id;
@@ -27,31 +26,29 @@ __wt_las_remove_block(WT_SESSION_IMPL *session,
remove_cnt = 0;
- WT_ERR(__wt_scr_alloc(session, 0, &las_addr));
- WT_ERR(__wt_scr_alloc(session, 0, &las_key));
-
/*
* Search for the block's unique prefix and step through all matching
* records, removing them.
*/
- las_addr->data = addr;
- las_addr->size = addr_size;
- las_key->size = 0;
- cursor->set_key(
- cursor, btree_id, las_addr, (uint64_t)0, (uint32_t)0, las_key);
+ las_addr.data = addr;
+ las_addr.size = addr_size;
+ las_key.size = 0;
+ las_timestamp.size = 0;
+ cursor->set_key(cursor, btree_id, &las_addr,
+ (uint64_t)0, (uint32_t)0, &las_timestamp, &las_key);
if ((ret = cursor->search_near(cursor, &exact)) == 0 && exact < 0)
ret = cursor->next(cursor);
for (; ret == 0; ret = cursor->next(cursor)) {
- WT_ERR(cursor->get_key(cursor,
- &las_id, las_addr, &las_counter, &las_txnid, las_key));
+ WT_ERR(cursor->get_key(cursor, &las_id, &las_addr, &las_counter,
+ &las_txnid, &las_timestamp, &las_key));
/*
* Confirm the search using the unique prefix; if not a match,
* we're done searching for records for this page.
*/
if (las_id != btree_id ||
- las_addr->size != addr_size ||
- memcmp(las_addr->data, addr, addr_size) != 0)
+ las_addr.size != addr_size ||
+ memcmp(las_addr.data, addr, addr_size) != 0)
break;
/*
@@ -64,10 +61,7 @@ __wt_las_remove_block(WT_SESSION_IMPL *session,
}
WT_ERR_NOTFOUND_OK(ret);
-err: __wt_scr_free(session, &las_addr);
- __wt_scr_free(session, &las_key);
-
- /*
+err: /*
* If there were races to remove records, we can over-count. All
* arithmetic is signed, so underflow isn't fatal, but check anyway so
* we don't skew low over time.
@@ -122,9 +116,7 @@ __las_page_instantiate(WT_SESSION_IMPL *session,
WT_CURSOR *cursor;
WT_CURSOR_BTREE cbt;
WT_DECL_ITEM(current_key);
- WT_DECL_ITEM(las_addr);
- WT_DECL_ITEM(las_key);
- WT_DECL_ITEM(las_value);
+ WT_ITEM las_addr, las_key, las_timestamp, las_value;
WT_DECL_RET;
WT_PAGE *page;
WT_UPDATE *first_upd, *last_upd, *upd;
@@ -141,14 +133,13 @@ __las_page_instantiate(WT_SESSION_IMPL *session,
total_incr = 0;
current_recno = recno = WT_RECNO_OOB;
session_flags = 0; /* [-Werror=maybe-uninitialized] */
+ WT_CLEAR(las_key);
+ WT_CLEAR(las_timestamp);
__wt_btcur_init(session, &cbt);
__wt_btcur_open(&cbt);
WT_ERR(__wt_scr_alloc(session, 0, &current_key));
- WT_ERR(__wt_scr_alloc(session, 0, &las_addr));
- WT_ERR(__wt_scr_alloc(session, 0, &las_key));
- WT_ERR(__wt_scr_alloc(session, 0, &las_value));
/* Open a lookaside table cursor. */
__wt_las_cursor(session, &cursor, &session_flags);
@@ -163,46 +154,53 @@ __las_page_instantiate(WT_SESSION_IMPL *session,
* Search for the block's unique prefix, stepping through any matching
* records.
*/
- las_addr->data = addr;
- las_addr->size = addr_size;
- las_key->size = 0;
- cursor->set_key(
- cursor, read_id, las_addr, (uint64_t)0, (uint32_t)0, las_key);
+ las_addr.data = addr;
+ las_addr.size = addr_size;
+ cursor->set_key(cursor, read_id, &las_addr,
+ (uint64_t)0, (uint32_t)0, &las_timestamp, &las_key);
if ((ret = cursor->search_near(cursor, &exact)) == 0 && exact < 0)
ret = cursor->next(cursor);
for (; ret == 0; ret = cursor->next(cursor)) {
- WT_ERR(cursor->get_key(cursor,
- &las_id, las_addr, &las_counter, &las_txnid, las_key));
+ WT_ERR(cursor->get_key(cursor, &las_id, &las_addr, &las_counter,
+ &las_txnid, &las_timestamp, &las_key));
/*
* Confirm the search using the unique prefix; if not a match,
* we're done searching for records for this page.
*/
if (las_id != read_id ||
- las_addr->size != addr_size ||
- memcmp(las_addr->data, addr, addr_size) != 0)
+ las_addr.size != addr_size ||
+ memcmp(las_addr.data, addr, addr_size) != 0)
break;
/*
* If the on-page value has become globally visible, this record
- * is no longer needed.
+ * is no longer needed. We clear the las_timestamp structure
+ * above to avoid reading uninitialized memory here when
+ * timestamps are disabled (even though it is unused in that
+ * case).
*/
- if (__wt_txn_visible_all(session, las_txnid))
+ if (__wt_txn_visible_all(
+ session, las_txnid, las_timestamp.data))
continue;
/* Allocate the WT_UPDATE structure. */
- WT_ERR(cursor->get_value(
- cursor, &upd_txnid, &upd_type, las_value));
- WT_ERR(__wt_update_alloc(session, las_value, &upd, &incr,
+ WT_ERR(cursor->get_value(cursor,
+ &upd_txnid, &las_timestamp, &upd_type, &las_value));
+ WT_ERR(__wt_update_alloc(session, &las_value, &upd, &incr,
upd_type == WT_UPDATE_DELETED ?
WT_UPDATE_DELETED : WT_UPDATE_STANDARD));
total_incr += incr;
upd->txnid = upd_txnid;
+#ifdef HAVE_TIMESTAMPS
+ WT_ASSERT(session, las_timestamp.size == WT_TIMESTAMP_SIZE);
+ __wt_timestamp_set(upd->timestamp, las_timestamp.data);
+#endif
switch (page->type) {
case WT_PAGE_COL_FIX:
case WT_PAGE_COL_VAR:
- p = las_key->data;
+ p = las_key.data;
WT_ERR(__wt_vunpack_uint(&p, 0, &recno));
if (current_recno == recno)
break;
@@ -216,9 +214,9 @@ __las_page_instantiate(WT_SESSION_IMPL *session,
current_recno = recno;
break;
case WT_PAGE_ROW_LEAF:
- if (current_key->size == las_key->size &&
+ if (current_key->size == las_key.size &&
memcmp(current_key->data,
- las_key->data, las_key->size) == 0)
+ las_key.data, las_key.size) == 0)
break;
if (first_upd != NULL) {
@@ -227,7 +225,7 @@ __las_page_instantiate(WT_SESSION_IMPL *session,
first_upd = NULL;
}
WT_ERR(__wt_buf_set(session,
- current_key, las_key->data, las_key->size));
+ current_key, las_key.data, las_key.size));
break;
WT_ILLEGAL_VALUE_ERR(session);
}
@@ -289,9 +287,6 @@ err: WT_TRET(__wt_las_cursor_close(session, &cursor, session_flags));
__wt_free_update_list(session, first_upd);
__wt_scr_free(session, &current_key);
- __wt_scr_free(session, &las_addr);
- __wt_scr_free(session, &las_key);
- __wt_scr_free(session, &las_value);
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/btree/row_modify.c b/src/third_party/wiredtiger/src/btree/row_modify.c
index cab07341a1c..e2d19bf705b 100644
--- a/src/third_party/wiredtiger/src/btree/row_modify.c
+++ b/src/third_party/wiredtiger/src/btree/row_modify.c
@@ -304,7 +304,7 @@ __wt_update_obsolete_check(
* Walk the list of updates, looking for obsolete updates at the end.
*/
for (first = NULL, count = 0; upd != NULL; upd = upd->next, count++)
- if (__wt_txn_visible_all(session, upd->txnid)) {
+ if (__wt_txn_upd_visible_all(session, upd)) {
if (first == NULL)
first = upd;
} else if (upd->txnid != WT_TXN_ABORTED)
diff --git a/src/third_party/wiredtiger/src/cache/cache_las.c b/src/third_party/wiredtiger/src/cache/cache_las.c
index a2233514223..a118e5d5e41 100644
--- a/src/third_party/wiredtiger/src/cache/cache_las.c
+++ b/src/third_party/wiredtiger/src/cache/cache_las.c
@@ -288,8 +288,7 @@ __wt_las_sweep(WT_SESSION_IMPL *session)
{
WT_CONNECTION_IMPL *conn;
WT_CURSOR *cursor;
- WT_DECL_ITEM(las_addr);
- WT_DECL_ITEM(las_key);
+ WT_ITEM las_addr, las_key, las_timestamp;
WT_DECL_RET;
WT_ITEM *key;
uint64_t cnt, las_counter, las_txnid, remove_cnt;
@@ -301,9 +300,7 @@ __wt_las_sweep(WT_SESSION_IMPL *session)
key = &conn->las_sweep_key;
remove_cnt = 0;
session_flags = 0; /* [-Werror=maybe-uninitialized] */
-
- WT_ERR(__wt_scr_alloc(session, 0, &las_addr));
- WT_ERR(__wt_scr_alloc(session, 0, &las_key));
+ WT_CLEAR(las_timestamp);
__wt_las_cursor(session, &cursor, &session_flags);
@@ -362,8 +359,8 @@ __wt_las_sweep(WT_SESSION_IMPL *session)
session, key, key->data, key->size));
}
- WT_ERR(cursor->get_key(cursor,
- &las_id, las_addr, &las_counter, &las_txnid, las_key));
+ WT_ERR(cursor->get_key(cursor, &las_id, &las_addr, &las_counter,
+ &las_txnid, &las_timestamp, &las_key));
/*
* If the on-page record transaction ID associated with the
@@ -372,8 +369,13 @@ __wt_las_sweep(WT_SESSION_IMPL *session)
* Cursor opened overwrite=true: won't return WT_NOTFOUND should
* another thread remove the record before we do, and the cursor
* remains positioned in that case.
+ *
+ * We clear the las_timestamp structure above to avoid reading
+ * uninitialized memory here when timestamps are disabled (even
+ * though it is unused in that case).
*/
- if (__wt_txn_visible_all(session, las_txnid)) {
+ if (__wt_txn_visible_all(
+ session, las_txnid, las_timestamp.data)) {
WT_ERR(cursor->remove(cursor));
++remove_cnt;
}
@@ -399,8 +401,5 @@ err: __wt_buf_free(session, key);
F_CLR(session, WT_SESSION_NO_CACHE);
- __wt_scr_free(session, &las_addr);
- __wt_scr_free(session, &las_key);
-
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/config/config.c b/src/third_party/wiredtiger/src/config/config.c
index 33eb988fc5a..9669d5bb39f 100644
--- a/src/third_party/wiredtiger/src/config/config.c
+++ b/src/third_party/wiredtiger/src/config/config.c
@@ -482,22 +482,24 @@ __config_next(WT_CONFIG *conf, WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value)
*/
#define WT_SHIFT_INT64(v, s) do { \
if ((v) < 0) \
- goto range; \
+ goto nonum; \
(v) = (int64_t)(((uint64_t)(v)) << (s)); \
+ if ((v) < 0) \
+ goto nonum; \
} while (0)
/*
* __config_process_value --
* Deal with special config values like true / false.
*/
-static int
-__config_process_value(WT_CONFIG *conf, WT_CONFIG_ITEM *value)
+static void
+__config_process_value(WT_CONFIG_ITEM *value)
{
char *endptr;
/* Empty values are okay: we can't do anything interesting with them. */
if (value->len == 0)
- return (0);
+ return;
if (value->type == WT_CONFIG_ITEM_ID) {
if (WT_STRING_MATCH("false", value->str, value->len)) {
@@ -511,6 +513,14 @@ __config_process_value(WT_CONFIG *conf, WT_CONFIG_ITEM *value)
errno = 0;
value->val = strtoll(value->str, &endptr, 10);
+ /*
+ * If we parsed the string but the number is out of range,
+ * treat the value as an identifier. If an integer is
+ * expected, that will be caught by __wt_config_check.
+ */
+ if (value->type == WT_CONFIG_ITEM_NUM && errno == ERANGE)
+ goto nonum;
+
/* Check any leftover characters. */
while (endptr < value->str + value->len)
switch (*endptr++) {
@@ -539,28 +549,17 @@ __config_process_value(WT_CONFIG *conf, WT_CONFIG_ITEM *value)
WT_SHIFT_INT64(value->val, 50);
break;
default:
- /*
- * We didn't get a well-formed number. That
- * might be okay, the required type will be
- * checked by __wt_config_check.
- */
- value->type = WT_CONFIG_ITEM_ID;
- break;
+ goto nonum;
}
+ }
- /*
- * If we parsed the whole string but the number is out of range,
- * report an error. Don't report an error for strings that
- * aren't well-formed integers: if an integer is expected, that
- * will be caught by __wt_config_check.
+ if (0) {
+nonum: /*
+ * We didn't get a well-formed number. That might be okay, the
+ * required type will be checked by __wt_config_check.
*/
- if (value->type == WT_CONFIG_ITEM_NUM && errno == ERANGE)
- goto range;
+ value->type = WT_CONFIG_ITEM_ID;
}
-
- return (0);
-
-range: return (__config_err(conf, "Number out of range", ERANGE));
}
/*
@@ -571,7 +570,8 @@ int
__wt_config_next(WT_CONFIG *conf, WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value)
{
WT_RET(__config_next(conf, key, value));
- return (__config_process_value(conf, value));
+ __config_process_value(value);
+ return (0);
}
/*
@@ -611,7 +611,9 @@ __config_getraw(
if (!found)
return (WT_NOTFOUND);
- return (top ? __config_process_value(cparser, value) : 0);
+ if (top)
+ __config_process_value(value);
+ return (0);
}
/*
diff --git a/src/third_party/wiredtiger/src/config/config_def.c b/src/third_party/wiredtiger/src/config/config_def.c
index a7397d21c6a..30b2b3e0e4d 100644
--- a/src/third_party/wiredtiger/src/config/config_def.c
+++ b/src/third_party/wiredtiger/src/config/config_def.c
@@ -32,6 +32,13 @@ static const WT_CONFIG_CHECK confchk_WT_CONNECTION_open_session[] = {
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_query_timestamp[] = {
+ { "get", "string",
+ NULL, "choices=[\"all_committed\"]",
+ NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
static const WT_CONFIG_CHECK
confchk_wiredtiger_open_async_subconfigs[] = {
{ "enabled", "boolean", NULL, NULL, NULL, 0 },
@@ -110,6 +117,9 @@ static const WT_CONFIG_CHECK confchk_WT_CONNECTION_reconfigure[] = {
{ "checkpoint", "category",
NULL, NULL,
confchk_wiredtiger_open_checkpoint_subconfigs, 2 },
+ { "diagnostic_timing_stress", "list",
+ NULL, "choices=[\"checkpoint_slow\"]",
+ NULL, 0 },
{ "error_prefix", "string", NULL, NULL, NULL, 0 },
{ "eviction", "category",
NULL, NULL,
@@ -158,6 +168,11 @@ static const WT_CONFIG_CHECK confchk_WT_CONNECTION_reconfigure[] = {
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_set_timestamp[] = {
+ { "oldest_timestamp", "string", NULL, NULL, NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
static const WT_CONFIG_CHECK confchk_WT_CURSOR_reconfigure[] = {
{ "append", "boolean", NULL, NULL, NULL, 0 },
{ "overwrite", "boolean", NULL, NULL, NULL, 0 },
@@ -179,6 +194,7 @@ static const WT_CONFIG_CHECK confchk_WT_SESSION_begin_transaction[] = {
NULL, 0 },
{ "name", "string", NULL, NULL, NULL, 0 },
{ "priority", "int", NULL, "min=-100,max=100", NULL, 0 },
+ { "read_timestamp", "string", NULL, NULL, NULL, 0 },
{ "snapshot", "string", NULL, NULL, NULL, 0 },
{ "sync", "boolean", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
@@ -188,11 +204,13 @@ static const WT_CONFIG_CHECK confchk_WT_SESSION_checkpoint[] = {
{ "drop", "list", NULL, NULL, NULL, 0 },
{ "force", "boolean", NULL, NULL, NULL, 0 },
{ "name", "string", NULL, NULL, NULL, 0 },
+ { "read_timestamp", "string", NULL, NULL, NULL, 0 },
{ "target", "list", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
static const WT_CONFIG_CHECK confchk_WT_SESSION_commit_transaction[] = {
+ { "commit_timestamp", "string", NULL, NULL, NULL, 0 },
{ "sync", "string",
NULL, "choices=[\"background\",\"off\",\"on\"]",
NULL, 0 },
@@ -389,6 +407,11 @@ static const WT_CONFIG_CHECK confchk_WT_SESSION_snapshot[] = {
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
+static const WT_CONFIG_CHECK confchk_WT_SESSION_timestamp_transaction[] = {
+ { "commit_timestamp", "string", NULL, NULL, NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
static const WT_CONFIG_CHECK confchk_WT_SESSION_transaction_sync[] = {
{ "timeout_ms", "int", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
@@ -691,6 +714,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open[] = {
{ "checkpoint_sync", "boolean", NULL, NULL, NULL, 0 },
{ "config_base", "boolean", NULL, NULL, NULL, 0 },
{ "create", "boolean", NULL, NULL, NULL, 0 },
+ { "diagnostic_timing_stress", "list",
+ NULL, "choices=[\"checkpoint_slow\"]",
+ NULL, 0 },
{ "direct_io", "list",
NULL, "choices=[\"checkpoint\",\"data\",\"log\"]",
NULL, 0 },
@@ -779,6 +805,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_all[] = {
{ "checkpoint_sync", "boolean", NULL, NULL, NULL, 0 },
{ "config_base", "boolean", NULL, NULL, NULL, 0 },
{ "create", "boolean", NULL, NULL, NULL, 0 },
+ { "diagnostic_timing_stress", "list",
+ NULL, "choices=[\"checkpoint_slow\"]",
+ NULL, 0 },
{ "direct_io", "list",
NULL, "choices=[\"checkpoint\",\"data\",\"log\"]",
NULL, 0 },
@@ -866,6 +895,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_basecfg[] = {
NULL, NULL,
confchk_wiredtiger_open_checkpoint_subconfigs, 2 },
{ "checkpoint_sync", "boolean", NULL, NULL, NULL, 0 },
+ { "diagnostic_timing_stress", "list",
+ NULL, "choices=[\"checkpoint_slow\"]",
+ NULL, 0 },
{ "direct_io", "list",
NULL, "choices=[\"checkpoint\",\"data\",\"log\"]",
NULL, 0 },
@@ -949,6 +981,9 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_usercfg[] = {
NULL, NULL,
confchk_wiredtiger_open_checkpoint_subconfigs, 2 },
{ "checkpoint_sync", "boolean", NULL, NULL, NULL, 0 },
+ { "diagnostic_timing_stress", "list",
+ NULL, "choices=[\"checkpoint_slow\"]",
+ NULL, 0 },
{ "direct_io", "list",
NULL, "choices=[\"checkpoint\",\"data\",\"log\"]",
NULL, 0 },
@@ -1057,25 +1092,34 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"ignore_cache_size=false,isolation=read-committed",
confchk_WT_CONNECTION_open_session, 2
},
+ { "WT_CONNECTION.query_timestamp",
+ "get=all_committed",
+ confchk_WT_CONNECTION_query_timestamp, 1
+ },
{ "WT_CONNECTION.reconfigure",
"async=(enabled=false,ops_max=1024,threads=2),cache_overhead=8,"
- "cache_size=100MB,checkpoint=(log_size=0,wait=0),error_prefix=,"
- "eviction=(threads_max=8,threads_min=1),"
- "eviction_checkpoint_target=5,eviction_dirty_target=5,"
- "eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
- ",file_manager=(close_handle_minimum=250,close_idle_time=30,"
+ "cache_size=100MB,checkpoint=(log_size=0,wait=0),"
+ "diagnostic_timing_stress=,error_prefix=,eviction=(threads_max=8,"
+ "threads_min=1),eviction_checkpoint_target=5,"
+ "eviction_dirty_target=5,eviction_dirty_trigger=20,"
+ "eviction_target=80,eviction_trigger=95,"
+ "file_manager=(close_handle_minimum=250,close_idle_time=30,"
"close_scan_interval=10),log=(archive=true,prealloc=true,"
"zero_fill=false),lsm_manager=(merge=true,worker_thread_max=4),"
"lsm_merge=true,shared_cache=(chunk=10MB,name=,quota=0,reserve=0,"
"size=500MB),statistics=none,statistics_log=(json=false,"
"on_close=false,sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
"verbose=",
- confchk_WT_CONNECTION_reconfigure, 19
+ confchk_WT_CONNECTION_reconfigure, 20
},
{ "WT_CONNECTION.set_file_system",
"",
NULL, 0
},
+ { "WT_CONNECTION.set_timestamp",
+ "oldest_timestamp=",
+ confchk_WT_CONNECTION_set_timestamp, 1
+ },
{ "WT_CURSOR.close",
"",
NULL, 0
@@ -1089,20 +1133,20 @@ static const WT_CONFIG_ENTRY config_entries[] = {
confchk_WT_SESSION_alter, 2
},
{ "WT_SESSION.begin_transaction",
- "isolation=,name=,priority=0,snapshot=,sync=",
- confchk_WT_SESSION_begin_transaction, 5
+ "isolation=,name=,priority=0,read_timestamp=,snapshot=,sync=",
+ confchk_WT_SESSION_begin_transaction, 6
},
{ "WT_SESSION.checkpoint",
- "drop=,force=false,name=,target=",
- confchk_WT_SESSION_checkpoint, 4
+ "drop=,force=false,name=,read_timestamp=,target=",
+ confchk_WT_SESSION_checkpoint, 5
},
{ "WT_SESSION.close",
"",
NULL, 0
},
{ "WT_SESSION.commit_transaction",
- "sync=",
- confchk_WT_SESSION_commit_transaction, 1
+ "commit_timestamp=,sync=",
+ confchk_WT_SESSION_commit_transaction, 2
},
{ "WT_SESSION.compact",
"timeout=1200",
@@ -1185,6 +1229,10 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"",
NULL, 0
},
+ { "WT_SESSION.timestamp_transaction",
+ "commit_timestamp=",
+ confchk_WT_SESSION_timestamp_transaction, 1
+ },
{ "WT_SESSION.transaction_sync",
"timeout_ms=1200000",
confchk_WT_SESSION_transaction_sync, 1
@@ -1270,57 +1318,57 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
"checkpoint=(log_size=0,wait=0),checkpoint_sync=true,"
- "config_base=true,create=false,direct_io=,encryption=(keyid=,"
- "name=,secretkey=),error_prefix=,eviction=(threads_max=8,"
- "threads_min=1),eviction_checkpoint_target=5,"
- "eviction_dirty_target=5,eviction_dirty_trigger=20,"
- "eviction_target=80,eviction_trigger=95,exclusive=false,"
- "extensions=,file_extend=,file_manager=(close_handle_minimum=250,"
- "close_idle_time=30,close_scan_interval=10),hazard_max=1000,"
- "in_memory=false,log=(archive=true,compressor=,enabled=false,"
- "file_max=100MB,path=\".\",prealloc=true,recover=on,"
- "zero_fill=false),lsm_manager=(merge=true,worker_thread_max=4),"
- "lsm_merge=true,mmap=true,multiprocess=false,readonly=false,"
- "session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB"
- ",name=,quota=0,reserve=0,size=500MB),statistics=none,"
- "statistics_log=(json=false,on_close=false,path=\".\",sources=,"
- "timestamp=\"%b %d %H:%M:%S\",wait=0),"
- "transaction_sync=(enabled=false,method=fsync),"
+ "config_base=true,create=false,diagnostic_timing_stress=,"
+ "direct_io=,encryption=(keyid=,name=,secretkey=),error_prefix=,"
+ "eviction=(threads_max=8,threads_min=1),"
+ "eviction_checkpoint_target=5,eviction_dirty_target=5,"
+ "eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
+ ",exclusive=false,extensions=,file_extend=,"
+ "file_manager=(close_handle_minimum=250,close_idle_time=30,"
+ "close_scan_interval=10),hazard_max=1000,in_memory=false,"
+ "log=(archive=true,compressor=,enabled=false,file_max=100MB,"
+ "path=\".\",prealloc=true,recover=on,zero_fill=false),"
+ "lsm_manager=(merge=true,worker_thread_max=4),lsm_merge=true,"
+ "mmap=true,multiprocess=false,readonly=false,session_max=100,"
+ "session_scratch_max=2MB,shared_cache=(chunk=10MB,name=,quota=0,"
+ "reserve=0,size=500MB),statistics=none,statistics_log=(json=false"
+ ",on_close=false,path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\""
+ ",wait=0),transaction_sync=(enabled=false,method=fsync),"
"use_environment=true,use_environment_priv=false,verbose=,"
"write_through=",
- confchk_wiredtiger_open, 40
+ confchk_wiredtiger_open, 41
},
{ "wiredtiger_open_all",
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
"checkpoint=(log_size=0,wait=0),checkpoint_sync=true,"
- "config_base=true,create=false,direct_io=,encryption=(keyid=,"
- "name=,secretkey=),error_prefix=,eviction=(threads_max=8,"
- "threads_min=1),eviction_checkpoint_target=5,"
- "eviction_dirty_target=5,eviction_dirty_trigger=20,"
- "eviction_target=80,eviction_trigger=95,exclusive=false,"
- "extensions=,file_extend=,file_manager=(close_handle_minimum=250,"
- "close_idle_time=30,close_scan_interval=10),hazard_max=1000,"
- "in_memory=false,log=(archive=true,compressor=,enabled=false,"
- "file_max=100MB,path=\".\",prealloc=true,recover=on,"
- "zero_fill=false),lsm_manager=(merge=true,worker_thread_max=4),"
- "lsm_merge=true,mmap=true,multiprocess=false,readonly=false,"
- "session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB"
- ",name=,quota=0,reserve=0,size=500MB),statistics=none,"
- "statistics_log=(json=false,on_close=false,path=\".\",sources=,"
- "timestamp=\"%b %d %H:%M:%S\",wait=0),"
- "transaction_sync=(enabled=false,method=fsync),"
+ "config_base=true,create=false,diagnostic_timing_stress=,"
+ "direct_io=,encryption=(keyid=,name=,secretkey=),error_prefix=,"
+ "eviction=(threads_max=8,threads_min=1),"
+ "eviction_checkpoint_target=5,eviction_dirty_target=5,"
+ "eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
+ ",exclusive=false,extensions=,file_extend=,"
+ "file_manager=(close_handle_minimum=250,close_idle_time=30,"
+ "close_scan_interval=10),hazard_max=1000,in_memory=false,"
+ "log=(archive=true,compressor=,enabled=false,file_max=100MB,"
+ "path=\".\",prealloc=true,recover=on,zero_fill=false),"
+ "lsm_manager=(merge=true,worker_thread_max=4),lsm_merge=true,"
+ "mmap=true,multiprocess=false,readonly=false,session_max=100,"
+ "session_scratch_max=2MB,shared_cache=(chunk=10MB,name=,quota=0,"
+ "reserve=0,size=500MB),statistics=none,statistics_log=(json=false"
+ ",on_close=false,path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\""
+ ",wait=0),transaction_sync=(enabled=false,method=fsync),"
"use_environment=true,use_environment_priv=false,verbose=,"
"version=(major=0,minor=0),write_through=",
- confchk_wiredtiger_open_all, 41
+ confchk_wiredtiger_open_all, 42
},
{ "wiredtiger_open_basecfg",
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
- "checkpoint=(log_size=0,wait=0),checkpoint_sync=true,direct_io=,"
- "encryption=(keyid=,name=,secretkey=),error_prefix=,"
- "eviction=(threads_max=8,threads_min=1),"
- "eviction_checkpoint_target=5,eviction_dirty_target=5,"
+ "checkpoint=(log_size=0,wait=0),checkpoint_sync=true,"
+ "diagnostic_timing_stress=,direct_io=,encryption=(keyid=,name=,"
+ "secretkey=),error_prefix=,eviction=(threads_max=8,threads_min=1)"
+ ",eviction_checkpoint_target=5,eviction_dirty_target=5,"
"eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
",extensions=,file_extend=,file_manager=(close_handle_minimum=250"
",close_idle_time=30,close_scan_interval=10),hazard_max=1000,"
@@ -1333,15 +1381,15 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",on_close=false,path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\""
",wait=0),transaction_sync=(enabled=false,method=fsync),verbose=,"
"version=(major=0,minor=0),write_through=",
- confchk_wiredtiger_open_basecfg, 35
+ confchk_wiredtiger_open_basecfg, 36
},
{ "wiredtiger_open_usercfg",
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
- "checkpoint=(log_size=0,wait=0),checkpoint_sync=true,direct_io=,"
- "encryption=(keyid=,name=,secretkey=),error_prefix=,"
- "eviction=(threads_max=8,threads_min=1),"
- "eviction_checkpoint_target=5,eviction_dirty_target=5,"
+ "checkpoint=(log_size=0,wait=0),checkpoint_sync=true,"
+ "diagnostic_timing_stress=,direct_io=,encryption=(keyid=,name=,"
+ "secretkey=),error_prefix=,eviction=(threads_max=8,threads_min=1)"
+ ",eviction_checkpoint_target=5,eviction_dirty_target=5,"
"eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
",extensions=,file_extend=,file_manager=(close_handle_minimum=250"
",close_idle_time=30,close_scan_interval=10),hazard_max=1000,"
@@ -1354,7 +1402,7 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",on_close=false,path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\""
",wait=0),transaction_sync=(enabled=false,method=fsync),verbose=,"
"write_through=",
- confchk_wiredtiger_open_usercfg, 34
+ confchk_wiredtiger_open_usercfg, 35
},
{ NULL, NULL, NULL, 0 }
};
diff --git a/src/third_party/wiredtiger/src/conn/conn_api.c b/src/third_party/wiredtiger/src/conn/conn_api.c
index 70e96aa8473..cb0aa17791e 100644
--- a/src/third_party/wiredtiger/src/conn/conn_api.c
+++ b/src/third_party/wiredtiger/src/conn/conn_api.c
@@ -1143,6 +1143,7 @@ __conn_reconfigure(WT_CONNECTION *wt_conn, const char *config)
WT_ERR(__wt_statlog_create(session, cfg));
WT_ERR(__wt_sweep_config(session, cfg));
WT_ERR(__wt_verbose_config(session, cfg));
+ WT_ERR(__wt_timing_stress_config(session, cfg));
/* Third, merge everything together, creating a new connection state. */
WT_ERR(__wt_config_merge(session, cfg, NULL, &p));
@@ -1184,6 +1185,43 @@ err: API_END_RET_NOTFOUND_MAP(session, ret);
}
/*
+ * __conn_query_timestamp --
+ * WT_CONNECTION->query_timestamp method.
+ */
+static int
+__conn_query_timestamp(WT_CONNECTION *wt_conn,
+ char *hex_timestamp, const char *config)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_SESSION_IMPL *session;
+
+ conn = (WT_CONNECTION_IMPL *)wt_conn;
+
+ CONNECTION_API_CALL(conn, session, query_timestamp, config, cfg);
+ WT_TRET(__wt_txn_global_query_timestamp(session, hex_timestamp, cfg));
+err: API_END_RET(session, ret);
+}
+
+/*
+ * __conn_set_timestamp --
+ * WT_CONNECTION->set_timestamp method.
+ */
+static int
+__conn_set_timestamp(WT_CONNECTION *wt_conn, const char *config)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_SESSION_IMPL *session;
+
+ conn = (WT_CONNECTION_IMPL *)wt_conn;
+
+ CONNECTION_API_CALL(conn, session, set_timestamp, config, cfg);
+ WT_TRET(__wt_txn_global_set_timestamp(session, cfg));
+err: API_END_RET(session, ret);
+}
+
+/*
* __conn_config_append --
* Append an entry to a config stack.
*/
@@ -1857,6 +1895,50 @@ __wt_verbose_config(WT_SESSION_IMPL *session, const char *cfg[])
}
/*
+ * __wt_timing_stress_config --
+ * Set diagnostic stress timing delay configuration.
+ */
+int
+__wt_timing_stress_config(WT_SESSION_IMPL *session, const char *cfg[])
+{
+ static const WT_NAME_FLAG stress_types[] = {
+ { "checkpoint_slow", WT_TIMING_STRESS_CHECKPOINT_SLOW },
+ { NULL, 0 }
+ };
+ WT_CONFIG_ITEM cval, sval;
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ const WT_NAME_FLAG *ft;
+ uint32_t flags;
+
+ conn = S2C(session);
+
+ WT_RET(__wt_config_gets(
+ session, cfg, "diagnostic_timing_stress", &cval));
+
+ flags = 0;
+ for (ft = stress_types; ft->name != NULL; ft++) {
+ if ((ret = __wt_config_subgets(
+ session, &cval, ft->name, &sval)) == 0 && sval.val != 0) {
+#ifdef HAVE_DIAGNOSTIC
+ LF_SET(ft->flag);
+#else
+ WT_RET_MSG(session, EINVAL,
+ "diagnostic_timing_stress option specified when "
+ "WiredTiger built without diagnostic support. Add "
+ "--enable-diagnostic to configure command and "
+ "rebuild to include support for diagnostic stress "
+ "timing delays");
+#endif
+ }
+ WT_RET_NOTFOUND_OK(ret);
+ }
+
+ conn->timing_stress_flags = flags;
+ return (0);
+}
+
+/*
* __conn_write_base_config --
* Save the base configuration used to create a database.
*/
@@ -2088,6 +2170,8 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
__conn_configure_method,
__conn_is_new,
__conn_open_session,
+ __conn_query_timestamp,
+ __conn_set_timestamp,
__conn_load_extension,
__conn_add_data_source,
__conn_add_collator,
@@ -2320,6 +2404,7 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
session, cval.str, cval.len, &conn->error_prefix));
}
WT_ERR(__wt_verbose_config(session, cfg));
+ WT_ERR(__wt_timing_stress_config(session, cfg));
WT_ERR(__wt_config_gets(session, cfg, "session_max", &cval));
conn->session_size = (uint32_t)cval.val + WT_EXTRA_INTERNAL_SESSIONS;
diff --git a/src/third_party/wiredtiger/src/conn/conn_open.c b/src/third_party/wiredtiger/src/conn/conn_open.c
index ab7253c2828..d1d7d264d53 100644
--- a/src/third_party/wiredtiger/src/conn/conn_open.c
+++ b/src/third_party/wiredtiger/src/conn/conn_open.c
@@ -70,29 +70,13 @@ __wt_connection_close(WT_CONNECTION_IMPL *conn)
WT_DECL_RET;
WT_DLH *dlh;
WT_SESSION_IMPL *s, *session;
- WT_TXN_GLOBAL *txn_global;
u_int i;
wt_conn = &conn->iface;
- txn_global = &conn->txn_global;
session = conn->default_session;
- /*
- * We're shutting down. Make sure everything gets freed.
- *
- * It's possible that the eviction server is in the middle of a long
- * operation, with a transaction ID pinned. In that case, we will loop
- * here until the transaction ID is released, when the oldest
- * transaction ID will catch up with the current ID.
- */
- for (;;) {
- WT_TRET(__wt_txn_update_oldest(session,
- WT_TXN_OLDEST_STRICT | WT_TXN_OLDEST_WAIT));
- if (txn_global->oldest_id == txn_global->current &&
- txn_global->metadata_pinned == txn_global->current)
- break;
- __wt_yield();
- }
+ /* Shut down transactions (wait for in-flight operations to complete. */
+ WT_TRET(__wt_txn_global_shutdown(session));
/* Shut down the subsystems, ensuring workers see the state change. */
F_SET(conn, WT_CONN_CLOSING);
diff --git a/src/third_party/wiredtiger/src/conn/conn_sweep.c b/src/third_party/wiredtiger/src/conn/conn_sweep.c
index df60a3c784d..592d66b5294 100644
--- a/src/third_party/wiredtiger/src/conn/conn_sweep.c
+++ b/src/third_party/wiredtiger/src/conn/conn_sweep.c
@@ -84,8 +84,8 @@ __sweep_expire_one(WT_SESSION_IMPL *session)
WT_RET(__wt_try_writelock(session, &dhandle->rwlock));
/* Only sweep clean trees where all updates are visible. */
- if (btree->modified ||
- !__wt_txn_visible_all(session, btree->rec_max_txn))
+ if (btree->modified || !__wt_txn_visible_all(session,
+ btree->rec_max_txn, WT_TIMESTAMP(btree->rec_max_timestamp)))
goto err;
/*
diff --git a/src/third_party/wiredtiger/src/cursor/cur_join.c b/src/third_party/wiredtiger/src/cursor/cur_join.c
index e4ccb90139e..855ad70d6e0 100644
--- a/src/third_party/wiredtiger/src/cursor/cur_join.c
+++ b/src/third_party/wiredtiger/src/cursor/cur_join.c
@@ -1146,7 +1146,7 @@ __curjoin_open_main(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
const char *raw_cfg[] = { WT_CONFIG_BASE(
session, WT_SESSION_open_cursor), "raw", NULL };
- main_uri = NULL;
+ main_uri = newformat = NULL;
idx = entry->index;
newsize = strlen(cjoin->table->name) + idx->colconf.len + 1;
@@ -1169,9 +1169,11 @@ __curjoin_open_main(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin,
newformat, len, "%s0x", entry->main->value_format));
__wt_free(session, entry->main->value_format);
entry->main->value_format = newformat;
+ newformat = NULL;
}
err: __wt_free(session, main_uri);
+ __wt_free(session, newformat);
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/docs/top/main.dox b/src/third_party/wiredtiger/src/docs/top/main.dox
index 6b28bd0062f..1bfb623c0a0 100644
--- a/src/third_party/wiredtiger/src/docs/top/main.dox
+++ b/src/third_party/wiredtiger/src/docs/top/main.dox
@@ -6,12 +6,12 @@ WiredTiger is an high performance, scalable, production quality, NoSQL,
@section releases Releases
<table>
-@row{<b>WiredTiger 2.9.2</b> (current),
+@row{<b>WiredTiger 2.9.3</b> (current),
+ <a href="releases/wiredtiger-2.9.3.tar.bz2"><b>[Release package]</b></a>,
+ <a href="2.9.3/index.html"><b>[Documentation]</b></a>}
+@row{<b>WiredTiger 2.9.2</b> (previous),
<a href="releases/wiredtiger-2.9.2.tar.bz2"><b>[Release package]</b></a>,
<a href="2.9.2/index.html"><b>[Documentation]</b></a>}
-@row{<b>WiredTiger 2.8.0</b> (previous),
- <a href="releases/wiredtiger-2.8.0.tar.bz2"><b>[Release package]</b></a>,
- <a href="2.8.0/index.html"><b>[Documentation]</b></a>}
@row{<b>Development branch</b>,
<a href="https://github.com/wiredtiger/wiredtiger"><b>[Source code]</b></a>,
<a href="develop/index.html"><b>[Documentation]</b></a>}
diff --git a/src/third_party/wiredtiger/src/docs/transactions.dox b/src/third_party/wiredtiger/src/docs/transactions.dox
index 3b438eda366..8a05de9b5f5 100644
--- a/src/third_party/wiredtiger/src/docs/transactions.dox
+++ b/src/third_party/wiredtiger/src/docs/transactions.dox
@@ -148,4 +148,48 @@ WT_SESSION::snapshot with a configuration that includes
the semantics supported by the drop configuration.
Named snapshots are not durable: they do not survive WT_CONNECTION::close.
+
+@section transaction_timestamps Application-specified Transaction Timestamps
+
+Some applications have their own notion of time, including an expected commit
+order for transactions that may be inconsistent with the order assigned by
+WiredTiger. We assume that applications can represent their notion of a
+timestamp as an integral value of some size that generally increases over
+time. For example, a simple 64-bit integer could be incremented to generate
+transaction timestamps, if that is sufficient for the application.
+
+The application's timestamp size is specified as a number of bytes at build
+time, with <code>configure --with-timestamp-size=X</code>. The default
+timestamp size is 8 bytes (i.e., 64 bits). Setting a size of zero disables
+transaction timestamp functionality.
+
+Applications can assign explicit commit timestamps to transactions, then read
+"as of" a timestamp. Timestamps and are communicated to WiredTiger using a
+lower case hexadecimal encoding, so the encoded value can be twice as long as
+the raw timestamp value.
+
+Setting a read timestamp in WT_SESSION::begin_transaction forces a transaction
+to run at snapshot isolation and ignore any commits with a newer timestamp.
+
+Setting an oldest timestamp in WT_CONNECTION::set_timestamp indicates that
+future read timestamps will be at least as recent as the oldest timestamp, so
+WiredTiger can discard history before the specified point. It is critical
+that the oldest timestamp update frequently or the cache can become full of
+updates, reducing performance.
+
+Commit timestamps cannot be set in the past of any read timestamp that has
+been used. This is enforced by assertions in diagnostic builds, if
+applications violate this rule, data consistency can be violated.
+
+The commits to a particular data item must be performed in timestamp order.
+Again, this is only checked in diagnostic builds and if applications violate
+this rule, data consistency can be violated.
+
+@subsection Timestamp support in the extension API
+
+The extension API, used by modules that extend WiredTiger via
+WT_CONNECTION::get_extension_api, is not timestamp-aware. In particular,
+WT_EXTENSION_API::transaction_oldest and
+WT_EXTENSION_API::transaction_visible do not take timestamps into account.
+Extensions relying on these functions may not work correctly with timestamps.
*/
diff --git a/src/third_party/wiredtiger/src/evict/evict_lru.c b/src/third_party/wiredtiger/src/evict/evict_lru.c
index 46291eb63de..4f4ecdf286c 100644
--- a/src/third_party/wiredtiger/src/evict/evict_lru.c
+++ b/src/third_party/wiredtiger/src/evict/evict_lru.c
@@ -410,7 +410,7 @@ __evict_server(WT_SESSION_IMPL *session, bool *did_work)
} else if (cache->pages_evicted != cache->pages_evict) {
cache->pages_evicted = cache->pages_evict;
#if defined(HAVE_DIAGNOSTIC) || defined(HAVE_VERBOSE)
- __wt_epoch(session, &cache->stuck_ts);
+ __wt_epoch(session, &cache->stuck_time);
} else if (!F_ISSET(conn, WT_CONN_IN_MEMORY)) {
/*
* If we're stuck for 5 minutes in diagnostic mode, or the
@@ -425,7 +425,7 @@ __evict_server(WT_SESSION_IMPL *session, bool *did_work)
* servicing reads while the cache appears stuck to eviction.
*/
__wt_epoch(session, &now);
- if (WT_TIMEDIFF_SEC(now, cache->stuck_ts) > 300) {
+ if (WT_TIMEDIFF_SEC(now, cache->stuck_time) > 300) {
#if defined(HAVE_DIAGNOSTIC)
__wt_err(session, ETIMEDOUT,
"Cache stuck for too long, giving up");
@@ -439,7 +439,7 @@ __evict_server(WT_SESSION_IMPL *session, bool *did_work)
WT_RET(__wt_verbose_dump_cache(session));
/* Reset the timer. */
- __wt_epoch(session, &cache->stuck_ts);
+ __wt_epoch(session, &cache->stuck_time);
}
#endif
}
@@ -477,7 +477,7 @@ __wt_evict_create(WT_SESSION_IMPL *session)
/*
* Ensure the cache stuck timer is initialized when starting eviction.
*/
- __wt_epoch(session, &conn->cache->stuck_ts);
+ __wt_epoch(session, &conn->cache->stuck_time);
#endif
/*
@@ -1852,7 +1852,7 @@ __evict_walk_file(WT_SESSION_IMPL *session,
mod = page->modify;
if (modified && txn_global->current != txn_global->oldest_id &&
(mod->last_eviction_id == __wt_txn_oldest_id(session) ||
- !__wt_txn_visible_all(session, mod->update_txn)))
+ !__wt_txn_visible_all(session, mod->update_txn, NULL)))
continue;
fast: /* If the page can't be evicted, give up. */
diff --git a/src/third_party/wiredtiger/src/evict/evict_page.c b/src/third_party/wiredtiger/src/evict/evict_page.c
index d50326afb1e..a12590dedbc 100644
--- a/src/third_party/wiredtiger/src/evict/evict_page.c
+++ b/src/third_party/wiredtiger/src/evict/evict_page.c
@@ -596,7 +596,8 @@ __evict_review(
__wt_page_is_modified(page) ||
LF_ISSET(WT_EVICT_LOOKASIDE) ||
F_ISSET(S2BT(session), WT_BTREE_LOOKASIDE) ||
- __wt_txn_visible_all(session, page->modify->rec_max_txn));
+ __wt_txn_visible_all(session, page->modify->rec_max_txn,
+ WT_TIMESTAMP(page->modify->rec_max_timestamp)));
return (0);
}
diff --git a/src/third_party/wiredtiger/src/include/btmem.h b/src/third_party/wiredtiger/src/include/btmem.h
index 32839192a96..54a03e5762c 100644
--- a/src/third_party/wiredtiger/src/include/btmem.h
+++ b/src/third_party/wiredtiger/src/include/btmem.h
@@ -193,10 +193,11 @@ struct __wt_ovfl_txnc {
* are written into a lookaside table, and restored as necessary if the page is
* read. The key is a unique marker for the page (a file ID plus an address),
* a counter (used to ensure the update records remain in the original order),
- * the on-page item's transaction ID (so we can discard any update records from
- * the lookaside table once the on-page item's transaction is globally visible),
- * and the page key (byte-string for row-store, record number for column-store).
- * The value is the WT_UPDATE structure's transaction ID, update size and value.
+ * the on-page item's transaction ID and timestamp (so we can discard any
+ * update records from the lookaside table once the on-page item's transaction
+ * is globally visible), and the page key (byte-string for row-store, record
+ * number for column-store). The value is the WT_UPDATE structure's
+ * transaction ID, update size and value.
*
* As the key for the lookaside table is different for row- and column-store, we
* store both key types in a WT_ITEM, building/parsing them in the code, because
@@ -207,8 +208,8 @@ struct __wt_ovfl_txnc {
* the row-store key is relatively large.
*/
#define WT_LAS_FORMAT \
- "key_format=" WT_UNCHECKED_STRING(IuQQu) \
- ",value_format=" WT_UNCHECKED_STRING(QBu)
+ "key_format=" WT_UNCHECKED_STRING(IuQQuu) \
+ ",value_format=" WT_UNCHECKED_STRING(QuBu)
/*
* WT_PAGE_MODIFY --
@@ -229,8 +230,9 @@ struct __wt_page_modify {
/* Avoid checking for obsolete updates during checkpoints. */
uint64_t obsolete_check_txn;
- /* The largest transaction ID seen on the page by reconciliation. */
+ /* The largest transaction seen on the page by reconciliation. */
uint64_t rec_max_txn;
+ WT_DECL_TIMESTAMP(rec_max_timestamp)
/* The largest update transaction ID (approximate). */
uint64_t update_txn;
@@ -299,6 +301,7 @@ struct __wt_page_modify {
WT_INSERT *ins;
WT_ROW *rip;
uint64_t onpage_txn;
+ WT_DECL_TIMESTAMP(onpage_timestamp)
} *supd;
uint32_t supd_entries;
@@ -716,6 +719,7 @@ struct __wt_page {
*/
struct __wt_page_deleted {
uint64_t txnid; /* Transaction ID */
+ WT_DECL_TIMESTAMP(timestamp)
WT_UPDATE **update_list; /* List of updates for abort */
};
@@ -906,6 +910,7 @@ struct __wt_ikey {
*/
WT_PACKED_STRUCT_BEGIN(__wt_update)
uint64_t txnid; /* transaction */
+ WT_DECL_TIMESTAMP(timestamp)
WT_UPDATE *next; /* forward-linked list */
@@ -928,11 +933,12 @@ WT_PACKED_STRUCT_BEGIN(__wt_update)
#define WT_UPDATE_MEMSIZE(upd) \
WT_ALIGN(sizeof(WT_UPDATE) + (upd)->size, 32)
WT_PACKED_STRUCT_END
+
/*
* WT_UPDATE_SIZE is the expected structure size -- we verify the build to
* ensure the compiler hasn't inserted padding.
*/
-#define WT_UPDATE_SIZE 21
+#define WT_UPDATE_SIZE (21 + WT_TIMESTAMP_SIZE)
/*
* WT_INSERT --
diff --git a/src/third_party/wiredtiger/src/include/btree.h b/src/third_party/wiredtiger/src/include/btree.h
index 95af9e154f8..e0f7570b869 100644
--- a/src/third_party/wiredtiger/src/include/btree.h
+++ b/src/third_party/wiredtiger/src/include/btree.h
@@ -136,6 +136,8 @@ struct __wt_btree {
uint64_t write_gen; /* Write generation */
uint64_t rec_max_txn; /* Maximum txn seen (clean trees) */
+ WT_DECL_TIMESTAMP(rec_max_timestamp)
+
uint64_t checkpoint_gen; /* Checkpoint generation */
volatile enum {
WT_CKPT_OFF, WT_CKPT_PREPARE, WT_CKPT_RUNNING
diff --git a/src/third_party/wiredtiger/src/include/btree.i b/src/third_party/wiredtiger/src/include/btree.i
index d4db65b2033..305de509424 100644
--- a/src/third_party/wiredtiger/src/include/btree.i
+++ b/src/third_party/wiredtiger/src/include/btree.i
@@ -1341,7 +1341,8 @@ __wt_page_can_evict(
* If the page is clean but has modifications that appear too new to
* evict, skip it.
*/
- if (!modified && !__wt_txn_visible_all(session, mod->rec_max_txn))
+ if (!modified && !__wt_txn_visible_all(
+ session, mod->rec_max_txn, WT_TIMESTAMP(mod->rec_max_timestamp)))
return (false);
return (true);
diff --git a/src/third_party/wiredtiger/src/include/cache.h b/src/third_party/wiredtiger/src/include/cache.h
index a3fc17b9740..9b5057d0b61 100644
--- a/src/third_party/wiredtiger/src/include/cache.h
+++ b/src/third_party/wiredtiger/src/include/cache.h
@@ -89,7 +89,7 @@ struct __wt_cache {
uint64_t evict_max_page_size; /* Largest page seen at eviction */
#if defined(HAVE_DIAGNOSTIC) || defined(HAVE_VERBOSE)
- struct timespec stuck_ts; /* Stuck timestamp */
+ struct timespec stuck_time; /* Stuck time */
#endif
/*
diff --git a/src/third_party/wiredtiger/src/include/config.h b/src/third_party/wiredtiger/src/include/config.h
index 1f21693511b..8bd201eea18 100644
--- a/src/third_party/wiredtiger/src/include/config.h
+++ b/src/third_party/wiredtiger/src/include/config.h
@@ -58,44 +58,47 @@ struct __wt_config_parser_impl {
#define WT_CONFIG_ENTRY_WT_CONNECTION_close 6
#define WT_CONFIG_ENTRY_WT_CONNECTION_load_extension 7
#define WT_CONFIG_ENTRY_WT_CONNECTION_open_session 8
-#define WT_CONFIG_ENTRY_WT_CONNECTION_reconfigure 9
-#define WT_CONFIG_ENTRY_WT_CONNECTION_set_file_system 10
-#define WT_CONFIG_ENTRY_WT_CURSOR_close 11
-#define WT_CONFIG_ENTRY_WT_CURSOR_reconfigure 12
-#define WT_CONFIG_ENTRY_WT_SESSION_alter 13
-#define WT_CONFIG_ENTRY_WT_SESSION_begin_transaction 14
-#define WT_CONFIG_ENTRY_WT_SESSION_checkpoint 15
-#define WT_CONFIG_ENTRY_WT_SESSION_close 16
-#define WT_CONFIG_ENTRY_WT_SESSION_commit_transaction 17
-#define WT_CONFIG_ENTRY_WT_SESSION_compact 18
-#define WT_CONFIG_ENTRY_WT_SESSION_create 19
-#define WT_CONFIG_ENTRY_WT_SESSION_drop 20
-#define WT_CONFIG_ENTRY_WT_SESSION_join 21
-#define WT_CONFIG_ENTRY_WT_SESSION_log_flush 22
-#define WT_CONFIG_ENTRY_WT_SESSION_log_printf 23
-#define WT_CONFIG_ENTRY_WT_SESSION_open_cursor 24
-#define WT_CONFIG_ENTRY_WT_SESSION_rebalance 25
-#define WT_CONFIG_ENTRY_WT_SESSION_reconfigure 26
-#define WT_CONFIG_ENTRY_WT_SESSION_rename 27
-#define WT_CONFIG_ENTRY_WT_SESSION_reset 28
-#define WT_CONFIG_ENTRY_WT_SESSION_rollback_transaction 29
-#define WT_CONFIG_ENTRY_WT_SESSION_salvage 30
-#define WT_CONFIG_ENTRY_WT_SESSION_snapshot 31
-#define WT_CONFIG_ENTRY_WT_SESSION_strerror 32
-#define WT_CONFIG_ENTRY_WT_SESSION_transaction_sync 33
-#define WT_CONFIG_ENTRY_WT_SESSION_truncate 34
-#define WT_CONFIG_ENTRY_WT_SESSION_upgrade 35
-#define WT_CONFIG_ENTRY_WT_SESSION_verify 36
-#define WT_CONFIG_ENTRY_colgroup_meta 37
-#define WT_CONFIG_ENTRY_file_config 38
-#define WT_CONFIG_ENTRY_file_meta 39
-#define WT_CONFIG_ENTRY_index_meta 40
-#define WT_CONFIG_ENTRY_lsm_meta 41
-#define WT_CONFIG_ENTRY_table_meta 42
-#define WT_CONFIG_ENTRY_wiredtiger_open 43
-#define WT_CONFIG_ENTRY_wiredtiger_open_all 44
-#define WT_CONFIG_ENTRY_wiredtiger_open_basecfg 45
-#define WT_CONFIG_ENTRY_wiredtiger_open_usercfg 46
+#define WT_CONFIG_ENTRY_WT_CONNECTION_query_timestamp 9
+#define WT_CONFIG_ENTRY_WT_CONNECTION_reconfigure 10
+#define WT_CONFIG_ENTRY_WT_CONNECTION_set_file_system 11
+#define WT_CONFIG_ENTRY_WT_CONNECTION_set_timestamp 12
+#define WT_CONFIG_ENTRY_WT_CURSOR_close 13
+#define WT_CONFIG_ENTRY_WT_CURSOR_reconfigure 14
+#define WT_CONFIG_ENTRY_WT_SESSION_alter 15
+#define WT_CONFIG_ENTRY_WT_SESSION_begin_transaction 16
+#define WT_CONFIG_ENTRY_WT_SESSION_checkpoint 17
+#define WT_CONFIG_ENTRY_WT_SESSION_close 18
+#define WT_CONFIG_ENTRY_WT_SESSION_commit_transaction 19
+#define WT_CONFIG_ENTRY_WT_SESSION_compact 20
+#define WT_CONFIG_ENTRY_WT_SESSION_create 21
+#define WT_CONFIG_ENTRY_WT_SESSION_drop 22
+#define WT_CONFIG_ENTRY_WT_SESSION_join 23
+#define WT_CONFIG_ENTRY_WT_SESSION_log_flush 24
+#define WT_CONFIG_ENTRY_WT_SESSION_log_printf 25
+#define WT_CONFIG_ENTRY_WT_SESSION_open_cursor 26
+#define WT_CONFIG_ENTRY_WT_SESSION_rebalance 27
+#define WT_CONFIG_ENTRY_WT_SESSION_reconfigure 28
+#define WT_CONFIG_ENTRY_WT_SESSION_rename 29
+#define WT_CONFIG_ENTRY_WT_SESSION_reset 30
+#define WT_CONFIG_ENTRY_WT_SESSION_rollback_transaction 31
+#define WT_CONFIG_ENTRY_WT_SESSION_salvage 32
+#define WT_CONFIG_ENTRY_WT_SESSION_snapshot 33
+#define WT_CONFIG_ENTRY_WT_SESSION_strerror 34
+#define WT_CONFIG_ENTRY_WT_SESSION_timestamp_transaction 35
+#define WT_CONFIG_ENTRY_WT_SESSION_transaction_sync 36
+#define WT_CONFIG_ENTRY_WT_SESSION_truncate 37
+#define WT_CONFIG_ENTRY_WT_SESSION_upgrade 38
+#define WT_CONFIG_ENTRY_WT_SESSION_verify 39
+#define WT_CONFIG_ENTRY_colgroup_meta 40
+#define WT_CONFIG_ENTRY_file_config 41
+#define WT_CONFIG_ENTRY_file_meta 42
+#define WT_CONFIG_ENTRY_index_meta 43
+#define WT_CONFIG_ENTRY_lsm_meta 44
+#define WT_CONFIG_ENTRY_table_meta 45
+#define WT_CONFIG_ENTRY_wiredtiger_open 46
+#define WT_CONFIG_ENTRY_wiredtiger_open_all 47
+#define WT_CONFIG_ENTRY_wiredtiger_open_basecfg 48
+#define WT_CONFIG_ENTRY_wiredtiger_open_usercfg 49
/*
* configuration section: END
* DO NOT EDIT: automatically built by dist/flags.py.
diff --git a/src/third_party/wiredtiger/src/include/connection.h b/src/third_party/wiredtiger/src/include/connection.h
index 56d801cd361..94abe48ffe5 100644
--- a/src/third_party/wiredtiger/src/include/connection.h
+++ b/src/third_party/wiredtiger/src/include/connection.h
@@ -410,6 +410,12 @@ struct __wt_connection_impl {
int page_size; /* OS page size for mmap alignment */
uint32_t verbose;
+ /*
+ * Variable with flags for which subsystems the diagnostic stress timing
+ * delays have been requested.
+ */
+ uint32_t timing_stress_flags;
+
#define WT_STDERR(s) (&S2C(s)->wt_stderr)
#define WT_STDOUT(s) (&S2C(s)->wt_stdout)
WT_FSTREAM wt_stderr, wt_stdout;
diff --git a/src/third_party/wiredtiger/src/include/extern.h b/src/third_party/wiredtiger/src/include/extern.h
index f055e4810b3..59e853d75f4 100644
--- a/src/third_party/wiredtiger/src/include/extern.h
+++ b/src/third_party/wiredtiger/src/include/extern.h
@@ -244,6 +244,7 @@ extern int __wt_conn_remove_encryptor(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL
extern int __wt_extractor_config(WT_SESSION_IMPL *session, const char *uri, const char *config, WT_EXTRACTOR **extractorp, int *ownp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_conn_remove_extractor(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_verbose_config(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_timing_stress_config(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_cache_config(WT_SESSION_IMPL *session, bool reconfigure, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_cache_create(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_cache_stats_update(WT_SESSION_IMPL *session);
@@ -748,6 +749,7 @@ extern void __wt_txn_release_snapshot(WT_SESSION_IMPL *session);
extern void __wt_txn_get_snapshot(WT_SESSION_IMPL *session);
extern int __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_txn_config(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_reconfigure(WT_SESSION_IMPL *session, const char *config) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_txn_release(WT_SESSION_IMPL *session);
extern int __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_txn_rollback(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -756,6 +758,7 @@ extern void __wt_txn_stats_update(WT_SESSION_IMPL *session);
extern void __wt_txn_destroy(WT_SESSION_IMPL *session);
extern int __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_txn_global_destroy(WT_SESSION_IMPL *session);
+extern int __wt_txn_global_shutdown(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_verbose_dump_txn(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_checkpoint_get_handles(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[], bool waiting) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -781,3 +784,8 @@ extern int __wt_txn_named_snapshot_get(WT_SESSION_IMPL *session, WT_CONFIG_ITEM
extern int __wt_txn_named_snapshot_config(WT_SESSION_IMPL *session, const char *cfg[], bool *has_create, bool *has_drops) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_txn_named_snapshot_destroy(WT_SESSION_IMPL *session);
extern int __wt_txn_recover(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_parse_timestamp(WT_SESSION_IMPL *session, const char *name, uint8_t *timestamp, WT_CONFIG_ITEM *cval) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_global_query_timestamp( WT_SESSION_IMPL *session, char *hex_timestamp, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_update_pinned_timestamp(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_global_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
diff --git a/src/third_party/wiredtiger/src/include/flags.h b/src/third_party/wiredtiger/src/include/flags.h
index 919c0dd2f98..ef66a186fa4 100644
--- a/src/third_party/wiredtiger/src/include/flags.h
+++ b/src/third_party/wiredtiger/src/include/flags.h
@@ -78,6 +78,7 @@
#define WT_STAT_TYPE_FAST 0x00000020
#define WT_STAT_TYPE_SIZE 0x00000040
#define WT_STAT_TYPE_TREE_WALK 0x00000080
+#define WT_TIMING_STRESS_CHECKPOINT_SLOW 0x00000001
#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/third_party/wiredtiger/src/include/lsm.h b/src/third_party/wiredtiger/src/include/lsm.h
index f8d0f480cbb..df7d6c8d5ca 100644
--- a/src/third_party/wiredtiger/src/include/lsm.h
+++ b/src/third_party/wiredtiger/src/include/lsm.h
@@ -86,7 +86,7 @@ struct __wt_cursor_lsm {
struct __wt_lsm_chunk {
const char *uri; /* Data source for this chunk */
const char *bloom_uri; /* URI of Bloom filter, if any */
- struct timespec create_ts; /* Creation time (for rate limiting) */
+ struct timespec create_time; /* Creation time (for rate limiting) */
uint64_t count; /* Approximate count of records */
uint64_t size; /* Final chunk size */
@@ -203,10 +203,10 @@ struct __wt_lsm_tree {
uint64_t ckpt_throttle; /* Rate limiting due to checkpoints */
uint64_t merge_throttle; /* Rate limiting due to merges */
uint64_t chunk_fill_ms; /* Estimate of time to fill a chunk */
- struct timespec last_flush_ts; /* Timestamp last flush finished */
+ struct timespec last_flush_time;/* Time last flush finished */
uint64_t chunks_flushed; /* Count of chunks flushed since open */
- struct timespec merge_aggressive_ts;/* Timestamp for merge aggression */
- struct timespec work_push_ts; /* Timestamp last work unit added */
+ struct timespec merge_aggressive_time;/* Time for merge aggression */
+ struct timespec work_push_time; /* Time last work unit added */
uint64_t merge_progressing; /* Bumped when merges are active */
uint32_t merge_syncing; /* Bumped when merges are syncing */
diff --git a/src/third_party/wiredtiger/src/include/misc.h b/src/third_party/wiredtiger/src/include/misc.h
index c84368b235c..838086c2ced 100644
--- a/src/third_party/wiredtiger/src/include/misc.h
+++ b/src/third_party/wiredtiger/src/include/misc.h
@@ -249,6 +249,24 @@
(dst).size = (src).size; \
} while (0)
+/* Timestamp type and helper macros. */
+#if WT_TIMESTAMP_SIZE > 0
+#define HAVE_TIMESTAMPS 1
+#else
+#undef HAVE_TIMESTAMPS
+#endif
+
+#ifdef HAVE_TIMESTAMPS
+#define WT_TIMESTAMP(x) (x)
+typedef uint8_t wt_timestamp_t[WT_TIMESTAMP_SIZE];
+#define WT_DECL_TIMESTAMP(x) wt_timestamp_t x;
+#else
+#define WT_TIMESTAMP(x) (NULL)
+#define WT_DECL_TIMESTAMP(x)
+#endif
+
+#define WT_GET_TIMESTAMP(x) WT_TIMESTAMP((x)->timestamp)
+
/*
* In diagnostic mode we track the locations from which hazard pointers and
* scratch buffers were acquired.
diff --git a/src/third_party/wiredtiger/src/include/serial.i b/src/third_party/wiredtiger/src/include/serial.i
index bd0e498f621..15d159192f9 100644
--- a/src/third_party/wiredtiger/src/include/serial.i
+++ b/src/third_party/wiredtiger/src/include/serial.i
@@ -312,11 +312,11 @@ __wt_update_serial(WT_SESSION_IMPL *session, WT_PAGE *page,
* is used as an indicator of there being further updates on this page.
*/
if ((txn = page->modify->obsolete_check_txn) != WT_TXN_NONE) {
- if (!__wt_txn_visible_all(session, txn)) {
+ if (!__wt_txn_visible_all(session, txn, NULL)) {
/* Try to move the oldest ID forward and re-check. */
WT_RET(__wt_txn_update_oldest(session, 0));
- if (!__wt_txn_visible_all(session, txn))
+ if (!__wt_txn_visible_all(session, txn, NULL))
return (0);
}
diff --git a/src/third_party/wiredtiger/src/include/session.h b/src/third_party/wiredtiger/src/include/session.h
index dfd84675721..cb84bd7c363 100644
--- a/src/third_party/wiredtiger/src/include/session.h
+++ b/src/third_party/wiredtiger/src/include/session.h
@@ -122,6 +122,7 @@ struct __wt_session_impl {
WT_TXN_ISOLATION isolation;
WT_TXN txn; /* Transaction state */
+#define WT_SESSION_BG_SYNC_MSEC 1200000
WT_LSN bg_sync_lsn; /* Background sync operation LSN. */
u_int ncursors; /* Count of active file cursors. */
diff --git a/src/third_party/wiredtiger/src/include/txn.h b/src/third_party/wiredtiger/src/include/txn.h
index c1f19ada959..bf2d9aa21ef 100644
--- a/src/third_party/wiredtiger/src/include/txn.h
+++ b/src/third_party/wiredtiger/src/include/txn.h
@@ -69,14 +69,18 @@ struct __wt_named_snapshot {
struct __wt_txn_state {
WT_CACHE_LINE_PAD_BEGIN
+ WT_RWLOCK rwlock;
volatile uint64_t id;
volatile uint64_t pinned_id;
volatile uint64_t metadata_pinned;
+
+ WT_DECL_TIMESTAMP(commit_timestamp)
+ WT_DECL_TIMESTAMP(read_timestamp)
+
WT_CACHE_LINE_PAD_END
};
struct __wt_txn_global {
- WT_SPINLOCK id_lock;
volatile uint64_t current; /* Current transaction ID. */
/* The oldest running transaction ID (may race). */
@@ -88,11 +92,16 @@ struct __wt_txn_global {
*/
volatile uint64_t oldest_id;
- /*
- * Prevents the oldest ID moving forwards while threads are scanning
- * the global transaction state.
- */
- WT_RWLOCK scan_rwlock;
+ WT_DECL_TIMESTAMP(commit_timestamp)
+ WT_DECL_TIMESTAMP(oldest_timestamp)
+ WT_DECL_TIMESTAMP(pinned_timestamp)
+ bool has_commit_timestamp, has_oldest_timestamp, has_pinned_timestamp;
+ bool oldest_is_pinned;
+
+ WT_SPINLOCK id_lock;
+
+ /* Protects the active transaction states. */
+ WT_RWLOCK rwlock;
/*
* Track information about the running checkpoint. The transaction
@@ -107,8 +116,7 @@ struct __wt_txn_global {
*/
volatile bool checkpoint_running; /* Checkpoint running */
volatile uint32_t checkpoint_id; /* Checkpoint's session ID */
- volatile uint64_t checkpoint_pinned; /* Oldest ID for checkpoint */
- volatile uint64_t checkpoint_txnid; /* Checkpoint's txn ID */
+ WT_TXN_STATE checkpoint_state; /* Checkpoint's txn state */
volatile uint64_t metadata_pinned; /* Oldest ID for metadata */
@@ -136,6 +144,7 @@ struct __wt_txn_op {
uint32_t fileid;
enum {
WT_TXN_OP_BASIC,
+ WT_TXN_OP_BASIC_TS,
WT_TXN_OP_INMEM,
WT_TXN_OP_REF,
WT_TXN_OP_TRUNCATE_COL,
@@ -185,6 +194,9 @@ struct __wt_txn {
uint32_t snapshot_count;
uint32_t txn_logsync; /* Log sync configuration */
+ WT_DECL_TIMESTAMP(read_timestamp)
+ WT_DECL_TIMESTAMP(commit_timestamp)
+
/* Array of modifications by this transaction. */
WT_TXN_OP *mod;
size_t mod_alloc;
@@ -202,13 +214,15 @@ struct __wt_txn {
WT_ITEM *ckpt_snapshot;
bool full_ckpt;
-#define WT_TXN_AUTOCOMMIT 0x01
-#define WT_TXN_ERROR 0x02
-#define WT_TXN_HAS_ID 0x04
-#define WT_TXN_HAS_SNAPSHOT 0x08
-#define WT_TXN_NAMED_SNAPSHOT 0x10
-#define WT_TXN_READONLY 0x20
-#define WT_TXN_RUNNING 0x40
-#define WT_TXN_SYNC_SET 0x80
+#define WT_TXN_AUTOCOMMIT 0x001
+#define WT_TXN_ERROR 0x002
+#define WT_TXN_HAS_ID 0x004
+#define WT_TXN_HAS_SNAPSHOT 0x008
+#define WT_TXN_HAS_TS_COMMIT 0x010
+#define WT_TXN_HAS_TS_READ 0x020
+#define WT_TXN_NAMED_SNAPSHOT 0x040
+#define WT_TXN_READONLY 0x080
+#define WT_TXN_RUNNING 0x100
+#define WT_TXN_SYNC_SET 0x200
uint32_t flags;
};
diff --git a/src/third_party/wiredtiger/src/include/txn.i b/src/third_party/wiredtiger/src/include/txn.i
index f4f571cb67e..85d70fbde89 100644
--- a/src/third_party/wiredtiger/src/include/txn.i
+++ b/src/third_party/wiredtiger/src/include/txn.i
@@ -9,6 +9,40 @@
static inline int __wt_txn_id_check(WT_SESSION_IMPL *session);
static inline void __wt_txn_read_last(WT_SESSION_IMPL *session);
+#ifdef HAVE_TIMESTAMPS
+static const wt_timestamp_t zero_timestamp;
+
+/*
+ * __wt_timestamp_cmp --
+ * Compare two timestamps.
+ */
+static inline int
+__wt_timestamp_cmp(const uint8_t *ts1, const uint8_t *ts2)
+{
+ return (memcmp(ts1, ts2, WT_TIMESTAMP_SIZE));
+}
+
+/*
+ * __wt_timestamp_set --
+ * Set a timestamp.
+ */
+static inline void
+__wt_timestamp_set(uint8_t *dest, const uint8_t *src)
+{
+ (void)memcpy(dest, src, WT_TIMESTAMP_SIZE);
+}
+
+/*
+ * __wt_timestamp_iszero --
+ * Check if a timestamp is equal to the special "zero" time.
+ */
+static inline bool
+__wt_timestamp_iszero(const uint8_t *ts)
+{
+ return (memcmp(ts, zero_timestamp, WT_TIMESTAMP_SIZE) == 0);
+}
+#endif
+
/*
* __txn_next_op --
* Mark a WT_UPDATE object modified by the current transaction.
@@ -74,6 +108,13 @@ __wt_txn_modify(WT_SESSION_IMPL *session, WT_UPDATE *upd)
WT_RET(__txn_next_op(session, &op));
op->type = F_ISSET(session, WT_SESSION_LOGGING_INMEM) ?
WT_TXN_OP_INMEM : WT_TXN_OP_BASIC;
+#ifdef HAVE_TIMESTAMPS
+ if (F_ISSET(txn, WT_TXN_HAS_TS_COMMIT)) {
+ __wt_timestamp_set(upd->timestamp, txn->commit_timestamp);
+ if (!F_ISSET(session, WT_SESSION_LOGGING_INMEM))
+ op->type = WT_TXN_OP_BASIC_TS;
+ }
+#endif
op->u.upd = upd;
upd->txnid = session->txn.id;
return (0);
@@ -119,16 +160,21 @@ __wt_txn_oldest_id(WT_SESSION_IMPL *session)
/*
* Take a local copy of these IDs in case they are updated while we are
- * checking visibility. The read of the transaction ID pinned by a
- * checkpoint needs to be carefully ordered: if a checkpoint is
- * starting and we have to start checking the pinned ID, we take the
- * minimum of it with the oldest ID, which is what we want.
+ * checking visibility.
*/
oldest_id = txn_global->oldest_id;
include_checkpoint_txn = btree == NULL ||
btree->checkpoint_gen != __wt_gen(session, WT_GEN_CHECKPOINT);
+ if (!include_checkpoint_txn)
+ return (oldest_id);
+
+ /*
+ * The read of the transaction ID pinned by a checkpoint needs to be
+ * carefully ordered: if a checkpoint is starting and we have to start
+ * checking the pinned ID, we take the minimum of it with the oldest
+ * ID, which is what we want.
+ */
WT_READ_BARRIER();
- checkpoint_pinned = txn_global->checkpoint_pinned;
/*
* Checkpoint transactions often fall behind ordinary application
@@ -140,7 +186,8 @@ __wt_txn_oldest_id(WT_SESSION_IMPL *session)
* the active checkpoint then it's safe to ignore the checkpoint ID in
* the visibility check.
*/
- if (!include_checkpoint_txn || checkpoint_pinned == WT_TXN_NONE ||
+ checkpoint_pinned = txn_global->checkpoint_state.pinned_id;
+ if (checkpoint_pinned == WT_TXN_NONE ||
WT_TXNID_LT(oldest_id, checkpoint_pinned))
return (oldest_id);
@@ -158,13 +205,13 @@ __wt_txn_committed(WT_SESSION_IMPL *session, uint64_t id)
}
/*
- * __wt_txn_visible_all --
+ * __txn_visible_all_id --
* Check if a given transaction ID is "globally visible". This is, if
* all sessions in the system will see the transaction ID including the
* ID that belongs to a running checkpoint.
*/
static inline bool
-__wt_txn_visible_all(WT_SESSION_IMPL *session, uint64_t id)
+__txn_visible_all_id(WT_SESSION_IMPL *session, uint64_t id)
{
uint64_t oldest_id;
@@ -174,11 +221,63 @@ __wt_txn_visible_all(WT_SESSION_IMPL *session, uint64_t id)
}
/*
- * __wt_txn_visible --
+ * __wt_txn_visible_all --
+ * Check if a given transaction is "globally visible". This is, if
+ * all sessions in the system will see the transaction ID including the
+ * ID that belongs to a running checkpoint.
+ */
+static inline bool
+__wt_txn_visible_all(
+ WT_SESSION_IMPL *session, uint64_t id, const uint8_t *timestamp)
+{
+ if (!__txn_visible_all_id(session, id))
+ return (false);
+
+#ifdef HAVE_TIMESTAMPS
+ {
+ WT_TXN_GLOBAL *txn_global = &S2C(session)->txn_global;
+ int cmp;
+
+ /* Timestamp check. */
+ if (!txn_global->has_pinned_timestamp || timestamp == NULL)
+ return (true);
+
+ __wt_readlock(session, &txn_global->rwlock);
+ cmp = __wt_timestamp_cmp(timestamp, txn_global->pinned_timestamp);
+ __wt_readunlock(session, &txn_global->rwlock);
+
+ /*
+ * We can discard updates with timestamps less than or equal to the
+ * pinned timestamp. This is different to the situation for
+ * transaction IDs, because we know that updates with timestamps are
+ * definitely committed (and in this case, that the transaction ID is
+ * globally visible).
+ */
+ return (cmp <= 0);
+ }
+#else
+ WT_UNUSED(timestamp);
+ return (true);
+#endif
+}
+
+/*
+ * __wt_txn_upd_visible_all --
+ * Is the given update visible to all (possible) readers?
+ */
+static inline bool
+__wt_txn_upd_visible_all(WT_SESSION_IMPL *session, WT_UPDATE *upd)
+{
+ return (__wt_txn_visible_all(
+ session, upd->txnid, WT_GET_TIMESTAMP(upd)));
+}
+
+/*
+ * __txn_visible_id --
* Can the current transaction see the given ID?
*/
static inline bool
-__wt_txn_visible(WT_SESSION_IMPL *session, uint64_t id)
+__txn_visible_id(WT_SESSION_IMPL *session, uint64_t id)
{
WT_TXN *txn;
bool found;
@@ -202,7 +301,7 @@ __wt_txn_visible(WT_SESSION_IMPL *session, uint64_t id)
* visible.
*/
if (!F_ISSET(txn, WT_TXN_HAS_SNAPSHOT))
- return (__wt_txn_visible_all(session, id));
+ return (__txn_visible_all_id(session, id));
/* Transactions see their own changes. */
if (id == txn->id)
@@ -227,6 +326,43 @@ __wt_txn_visible(WT_SESSION_IMPL *session, uint64_t id)
}
/*
+ * __wt_txn_visible --
+ * Can the current transaction see the given ID / timestamp?
+ */
+static inline bool
+__wt_txn_visible(
+ WT_SESSION_IMPL *session, uint64_t id, const uint8_t *timestamp)
+{
+ if (!__txn_visible_id(session, id))
+ return (false);
+
+#ifdef HAVE_TIMESTAMPS
+ {
+ WT_TXN *txn = &session->txn;
+
+ /* Timestamp check. */
+ if (!F_ISSET(txn, WT_TXN_HAS_TS_READ) || timestamp == NULL)
+ return (true);
+
+ return (memcmp(timestamp, txn->read_timestamp, WT_TIMESTAMP_SIZE) <= 0);
+ }
+#else
+ WT_UNUSED(timestamp);
+ return (true);
+#endif
+}
+
+/*
+ * __wt_txn_upd_visible --
+ * Can the current transaction see the given update.
+ */
+static inline bool
+__wt_txn_upd_visible(WT_SESSION_IMPL *session, WT_UPDATE *upd)
+{
+ return (__wt_txn_visible(session, upd->txnid, WT_GET_TIMESTAMP(upd)));
+}
+
+/*
* __wt_txn_read --
* Get the first visible update in a list (or NULL if none are visible).
*/
@@ -236,7 +372,7 @@ __wt_txn_read(WT_SESSION_IMPL *session, WT_UPDATE *upd)
/* Skip reserved place-holders, they're never visible. */
for (; upd != NULL; upd = upd->next)
if (upd->type != WT_UPDATE_RESERVED &&
- __wt_txn_visible(session, upd->txnid))
+ __wt_txn_upd_visible(session, upd))
break;
return (upd);
@@ -333,9 +469,11 @@ static inline uint64_t
__wt_txn_id_alloc(WT_SESSION_IMPL *session, bool publish)
{
WT_TXN_GLOBAL *txn_global;
+ WT_TXN_STATE *txn_state;
uint64_t id;
txn_global = &S2C(session)->txn_global;
+ txn_state = WT_SESSION_TXN_STATE(session);
/*
* Allocating transaction IDs involves several steps.
@@ -349,23 +487,22 @@ __wt_txn_id_alloc(WT_SESSION_IMPL *session, bool publish)
* reader could get a snapshot that makes our changes visible before we
* commit.
*
- * Lastly, we spin to update the current ID. This is the only place
- * that the current ID is updated, and it is in the same cache line as
- * the field we allocate from, so we should usually succeed on the
- * first try.
- *
* We want the global value to lead the allocated values, so that any
* allocated transaction ID eventually becomes globally visible. When
* there are no transactions running, the oldest_id will reach the
* global current ID, so we want post-increment semantics. Our atomic
* add primitive does pre-increment, so adjust the result here.
+ *
+ * We rely on atomic reads of the current ID to create snapshots, so
+ * for unlocked reads to be well defined, we must use an atomic
+ * increment here.
*/
- __wt_spin_lock(session, &txn_global->id_lock);
+ __wt_spin_lock(session, &txn_global->id_lock);
id = txn_global->current;
if (publish) {
session->txn.id = id;
- WT_PUBLISH(WT_SESSION_TXN_STATE(session)->id, id);
+ WT_PUBLISH(txn_state->id, id);
}
/*
@@ -422,7 +559,7 @@ __wt_txn_update_check(WT_SESSION_IMPL *session, WT_UPDATE *upd)
txn = &session->txn;
if (txn->isolation == WT_ISO_SNAPSHOT)
- while (upd != NULL && !__wt_txn_visible(session, upd->txnid)) {
+ while (upd != NULL && !__wt_txn_upd_visible(session, upd)) {
if (upd->txnid != WT_TXN_ABORTED) {
WT_STAT_CONN_INCR(
session, txn_update_conflict);
diff --git a/src/third_party/wiredtiger/src/include/wiredtiger.in b/src/third_party/wiredtiger/src/include/wiredtiger.in
index cf7117376af..60bacbcf51d 100644
--- a/src/third_party/wiredtiger/src/include/wiredtiger.in
+++ b/src/third_party/wiredtiger/src/include/wiredtiger.in
@@ -1676,6 +1676,8 @@ struct __wt_session {
* @config{priority, priority of the transaction for resolving
* conflicts. Transactions with higher values are less likely to
* abort., an integer between -100 and 100; default \c 0.}
+ * @config{read_timestamp, read using the specified timestamp\, see @ref
+ * transaction_timestamps., a string; default empty.}
* @config{snapshot, use a named\, in-memory snapshot\, see @ref
* transaction_named_snapshots., a string; default empty.}
* @config{sync, whether to sync log records when the transaction
@@ -1698,6 +1700,9 @@ struct __wt_session {
*
* @param session the session handle
* @configstart{WT_SESSION.commit_transaction, see dist/api_data.py}
+ * @config{commit_timestamp, set the commit timestamp for the current
+ * transaction\, see @ref transaction_timestamps., a string; default
+ * empty.}
* @config{sync, override whether to sync log records when the
* transaction commits\, inherited from ::wiredtiger_open \c
* transaction_sync. The \c background setting initiates a background
@@ -1728,6 +1733,21 @@ struct __wt_session {
int __F(rollback_transaction)(WT_SESSION *session, const char *config);
/*!
+ * Set a timestamp on a transaction.
+ *
+ * @snippet ex_all.c transaction timestamp
+ *
+ * @param session the session handle
+ * @configstart{WT_SESSION.timestamp_transaction, see dist/api_data.py}
+ * @config{commit_timestamp, set the commit timestamp for the current
+ * transaction\, see @ref transaction_timestamps., a string; default
+ * empty.}
+ * @configend
+ * @errors
+ */
+ int __F(timestamp_transaction)(WT_SESSION *session, const char *config);
+
+ /*!
* Write a transactionally consistent snapshot of a database or set of
* objects. The checkpoint includes all transactions committed before
* the checkpoint starts. Additionally, checkpoints may optionally be
@@ -2173,6 +2193,51 @@ struct __wt_connection {
/*! @} */
/*!
+ * @name Transactions
+ * @{
+ */
+ /*!
+ * Query the global transaction timestamp state.
+ *
+ * @snippet ex_all.c query timestamp
+ *
+ * @param connection the connection handle
+ * @param[out] hex_timestamp a buffer that will be set to the
+ * hexadecimal encoding of the timestamp being queried. Must be large
+ * enough to hold a hex-encoded timestamp (i.e., double the timestamp
+ * size plus one byte for NUL termination).
+ * @configstart{WT_CONNECTION.query_timestamp, see dist/api_data.py}
+ * @config{get, specify which timestamp to query: \c all_committed
+ * returns the largest timestamp such that all earlier timestamps have
+ * committed. See @ref transaction_timestamps., a string\, chosen from
+ * the following options: \c "all_committed"; default \c all_committed.}
+ * @configend
+ * @errors
+ * If there is no matching timestamp (e.g., if this method is called
+ * before timestamps are used) ::WT_NOTFOUND will be returned.
+ */
+ int __F(query_timestamp)(
+ WT_CONNECTION *connection, char *hex_timestamp, const char *config);
+
+ /*!
+ * Set a global transaction timestamp.
+ *
+ * @snippet ex_all.c set oldest timestamp
+ *
+ * @param connection the connection handle
+ * @configstart{WT_CONNECTION.set_timestamp, see dist/api_data.py}
+ * @config{oldest_timestamp, future commits and queries will be no
+ * earlier than the specified timestamp. Supplied values must be
+ * monotonically increasing. see @ref transaction_timestamps., a
+ * string; default empty.}
+ * @configend
+ * @errors
+ */
+ int __F(set_timestamp)(
+ WT_CONNECTION *connection, const char *config);
+ /*! @} */
+
+ /*!
* @name Extensions
* @{
*/
@@ -3110,9 +3175,6 @@ struct __wt_config_parser {
/*!
* Return the next key/value pair.
*
- * When iteration would pass the end of the configuration string
- * ::WT_NOTFOUND will be returned.
- *
* If an item has no explicitly assigned value, the item will be
* returned in \c key and the \c value will be set to the boolean
* \c "true" value.
@@ -3121,7 +3183,8 @@ struct __wt_config_parser {
* @param key the returned key
* @param value the returned value
* @errors
- *
+ * When iteration would pass the end of the configuration string
+ * ::WT_NOTFOUND will be returned.
*/
int __F(next)(WT_CONFIG_PARSER *config_parser,
WT_CONFIG_ITEM *key, WT_CONFIG_ITEM *value);
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_cursor.c b/src/third_party/wiredtiger/src/lsm/lsm_cursor.c
index 1d15ed793a2..06dfec725bb 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_cursor.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_cursor.c
@@ -240,7 +240,7 @@ __clsm_enter(WT_CURSOR_LSM *clsm, bool reset, bool update)
break;
WT_ASSERT(session,
!__wt_txn_visible_all(
- session, switch_txn));
+ session, switch_txn, NULL));
}
}
}
@@ -539,7 +539,7 @@ retry: if (F_ISSET(clsm, WT_CLSM_MERGE)) {
clsm->chunks[ngood - 1]->switch_txn =
chunk->switch_txn;
if (__wt_txn_visible_all(
- session, chunk->switch_txn))
+ session, chunk->switch_txn, NULL))
break;
}
} else {
@@ -1466,8 +1466,8 @@ __clsm_put(WT_SESSION_IMPL *session, WT_CURSOR_LSM *clsm,
for (i = 0, slot = clsm->nchunks - 1; i < clsm->nupdates; i++, slot--) {
/* Check if we need to keep updating old chunks. */
- if (i > 0 &&
- __wt_txn_visible(session, clsm->chunks[slot]->switch_txn)) {
+ if (i > 0 && __wt_txn_visible(
+ session, clsm->chunks[slot]->switch_txn, NULL)) {
clsm->nupdates = i;
break;
}
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_manager.c b/src/third_party/wiredtiger/src/lsm/lsm_manager.c
index b1f775a275e..b3e13870c95 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_manager.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_manager.c
@@ -388,8 +388,8 @@ __lsm_manager_run_server(WT_SESSION_IMPL *session)
if (!lsm_tree->active)
continue;
__wt_epoch(session, &now);
- pushms = lsm_tree->work_push_ts.tv_sec == 0 ? 0 :
- WT_TIMEDIFF_MS(now, lsm_tree->work_push_ts);
+ pushms = lsm_tree->work_push_time.tv_sec == 0 ? 0 :
+ WT_TIMEDIFF_MS(now, lsm_tree->work_push_time);
fillms = 3 * lsm_tree->chunk_fill_ms;
if (fillms == 0)
fillms = 10000;
@@ -644,7 +644,7 @@ __wt_lsm_manager_push_entry(WT_SESSION_IMPL *session,
return (0);
}
- __wt_epoch(session, &lsm_tree->work_push_ts);
+ __wt_epoch(session, &lsm_tree->work_push_time);
WT_RET(__wt_calloc_one(session, &entry));
entry->type = type;
entry->flags = flags;
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_merge.c b/src/third_party/wiredtiger/src/lsm/lsm_merge.c
index 882dfa86a18..28e954c6f6a 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_merge.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_merge.c
@@ -91,12 +91,12 @@ __lsm_merge_aggressive_update(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
*/
if (!lsm_tree->aggressive_timer_enabled) {
lsm_tree->aggressive_timer_enabled = true;
- __wt_epoch(session, &lsm_tree->merge_aggressive_ts);
+ __wt_epoch(session, &lsm_tree->merge_aggressive_time);
}
__wt_epoch(session, &now);
msec_since_last_merge =
- WT_TIMEDIFF_MS(now, lsm_tree->merge_aggressive_ts);
+ WT_TIMEDIFF_MS(now, lsm_tree->merge_aggressive_time);
/*
* If there is no estimate for how long it's taking to fill chunks
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_tree.c b/src/third_party/wiredtiger/src/lsm/lsm_tree.c
index 62ec44764e7..ebdd1e492cc 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_tree.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_tree.c
@@ -266,7 +266,7 @@ __wt_lsm_tree_setup_chunk(
WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, WT_LSM_CHUNK *chunk)
{
WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_SCHEMA));
- __wt_epoch(session, &chunk->create_ts);
+ __wt_epoch(session, &chunk->create_time);
WT_RET(__wt_lsm_tree_chunk_name(
session, lsm_tree, chunk->id, &chunk->uri));
@@ -497,7 +497,7 @@ __lsm_tree_open(WT_SESSION_IMPL *session,
lsm_tree->queue_ref = 0;
/* Set a flush timestamp as a baseline. */
- __wt_epoch(session, &lsm_tree->last_flush_ts);
+ __wt_epoch(session, &lsm_tree->last_flush_time);
/* Now the tree is setup, make it visible to others. */
TAILQ_INSERT_HEAD(&conn->lsmqh, lsm_tree, q);
@@ -651,10 +651,10 @@ __wt_lsm_tree_throttle(
lsm_tree->ckpt_throttle =
WT_MAX(WT_LSM_THROTTLE_START, 2 * lsm_tree->ckpt_throttle);
} else {
- WT_ASSERT(session,
- WT_TIMECMP(last_chunk->create_ts, ondisk->create_ts) >= 0);
- timediff =
- WT_TIMEDIFF_NS(last_chunk->create_ts, ondisk->create_ts);
+ WT_ASSERT(session, WT_TIMECMP(
+ last_chunk->create_time, ondisk->create_time) >= 0);
+ timediff = WT_TIMEDIFF_NS(
+ last_chunk->create_time, ondisk->create_time);
lsm_tree->ckpt_throttle =
(in_memory - 2) * timediff / (20 * record_count);
@@ -704,13 +704,13 @@ __wt_lsm_tree_throttle(
prev_chunk = lsm_tree->chunk[lsm_tree->nchunks - 2];
WT_ASSERT(session, prev_chunk->generation == 0);
WT_ASSERT(session, WT_TIMECMP(
- last_chunk->create_ts, prev_chunk->create_ts) >= 0);
+ last_chunk->create_time, prev_chunk->create_time) >= 0);
timediff = WT_TIMEDIFF_NS(
- last_chunk->create_ts, prev_chunk->create_ts);
- WT_ASSERT(session,
- WT_TIMECMP(prev_chunk->create_ts, ondisk->create_ts) >= 0);
+ last_chunk->create_time, prev_chunk->create_time);
+ WT_ASSERT(session, WT_TIMECMP(
+ prev_chunk->create_time, ondisk->create_time) >= 0);
oldtime = WT_TIMEDIFF_NS(
- prev_chunk->create_ts, ondisk->create_ts);
+ prev_chunk->create_time, ondisk->create_time);
if (timediff < 10 * oldtime)
lsm_tree->chunk_fill_ms =
(3 * lsm_tree->chunk_fill_ms +
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_work_unit.c b/src/third_party/wiredtiger/src/lsm/lsm_work_unit.c
index ec55de31e0d..9798bd0cf50 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_work_unit.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_work_unit.c
@@ -296,7 +296,7 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
WT_RET(__wt_txn_update_oldest(
session, WT_TXN_OLDEST_STRICT | WT_TXN_OLDEST_WAIT));
if (chunk->switch_txn == WT_TXN_NONE ||
- !__wt_txn_visible_all(session, chunk->switch_txn)) {
+ !__wt_txn_visible_all(session, chunk->switch_txn, NULL)) {
__wt_verbose(session, WT_VERB_LSM,
"LSM worker %s: running transaction, return",
chunk->uri);
@@ -359,7 +359,7 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
WT_ERR(__wt_lsm_tree_set_chunk_size(session, chunk));
/* Update the flush timestamp to help track ongoing progress. */
- __wt_epoch(session, &lsm_tree->last_flush_ts);
+ __wt_epoch(session, &lsm_tree->last_flush_time);
++lsm_tree->chunks_flushed;
/* Lock the tree, mark the chunk as on disk and update the metadata. */
diff --git a/src/third_party/wiredtiger/src/reconcile/rec_write.c b/src/third_party/wiredtiger/src/reconcile/rec_write.c
index 1c266496ec8..a304dc54340 100644
--- a/src/third_party/wiredtiger/src/reconcile/rec_write.c
+++ b/src/third_party/wiredtiger/src/reconcile/rec_write.c
@@ -58,8 +58,9 @@ typedef struct {
uint64_t orig_btree_checkpoint_gen;
uint64_t orig_txn_checkpoint_gen;
- /* Track the page's maximum transaction ID. */
+ /* Track the page's maximum transaction. */
uint64_t max_txn;
+ WT_DECL_TIMESTAMP(max_timestamp)
uint64_t update_mem_all; /* Total update memory size */
uint64_t update_mem_saved; /* Saved update memory size */
@@ -682,6 +683,9 @@ __rec_write_page_status(WT_SESSION_IMPL *session, WT_RECONCILE *r)
* we're likely to be able to evict this page in the future).
*/
mod->rec_max_txn = r->max_txn;
+#ifdef HAVE_TIMESTAMPS
+ __wt_timestamp_set(mod->rec_max_timestamp, r->max_timestamp);
+#endif
/*
* Track the tree's maximum transaction ID (used to decide if
@@ -691,9 +695,16 @@ __rec_write_page_status(WT_SESSION_IMPL *session, WT_RECONCILE *r)
* about the maximum transaction ID of current updates in the
* tree, and checkpoint visits every dirty page in the tree.
*/
- if (!F_ISSET(r, WT_EVICTING) &&
- WT_TXNID_LT(btree->rec_max_txn, r->max_txn))
- btree->rec_max_txn = r->max_txn;
+ if (F_ISSET(r, WT_EVICTING)) {
+ if (WT_TXNID_LT(btree->rec_max_txn, r->max_txn))
+ btree->rec_max_txn = r->max_txn;
+#ifdef HAVE_TIMESTAMPS
+ if (__wt_timestamp_cmp(
+ btree->rec_max_timestamp, r->max_timestamp) < 0)
+ __wt_timestamp_set(
+ btree->rec_max_timestamp, r->max_timestamp);
+#endif
+ }
/*
* The page only might be clean; if the write generation is
@@ -1117,13 +1128,19 @@ __rec_bnd_cleanup(WT_SESSION_IMPL *session, WT_RECONCILE *r, bool destroy)
*/
static int
__rec_update_save(WT_SESSION_IMPL *session,
- WT_RECONCILE *r, WT_INSERT *ins, WT_ROW *rip, uint64_t txnid)
+ WT_RECONCILE *r, WT_INSERT *ins, WT_ROW *rip, WT_UPDATE *upd)
{
WT_RET(__wt_realloc_def(
session, &r->supd_allocated, r->supd_next + 1, &r->supd));
r->supd[r->supd_next].ins = ins;
r->supd[r->supd_next].rip = rip;
- r->supd[r->supd_next].onpage_txn = txnid;
+ r->supd[r->supd_next].onpage_txn =
+ upd == NULL ? WT_TXN_NONE : upd->txnid;
+#ifdef HAVE_TIMESTAMPS
+ if (upd != NULL)
+ __wt_timestamp_set(
+ r->supd[r->supd_next].onpage_timestamp, upd->timestamp);
+#endif
++r->supd_next;
return (0);
}
@@ -1158,6 +1175,8 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
WT_BTREE *btree;
WT_DECL_RET;
WT_DECL_ITEM(tmp);
+ WT_DECL_TIMESTAMP(min_timestamp)
+ WT_DECL_TIMESTAMP(max_timestamp)
WT_PAGE *page;
WT_UPDATE *append, *upd, *upd_list;
size_t notused, update_mem;
@@ -1184,6 +1203,10 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
skipped = false;
update_mem = 0;
max_txn = WT_TXN_NONE;
+#ifdef HAVE_TIMESTAMPS
+ __wt_timestamp_set(max_timestamp, zero_timestamp);
+ memset(min_timestamp, 0xff, WT_TIMESTAMP_SIZE);
+#endif
min_txn = UINT64_MAX;
if (F_ISSET(r, WT_EVICTING)) {
@@ -1208,6 +1231,14 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
if (WT_TXNID_LT(txnid, min_txn))
min_txn = txnid;
+#ifdef HAVE_TIMESTAMPS
+ /* Similarly for the oldest timestamp. */
+ if (__wt_timestamp_cmp(
+ min_timestamp, upd->timestamp) > 0)
+ __wt_timestamp_set(
+ min_timestamp, upd->timestamp);
+#endif
+
/*
* Find the first update we can use.
*
@@ -1222,6 +1253,12 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
if (__wt_txn_committed(session, txnid)) {
if (*updp == NULL)
*updp = upd;
+#ifdef HAVE_TIMESTAMPS
+ if (__wt_timestamp_cmp(
+ max_timestamp, upd->timestamp) < 0)
+ __wt_timestamp_set(
+ max_timestamp, upd->timestamp);
+#endif
} else
skipped = true;
}
@@ -1245,7 +1282,7 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
* visible update.
*/
if (*updp == NULL) {
- if (__wt_txn_visible(session, txnid))
+ if (__wt_txn_upd_visible(session, upd))
*updp = upd;
else
skipped = true;
@@ -1269,13 +1306,17 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
return (0);
/*
- * Track the maximum transaction ID in the page. We store this in the
+ * Track the most recent transaction in the page. We store this in the
* tree at the end of reconciliation in the service of checkpoints, it
* is used to avoid discarding trees from memory when they have changes
* required to satisfy a snapshot read.
*/
if (WT_TXNID_LT(r->max_txn, max_txn))
r->max_txn = max_txn;
+#ifdef HAVE_TIMESTAMPS
+ if (__wt_timestamp_cmp(r->max_timestamp, max_timestamp) < 0)
+ __wt_timestamp_set(r->max_timestamp, max_timestamp);
+#endif
/*
* If there are no skipped updates and all updates are globally visible,
@@ -1289,9 +1330,9 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
* Skip the visibility check for the lookaside table as a special-case,
* we know there are no older readers of that table.
*/
- if (!skipped &&
- (F_ISSET(btree, WT_BTREE_LOOKASIDE) ||
- __wt_txn_visible_all(session, max_txn))) {
+ if (!skipped && (F_ISSET(btree, WT_BTREE_LOOKASIDE) ||
+ __wt_txn_visible_all(session,
+ max_txn, WT_TIMESTAMP(max_timestamp)))) {
#ifdef HAVE_DIAGNOSTIC
/*
* The checkpoint transaction is special. Make sure we never
@@ -1300,7 +1341,7 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
*/
txnid = *updp == NULL ? WT_TXN_NONE : (*updp)->txnid;
WT_ASSERT(session, txnid == WT_TXN_NONE ||
- txnid != S2C(session)->txn_global.checkpoint_txnid ||
+ txnid != S2C(session)->txn_global.checkpoint_state.id ||
WT_SESSION_IS_CHECKPOINT(session));
#endif
return (0);
@@ -1414,7 +1455,8 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
*/
if (vpack != NULL &&
vpack->raw == WT_CELL_VALUE_OVFL_RM &&
- !__wt_txn_visible_all(session, min_txn))
+ !__wt_txn_visible_all(
+ session, min_txn, WT_TIMESTAMP(min_timestamp)))
append_origv = true;
} else {
/*
@@ -1424,7 +1466,8 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
* list and ignore the current on-page value. If no update is
* globally visible, readers require the page's original value.
*/
- if (!__wt_txn_visible_all(session, min_txn))
+ if (!__wt_txn_visible_all(
+ session, min_txn, WT_TIMESTAMP(min_timestamp)))
append_origv = true;
}
@@ -1464,7 +1507,7 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
append->txnid = WT_TXN_NONE;
for (upd = upd_list; upd->next != NULL; upd = upd->next)
;
- upd->next = append;
+ WT_PUBLISH(upd->next, append);
__wt_cache_page_inmem_incr(
session, page, WT_UPDATE_MEMSIZE(append));
}
@@ -1480,8 +1523,7 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
* that transaction ID is globally visible, we know we no longer need
* the lookaside table records, allowing them to be discarded.
*/
- return (__rec_update_save(session,
- r, ins, rip, (*updp == NULL) ? WT_TXN_NONE : (*updp)->txnid));
+ return (__rec_update_save(session, r, ins, rip, *updp));
}
/*
@@ -1533,8 +1575,9 @@ __rec_child_deleted(WT_SESSION_IMPL *session,
*
* In some cases, there had better not be any updates we can't see.
*/
- if (F_ISSET(r, WT_VISIBILITY_ERR) &&
- page_del != NULL && !__wt_txn_visible(session, page_del->txnid))
+ if (F_ISSET(r, WT_VISIBILITY_ERR) && page_del != NULL &&
+ !__wt_txn_visible(session,
+ page_del->txnid, WT_GET_TIMESTAMP(page_del)))
WT_PANIC_RET(session, EINVAL,
"reconciliation illegally skipped an update");
@@ -1563,8 +1606,8 @@ __rec_child_deleted(WT_SESSION_IMPL *session,
* instantiates an entirely new page.)
*/
if (ref->addr != NULL &&
- (page_del == NULL ||
- __wt_txn_visible_all(session, page_del->txnid)))
+ (page_del == NULL || __wt_txn_visible_all(
+ session, page_del->txnid, WT_GET_TIMESTAMP(page_del))))
WT_RET(__wt_ref_block_free(session, ref));
/*
@@ -1614,7 +1657,8 @@ __rec_child_deleted(WT_SESSION_IMPL *session,
* If the delete is not visible in this checkpoint, write the original
* address normally. Otherwise, we have to write a proxy record.
*/
- if (__wt_txn_visible(session, page_del->txnid))
+ if (__wt_txn_visible(
+ session, page_del->txnid, WT_GET_TIMESTAMP(page_del)))
*statep = WT_CHILD_PROXY;
return (0);
@@ -3648,7 +3692,7 @@ __rec_update_las(WT_SESSION_IMPL *session,
WT_CURSOR *cursor;
WT_DECL_ITEM(key);
WT_DECL_RET;
- WT_ITEM las_addr, las_value;
+ WT_ITEM las_addr, las_timestamp, las_value;
WT_PAGE *page;
WT_SAVE_UPD *list;
WT_UPDATE *upd;
@@ -3658,6 +3702,7 @@ __rec_update_las(WT_SESSION_IMPL *session,
cursor = NULL;
WT_CLEAR(las_addr);
+ WT_CLEAR(las_timestamp);
WT_CLEAR(las_value);
page = r->page;
insert_cnt = 0;
@@ -3748,8 +3793,13 @@ __rec_update_las(WT_SESSION_IMPL *session,
if (upd->type == WT_UPDATE_RESERVED)
continue;
- cursor->set_key(cursor, btree_id,
- &las_addr, ++las_counter, list->onpage_txn, key);
+#ifdef HAVE_TIMESTAMPS
+ las_timestamp.data = list->onpage_timestamp;
+ las_timestamp.size = WT_TIMESTAMP_SIZE;
+#endif
+ cursor->set_key(cursor,
+ btree_id, &las_addr, ++las_counter,
+ list->onpage_txn, &las_timestamp, key);
if (upd->type == WT_UPDATE_DELETED)
las_value.size = 0;
@@ -3757,8 +3807,12 @@ __rec_update_las(WT_SESSION_IMPL *session,
las_value.data = WT_UPDATE_DATA(upd);
las_value.size = upd->size;
}
- cursor->set_value(
- cursor, upd->txnid, upd->type, &las_value);
+#ifdef HAVE_TIMESTAMPS
+ las_timestamp.data = upd->timestamp;
+ las_timestamp.size = WT_TIMESTAMP_SIZE;
+#endif
+ cursor->set_value(cursor,
+ upd->txnid, &las_timestamp, upd->type, &las_value);
WT_ERR(cursor->insert(cursor));
++insert_cnt;
diff --git a/src/third_party/wiredtiger/src/session/session_api.c b/src/third_party/wiredtiger/src/session/session_api.c
index 592d6835809..882de30f12b 100644
--- a/src/third_party/wiredtiger/src/session/session_api.c
+++ b/src/third_party/wiredtiger/src/session/session_api.c
@@ -293,15 +293,7 @@ __session_reconfigure(WT_SESSION *wt_session, const char *config)
WT_ERR(__wt_session_reset_cursors(session, false));
- ret = __wt_config_getones(session, config, "isolation", &cval);
- if (ret == 0 && cval.len != 0) {
- session->isolation = session->txn.isolation =
- WT_STRING_MATCH("snapshot", cval.str, cval.len) ?
- WT_ISO_SNAPSHOT :
- WT_STRING_MATCH("read-uncommitted", cval.str, cval.len) ?
- WT_ISO_READ_UNCOMMITTED : WT_ISO_READ_COMMITTED;
- }
- WT_ERR_NOTFOUND_OK(ret);
+ WT_ERR(__wt_txn_reconfigure(session, config));
ret = __wt_config_getones(session, config, "ignore_cache_size", &cval);
if (ret == 0) {
@@ -1466,6 +1458,22 @@ err: API_END_RET(session, ret);
}
/*
+ * __session_timestamp_transaction --
+ * WT_SESSION->timestamp_transaction method.
+ */
+static int
+__session_timestamp_transaction(WT_SESSION *wt_session, const char *config)
+{
+ WT_DECL_RET;
+ WT_SESSION_IMPL *session;
+
+ session = (WT_SESSION_IMPL *)wt_session;
+ SESSION_API_CALL(session, timestamp_transaction, config, cfg);
+ WT_TRET(__wt_txn_set_timestamp(session, cfg));
+err: API_END_RET(session, ret);
+}
+
+/*
* __session_transaction_pinned_range --
* WT_SESSION->transaction_pinned_range method.
*/
@@ -1525,7 +1533,6 @@ __session_transaction_sync(WT_SESSION *wt_session, const char *config)
WT_SESSION_IMPL *session;
struct timespec now, start;
uint64_t remaining_usec, timeout_ms, waited_ms;
- bool forever;
session = (WT_SESSION_IMPL *)wt_session;
SESSION_API_CALL(session, transaction_sync, config, cfg);
@@ -1542,7 +1549,6 @@ __session_transaction_sync(WT_SESSION *wt_session, const char *config)
log = conn->log;
timeout_ms = waited_ms = 0;
- forever = true;
/*
* If there is no background sync LSN in this session, there
@@ -1562,12 +1568,9 @@ __session_transaction_sync(WT_SESSION *wt_session, const char *config)
* Our LSN is not yet stable. Wait and check again depending on the
* timeout.
*/
- WT_ERR(__wt_config_gets_def(
- session, cfg, "timeout_ms", (int)UINT_MAX, &cval));
- if ((unsigned int)cval.val != UINT_MAX) {
- timeout_ms = (uint64_t)cval.val;
- forever = false;
- }
+ WT_ERR(__wt_config_gets_def(session,
+ cfg, "timeout_ms", (int)WT_SESSION_BG_SYNC_MSEC, &cval));
+ timeout_ms = (uint64_t)cval.val;
if (timeout_ms == 0)
WT_ERR(ETIMEDOUT);
@@ -1584,7 +1587,7 @@ __session_transaction_sync(WT_SESSION *wt_session, const char *config)
__wt_cond_signal(session, conn->log_file_cond);
__wt_epoch(session, &now);
waited_ms = WT_TIMEDIFF_MS(now, start);
- if (forever || waited_ms < timeout_ms) {
+ if (waited_ms < timeout_ms) {
remaining_usec = (timeout_ms - waited_ms) * WT_THOUSAND;
__wt_cond_wait(session, log->log_sync_cond,
remaining_usec, __transaction_sync_run_chk);
@@ -1762,6 +1765,7 @@ __open_session(WT_CONNECTION_IMPL *conn,
__session_begin_transaction,
__session_commit_transaction,
__session_rollback_transaction,
+ __session_timestamp_transaction,
__session_checkpoint,
__session_snapshot,
__session_transaction_pinned_range,
@@ -1790,6 +1794,7 @@ __open_session(WT_CONNECTION_IMPL *conn,
__session_begin_transaction,
__session_commit_transaction,
__session_rollback_transaction,
+ __session_timestamp_transaction,
__session_checkpoint_readonly,
__session_snapshot,
__session_transaction_pinned_range,
diff --git a/src/third_party/wiredtiger/src/txn/txn.c b/src/third_party/wiredtiger/src/txn/txn.c
index fb77ab4e860..02adad65ba5 100644
--- a/src/third_party/wiredtiger/src/txn/txn.c
+++ b/src/third_party/wiredtiger/src/txn/txn.c
@@ -98,7 +98,7 @@ __wt_txn_release_snapshot(WT_SESSION_IMPL *session)
WT_ASSERT(session,
txn_state->pinned_id == WT_TXN_NONE ||
session->txn.isolation == WT_ISO_READ_UNCOMMITTED ||
- !__wt_txn_visible_all(session, txn_state->pinned_id));
+ !__wt_txn_visible_all(session, txn_state->pinned_id, NULL));
txn_state->metadata_pinned = txn_state->pinned_id = WT_TXN_NONE;
F_CLR(txn, WT_TXN_HAS_SNAPSHOT);
@@ -126,7 +126,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
n = 0;
/* We're going to scan the table: wait for the lock. */
- __wt_readlock(session, &txn_global->scan_rwlock);
+ __wt_readlock(session, &txn_global->rwlock);
current_id = pinned_id = txn_global->current;
prev_oldest_id = txn_global->oldest_id;
@@ -137,7 +137,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
* metadata. We don't have to keep the checkpoint's changes pinned so
* don't including it in the published pinned ID.
*/
- if ((id = txn_global->checkpoint_txnid) != WT_TXN_NONE) {
+ if ((id = txn_global->checkpoint_state.id) != WT_TXN_NONE) {
txn->snapshot[n++] = id;
txn_state->metadata_pinned = id;
}
@@ -180,7 +180,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
WT_ASSERT(session, prev_oldest_id == txn_global->oldest_id);
txn_state->pinned_id = pinned_id;
-done: __wt_readunlock(session, &txn_global->scan_rwlock);
+done: __wt_readunlock(session, &txn_global->rwlock);
__txn_sort_snapshot(session, n, current_id);
}
@@ -207,7 +207,7 @@ __txn_oldest_scan(WT_SESSION_IMPL *session,
/* The oldest ID cannot change while we are holding the scan lock. */
prev_oldest_id = txn_global->oldest_id;
last_running = oldest_id = txn_global->current;
- if ((metadata_pinned = txn_global->checkpoint_txnid) == WT_TXN_NONE)
+ if ((metadata_pinned = txn_global->checkpoint_state.id) == WT_TXN_NONE)
metadata_pinned = oldest_id;
/* Walk the array of concurrent transactions. */
@@ -282,6 +282,12 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
prev_metadata_pinned = txn_global->metadata_pinned;
prev_oldest_id = txn_global->oldest_id;
+#ifdef HAVE_TIMESTAMPS
+ /* Try to move the pinned timestamp forward. */
+ if (strict)
+ WT_RET(__wt_txn_update_pinned_timestamp(session));
+#endif
+
/*
* For pure read-only workloads, or if the update isn't forced and the
* oldest ID isn't too far behind, avoid scanning.
@@ -293,13 +299,13 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
/* First do a read-only scan. */
if (wait)
- __wt_readlock(session, &txn_global->scan_rwlock);
+ __wt_readlock(session, &txn_global->rwlock);
else if ((ret =
- __wt_try_readlock(session, &txn_global->scan_rwlock)) != 0)
+ __wt_try_readlock(session, &txn_global->rwlock)) != 0)
return (ret == EBUSY ? 0 : ret);
__txn_oldest_scan(session,
&oldest_id, &last_running, &metadata_pinned, &oldest_session);
- __wt_readunlock(session, &txn_global->scan_rwlock);
+ __wt_readunlock(session, &txn_global->rwlock);
/*
* If the state hasn't changed (or hasn't moved far enough for
@@ -314,9 +320,9 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
/* It looks like an update is necessary, wait for exclusive access. */
if (wait)
- __wt_writelock(session, &txn_global->scan_rwlock);
+ __wt_writelock(session, &txn_global->rwlock);
else if ((ret =
- __wt_try_writelock(session, &txn_global->scan_rwlock)) != 0)
+ __wt_try_writelock(session, &txn_global->rwlock)) != 0)
return (ret == EBUSY ? 0 : ret);
/*
@@ -375,7 +381,7 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
#endif
}
-done: __wt_writeunlock(session, &txn_global->scan_rwlock);
+done: __wt_writeunlock(session, &txn_global->rwlock);
return (ret);
}
@@ -431,6 +437,60 @@ __wt_txn_config(WT_SESSION_IMPL *session, const char *cfg[])
*/
WT_RET(__wt_txn_named_snapshot_get(session, &cval));
+ WT_RET(__wt_config_gets_def(session, cfg, "read_timestamp", 0, &cval));
+ if (cval.len > 0) {
+#ifdef HAVE_TIMESTAMPS
+ WT_TXN_GLOBAL *txn_global = &S2C(session)->txn_global;
+ WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session);
+ wt_timestamp_t oldest_timestamp;
+
+ WT_RET(__wt_txn_parse_timestamp(
+ session, "read", txn->read_timestamp, &cval));
+ __wt_readlock(session, &txn_global->rwlock);
+ __wt_timestamp_set(
+ oldest_timestamp, txn_global->oldest_timestamp);
+ __wt_readunlock(session, &txn_global->rwlock);
+ if (__wt_timestamp_cmp(
+ txn->read_timestamp, oldest_timestamp) < 0)
+ WT_RET_MSG(session, EINVAL,
+ "read timestamp %.*s older than oldest timestamp",
+ (int)cval.len, cval.str);
+ __wt_timestamp_set(
+ txn_state->read_timestamp, txn->read_timestamp);
+ F_SET(txn, WT_TXN_HAS_TS_READ);
+ txn->isolation = WT_ISO_SNAPSHOT;
+#else
+ WT_RET_MSG(session, EINVAL, "read_timestamp requires a "
+ "version of WiredTiger built with timestamp support");
+#endif
+ }
+
+ return (0);
+}
+
+/*
+ * __wt_txn_reconfigure --
+ * WT_SESSION::reconfigure for transactions.
+ */
+int
+__wt_txn_reconfigure(WT_SESSION_IMPL *session, const char *config)
+{
+ WT_CONFIG_ITEM cval;
+ WT_DECL_RET;
+ WT_TXN *txn;
+
+ txn = &session->txn;
+
+ ret = __wt_config_getones(session, config, "isolation", &cval);
+ if (ret == 0 && cval.len != 0) {
+ session->isolation = txn->isolation =
+ WT_STRING_MATCH("snapshot", cval.str, cval.len) ?
+ WT_ISO_SNAPSHOT :
+ WT_STRING_MATCH("read-uncommitted", cval.str, cval.len) ?
+ WT_ISO_READ_UNCOMMITTED : WT_ISO_READ_COMMITTED;
+ }
+ WT_RET_NOTFOUND_OK(ret);
+
return (0);
}
@@ -455,7 +515,8 @@ __wt_txn_release(WT_SESSION_IMPL *session)
/* Clear the transaction's ID from the global table. */
if (WT_SESSION_IS_CHECKPOINT(session)) {
WT_ASSERT(session, txn_state->id == WT_TXN_NONE);
- txn->id = txn_global->checkpoint_txnid = WT_TXN_NONE;
+ txn->id = txn_global->checkpoint_state.id =
+ txn_global->checkpoint_state.pinned_id = WT_TXN_NONE;
/*
* Be extra careful to cleanup everything for checkpoints: once
@@ -463,7 +524,6 @@ __wt_txn_release(WT_SESSION_IMPL *session)
* if this session is doing a checkpoint.
*/
txn_global->checkpoint_id = 0;
- txn_global->checkpoint_pinned = WT_TXN_NONE;
} else if (F_ISSET(txn, WT_TXN_HAS_ID)) {
WT_ASSERT(session,
!WT_TXNID_LT(txn->id, txn_global->last_running));
@@ -471,6 +531,19 @@ __wt_txn_release(WT_SESSION_IMPL *session)
WT_ASSERT(session, txn_state->id != WT_TXN_NONE &&
txn->id != WT_TXN_NONE);
WT_PUBLISH(txn_state->id, WT_TXN_NONE);
+#ifdef HAVE_TIMESTAMPS
+ if (F_ISSET(txn, WT_TXN_HAS_TS_COMMIT)) {
+ /*
+ * We rely on a non-zero ID to protect our published
+ * commit timestamp. Otherwise we would need a lock
+ * here.
+ */
+ WT_WRITE_BARRIER();
+ __wt_timestamp_set(
+ txn_state->commit_timestamp, zero_timestamp);
+ }
+#endif
+
txn->id = WT_TXN_NONE;
}
@@ -503,6 +576,12 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
WT_DECL_RET;
WT_TXN *txn;
WT_TXN_OP *op;
+#ifdef HAVE_TIMESTAMPS
+ WT_TXN_GLOBAL *txn_global = &S2C(session)->txn_global;
+ WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session);
+ wt_timestamp_t prev_commit_timestamp;
+ bool update_timestamp;
+#endif
u_int i;
bool did_update;
@@ -514,10 +593,32 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
WT_ASSERT(session, !F_ISSET(txn, WT_TXN_ERROR) || !did_update);
/*
+ * Look for a commit timestamp.
+ */
+ WT_ERR(
+ __wt_config_gets_def(session, cfg, "commit_timestamp", 0, &cval));
+ if (cval.len != 0) {
+#ifdef HAVE_TIMESTAMPS
+ WT_ERR(__wt_txn_parse_timestamp(
+ session, "commit", txn->commit_timestamp, &cval));
+ if (!F_ISSET(txn, WT_TXN_HAS_TS_COMMIT)) {
+ __wt_writelock(session, &txn_global->rwlock);
+ __wt_timestamp_set(txn_state->commit_timestamp,
+ txn->commit_timestamp);
+ __wt_writeunlock(session, &txn_global->rwlock);
+ F_SET(txn, WT_TXN_HAS_TS_COMMIT);
+ }
+#else
+ WT_ERR_MSG(session, EINVAL, "commit_timestamp requires a "
+ "version of WiredTiger built with timestamp support");
+#endif
+ }
+
+ /*
* The default sync setting is inherited from the connection, but can
* be overridden by an explicit "sync" setting for this transaction.
*/
- WT_RET(__wt_config_gets_def(session, cfg, "sync", 0, &cval));
+ WT_ERR(__wt_config_gets_def(session, cfg, "sync", 0, &cval));
/*
* If the user chose the default setting, check whether sync is enabled
@@ -541,7 +642,7 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* Flag that as an error.
*/
if (F_ISSET(txn, WT_TXN_SYNC_SET))
- WT_RET_MSG(session, EINVAL,
+ WT_ERR_MSG(session, EINVAL,
"Sync already set during begin_transaction");
if (WT_STRING_MATCH("background", cval.str, cval.len))
txn->txn_logsync = WT_LOG_BACKGROUND;
@@ -555,7 +656,7 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
/* Commit notification. */
if (txn->notify != NULL)
- WT_TRET(txn->notify->notify(txn->notify,
+ WT_ERR(txn->notify->notify(txn->notify,
(WT_SESSION *)session, txn->id, 1));
/*
@@ -565,11 +666,11 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
*/
if (session->ncursors > 0) {
WT_DIAGNOSTIC_YIELD;
- WT_RET(__wt_session_copy_values(session));
+ WT_ERR(__wt_session_copy_values(session));
}
/* If we are logging, write a commit log record. */
- if (ret == 0 && did_update &&
+ if (did_update &&
FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED) &&
!F_ISSET(session, WT_SESSION_NO_LOGGING)) {
/*
@@ -578,44 +679,103 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* This is particularly important for checkpoints.
*/
__wt_txn_release_snapshot(session);
- ret = __wt_txn_log_commit(session, cfg);
+ WT_ERR(__wt_txn_log_commit(session, cfg));
}
- /*
- * If anything went wrong, roll back.
- *
- * !!!
- * Nothing can fail after this point.
- */
- if (ret != 0) {
- WT_TRET(__wt_txn_rollback(session, cfg));
- return (ret);
- }
+ /* Note: we're going to commit: nothing can fail after this point. */
+ /* Process and free updates. */
for (i = 0, op = txn->mod; i < txn->mod_count; i++, op++) {
switch (op->type) {
case WT_TXN_OP_BASIC:
+ case WT_TXN_OP_BASIC_TS:
case WT_TXN_OP_INMEM:
/*
- * Switch reserved operations to abort to simplify
- * obsolete update list truncation.
+ * Switch reserved operations to abort to
+ * simplify obsolete update list truncation.
*/
- if (op->u.upd->type == WT_UPDATE_RESERVED)
+ if (op->u.upd->type == WT_UPDATE_RESERVED) {
op->u.upd->txnid = WT_TXN_ABORTED;
+ break;
+ }
+
+#ifdef HAVE_TIMESTAMPS
+ if (F_ISSET(txn, WT_TXN_HAS_TS_COMMIT) &&
+ op->type != WT_TXN_OP_BASIC_TS)
+ __wt_timestamp_set(op->u.upd->timestamp,
+ txn->commit_timestamp);
+#endif
break;
+
case WT_TXN_OP_REF:
+#ifdef HAVE_TIMESTAMPS
+ if (F_ISSET(txn, WT_TXN_HAS_TS_COMMIT))
+ __wt_timestamp_set(
+ op->u.ref->page_del->timestamp,
+ txn->commit_timestamp);
+#endif
+ break;
+
case WT_TXN_OP_TRUNCATE_COL:
case WT_TXN_OP_TRUNCATE_ROW:
+ /* Other operations don't need timestamps. */
break;
}
- /* Free memory associated with updates. */
__wt_txn_op_free(session, op);
}
txn->mod_count = 0;
+#ifdef HAVE_TIMESTAMPS
+ /*
+ * Track the largest commit timestamp we have seen.
+ *
+ * We don't actually clear the local commit timestamp, just the flag.
+ * That said, we can't update the global commit timestamp until this
+ * transaction is visible, which happens when we release it.
+ */
+ update_timestamp = F_ISSET(txn, WT_TXN_HAS_TS_COMMIT);
+#endif
+
__wt_txn_release(session);
+
+#ifdef HAVE_TIMESTAMPS
+ /* First check if we've already committed something in the future. */
+ if (update_timestamp) {
+ __wt_readlock(session, &txn_global->rwlock);
+ __wt_timestamp_set(
+ prev_commit_timestamp, txn_global->commit_timestamp);
+ __wt_readunlock(session, &txn_global->rwlock);
+ update_timestamp = __wt_timestamp_cmp(
+ txn->commit_timestamp, prev_commit_timestamp) > 0;
+ }
+
+ /*
+ * If it looks like we need to move the global commit timestamp,
+ * write lock and re-check.
+ */
+ if (update_timestamp) {
+ __wt_writelock(session, &txn_global->rwlock);
+ if (__wt_timestamp_cmp(txn->commit_timestamp,
+ txn_global->commit_timestamp) > 0) {
+ __wt_timestamp_set(txn_global->commit_timestamp,
+ txn->commit_timestamp);
+ txn_global->has_commit_timestamp = true;
+ }
+ __wt_writeunlock(session, &txn_global->rwlock);
+ }
+#endif
+
return (0);
+
+err: /*
+ * If anything went wrong, roll back.
+ *
+ * !!!
+ * Nothing can fail after this point.
+ */
+ WT_TRET(__wt_txn_rollback(session, cfg));
+ return (ret);
}
/*
@@ -648,6 +808,7 @@ __wt_txn_rollback(WT_SESSION_IMPL *session, const char *cfg[])
switch (op->type) {
case WT_TXN_OP_BASIC:
+ case WT_TXN_OP_BASIC_TS:
case WT_TXN_OP_INMEM:
WT_ASSERT(session, op->u.upd->txnid == txn->id);
op->u.upd->txnid = WT_TXN_ABORTED;
@@ -723,7 +884,7 @@ __wt_txn_stats_update(WT_SESSION_IMPL *session)
conn = S2C(session);
txn_global = &conn->txn_global;
stats = conn->stats;
- checkpoint_pinned = txn_global->checkpoint_pinned;
+ checkpoint_pinned = txn_global->checkpoint_state.pinned_id;
snapshot_pinned = txn_global->nsnap_oldest_id;
WT_STAT_SET(session, stats, txn_pinned_range,
@@ -780,10 +941,11 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
txn_global->current = txn_global->last_running =
txn_global->metadata_pinned = txn_global->oldest_id = WT_TXN_FIRST;
- WT_RET(__wt_spin_init(session,
- &txn_global->id_lock, "transaction id lock"));
- WT_RET(__wt_rwlock_init(session, &txn_global->scan_rwlock));
+ WT_RET(__wt_spin_init(
+ session, &txn_global->id_lock, "transaction id lock"));
+ WT_RET(__wt_rwlock_init(session, &txn_global->rwlock));
WT_RET(__wt_rwlock_init(session, &txn_global->nsnap_rwlock));
+
txn_global->nsnap_oldest_id = WT_TXN_NONE;
TAILQ_INIT(&txn_global->nsnaph);
@@ -813,11 +975,51 @@ __wt_txn_global_destroy(WT_SESSION_IMPL *session)
return;
__wt_spin_destroy(session, &txn_global->id_lock);
- __wt_rwlock_destroy(session, &txn_global->scan_rwlock);
+ __wt_rwlock_destroy(session, &txn_global->rwlock);
__wt_rwlock_destroy(session, &txn_global->nsnap_rwlock);
__wt_free(session, txn_global->states);
}
+/*
+ * __wt_txn_global_shutdown --
+ * Shut down the global transaction state.
+ */
+int
+__wt_txn_global_shutdown(WT_SESSION_IMPL *session)
+{
+ WT_DECL_RET;
+ WT_TXN_GLOBAL *txn_global;
+
+ txn_global = &S2C(session)->txn_global;
+
+ /*
+ * We're shutting down. Make sure everything gets freed.
+ *
+ * It's possible that the eviction server is in the middle of a long
+ * operation, with a transaction ID pinned. In that case, we will loop
+ * here until the transaction ID is released, when the oldest
+ * transaction ID will catch up with the current ID.
+ */
+ for (;;) {
+ WT_TRET(__wt_txn_update_oldest(session,
+ WT_TXN_OLDEST_STRICT | WT_TXN_OLDEST_WAIT));
+ if (txn_global->oldest_id == txn_global->current &&
+ txn_global->metadata_pinned == txn_global->current)
+ break;
+ __wt_yield();
+ }
+
+#ifdef HAVE_TIMESTAMPS
+ /*
+ * Now that all transactions have completed, no timestamps should be
+ * pinned.
+ */
+ memset(txn_global->pinned_timestamp, 0xff, WT_TIMESTAMP_SIZE);
+#endif
+
+ return (ret);
+}
+
#if defined(HAVE_DIAGNOSTIC) || defined(HAVE_VERBOSE)
/*
* __wt_verbose_dump_txn --
@@ -849,13 +1051,12 @@ __wt_verbose_dump_txn(WT_SESSION_IMPL *session)
WT_RET(__wt_msg(session, "checkpoint running? %s",
txn_global->checkpoint_running ? "yes" : "no"));
- WT_RET(__wt_msg(session,
- "checkpoint generation: %" PRIu64,
+ WT_RET(__wt_msg(session, "checkpoint generation: %" PRIu64,
__wt_gen(session, WT_GEN_CHECKPOINT)));
- WT_RET(__wt_msg(session,
- "checkpoint pinned ID: %" PRIu64, txn_global->checkpoint_pinned));
- WT_RET(__wt_msg(session,
- "checkpoint txn ID: %" PRIu64, txn_global->checkpoint_txnid));
+ WT_RET(__wt_msg(session, "checkpoint pinned ID: %" PRIu64,
+ txn_global->checkpoint_state.pinned_id));
+ WT_RET(__wt_msg(session, "checkpoint txn ID: %" PRIu64,
+ txn_global->checkpoint_state.id));
WT_ORDERED_READ(session_cnt, conn->session_cnt);
WT_RET(__wt_msg(session, "session count: %" PRIu32, session_cnt));
diff --git a/src/third_party/wiredtiger/src/txn/txn_ckpt.c b/src/third_party/wiredtiger/src/txn/txn_ckpt.c
index 82163f471b8..73ad96b5518 100644
--- a/src/third_party/wiredtiger/src/txn/txn_ckpt.c
+++ b/src/third_party/wiredtiger/src/txn/txn_ckpt.c
@@ -8,6 +8,7 @@
#include "wt_internal.h"
+static void __checkpoint_timing_stress(WT_SESSION_IMPL *);
static int __checkpoint_lock_dirty_tree(
WT_SESSION_IMPL *, bool, bool, bool, const char *[]);
static int __checkpoint_mark_skip(WT_SESSION_IMPL *, WT_CKPT *, bool);
@@ -564,19 +565,28 @@ __checkpoint_fail_reset(WT_SESSION_IMPL *session)
static int
__checkpoint_prepare(WT_SESSION_IMPL *session, const char *cfg[])
{
+ WT_CONFIG_ITEM cval;
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_TXN *txn;
WT_TXN_GLOBAL *txn_global;
WT_TXN_STATE *txn_state;
+ char timestamp_config[100];
const char *txn_cfg[] = { WT_CONFIG_BASE(session,
- WT_SESSION_begin_transaction), "isolation=snapshot", NULL };
+ WT_SESSION_begin_transaction), "isolation=snapshot", NULL, NULL };
conn = S2C(session);
txn = &session->txn;
txn_global = &conn->txn_global;
txn_state = WT_SESSION_TXN_STATE(session);
+ WT_RET(__wt_config_gets(session, cfg, "read_timestamp", &cval));
+ if (cval.len > 0) {
+ WT_RET(__wt_snprintf(timestamp_config, sizeof(timestamp_config),
+ "read_timestamp=%.*s", (int)cval.len, cval.str));
+ txn_cfg[2] = timestamp_config;
+ }
+
/*
* Start a snapshot transaction for the checkpoint.
*
@@ -613,9 +623,9 @@ __checkpoint_prepare(WT_SESSION_IMPL *session, const char *cfg[])
* This allows ordinary visibility checks to move forward because
* checkpoints often take a long time and only write to the metadata.
*/
- __wt_writelock(session, &txn_global->scan_rwlock);
- txn_global->checkpoint_txnid = txn->id;
- txn_global->checkpoint_pinned = WT_MIN(txn->id, txn->snap_min);
+ __wt_writelock(session, &txn_global->rwlock);
+ txn_global->checkpoint_state = *txn_state;
+ txn_global->checkpoint_state.pinned_id = WT_MIN(txn->id, txn->snap_min);
/*
* Sanity check that the oldest ID hasn't moved on before we have
@@ -634,7 +644,7 @@ __checkpoint_prepare(WT_SESSION_IMPL *session, const char *cfg[])
*/
txn_state->id = txn_state->pinned_id =
txn_state->metadata_pinned = WT_TXN_NONE;
- __wt_writeunlock(session, &txn_global->scan_rwlock);
+ __wt_writeunlock(session, &txn_global->rwlock);
/*
* Get a list of handles we want to flush; for named checkpoints this
@@ -771,6 +781,8 @@ __txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
WT_ERR(__wt_txn_checkpoint_log(
session, full, WT_TXN_LOG_CKPT_START, NULL));
+ __checkpoint_timing_stress(session);
+
WT_ERR(__checkpoint_apply(session, cfg, __checkpoint_tree_helper));
/*
@@ -852,7 +864,7 @@ __txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
* Now that the metadata is stable, re-open the metadata file for
* regular eviction by clearing the checkpoint_pinned flag.
*/
- txn_global->checkpoint_pinned = WT_TXN_NONE;
+ txn_global->checkpoint_state.pinned_id = WT_TXN_NONE;
if (full) {
__wt_epoch(session, &stop);
@@ -1671,7 +1683,8 @@ __wt_checkpoint_close(WT_SESSION_IMPL *session, bool final)
if (!btree->modified && !bulk) {
WT_RET(__wt_txn_update_oldest(
session, WT_TXN_OLDEST_STRICT | WT_TXN_OLDEST_WAIT));
- return (__wt_txn_visible_all(session, btree->rec_max_txn) ?
+ return (__wt_txn_visible_all(session, btree->rec_max_txn,
+ WT_TIMESTAMP(btree->rec_max_timestamp)) ?
__wt_cache_op(session, WT_SYNC_DISCARD) : EBUSY);
}
@@ -1697,3 +1710,29 @@ __wt_checkpoint_close(WT_SESSION_IMPL *session, bool final)
return (ret);
}
+
+/*
+ * __checkpoint_timing_stress --
+ * Optionally add a 10 second delay to a checkpoint to simulate a long
+ * running checkpoint for debug purposes. The reason for this option is
+ * finding operations that can block while waiting for a checkpoint to
+ * complete.
+ */
+static void
+__checkpoint_timing_stress(WT_SESSION_IMPL *session)
+{
+ WT_CONNECTION_IMPL *conn;
+
+ conn = S2C(session);
+
+ /*
+ * We only want to sleep if the flag is set and the checkpoint comes
+ * from the API, so check if the session used is either of the two
+ * sessions set aside for internal checkpoints.
+ */
+ if (conn->ckpt_session != session &&
+ conn->meta_ckpt_session != session &&
+ FLD_ISSET(conn->timing_stress_flags,
+ WT_TIMING_STRESS_CHECKPOINT_SLOW))
+ __wt_sleep(10, 0);
+}
diff --git a/src/third_party/wiredtiger/src/txn/txn_ext.c b/src/third_party/wiredtiger/src/txn/txn_ext.c
index 625f970cca8..1fe4d6ddf47 100644
--- a/src/third_party/wiredtiger/src/txn/txn_ext.c
+++ b/src/third_party/wiredtiger/src/txn/txn_ext.c
@@ -101,5 +101,5 @@ __wt_ext_transaction_visible(
(void)wt_api; /* Unused parameters */
return (__wt_txn_visible(
- (WT_SESSION_IMPL *)wt_session, transaction_id));
+ (WT_SESSION_IMPL *)wt_session, transaction_id, NULL));
}
diff --git a/src/third_party/wiredtiger/src/txn/txn_log.c b/src/third_party/wiredtiger/src/txn/txn_log.c
index 74dc679a6ef..3d218aea94f 100644
--- a/src/third_party/wiredtiger/src/txn/txn_log.c
+++ b/src/third_party/wiredtiger/src/txn/txn_log.c
@@ -148,6 +148,7 @@ __wt_txn_op_free(WT_SESSION_IMPL *session, WT_TXN_OP *op)
{
switch (op->type) {
case WT_TXN_OP_BASIC:
+ case WT_TXN_OP_BASIC_TS:
case WT_TXN_OP_INMEM:
case WT_TXN_OP_REF:
case WT_TXN_OP_TRUNCATE_COL:
@@ -225,6 +226,7 @@ __wt_txn_log_op(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt)
switch (op->type) {
case WT_TXN_OP_BASIC:
+ case WT_TXN_OP_BASIC_TS:
ret = __txn_op_log(session, logrec, op, cbt);
break;
case WT_TXN_OP_INMEM:
diff --git a/src/third_party/wiredtiger/src/txn/txn_nsnap.c b/src/third_party/wiredtiger/src/txn/txn_nsnap.c
index 601d9492566..9ad987d73f6 100644
--- a/src/third_party/wiredtiger/src/txn/txn_nsnap.c
+++ b/src/third_party/wiredtiger/src/txn/txn_nsnap.c
@@ -43,13 +43,13 @@ __nsnap_drop_one(WT_SESSION_IMPL *session, WT_CONFIG_ITEM *name)
/* Bump the global ID if we are removing the first entry */
if (found == TAILQ_FIRST(&txn_global->nsnaph)) {
WT_ASSERT(session, !__wt_txn_visible_all(
- session, txn_global->nsnap_oldest_id));
+ session, txn_global->nsnap_oldest_id, NULL));
txn_global->nsnap_oldest_id = (TAILQ_NEXT(found, q) != NULL) ?
TAILQ_NEXT(found, q)->pinned_id : WT_TXN_NONE;
WT_DIAGNOSTIC_YIELD;
WT_ASSERT(session, txn_global->nsnap_oldest_id == WT_TXN_NONE ||
!__wt_txn_visible_all(
- session, txn_global->nsnap_oldest_id));
+ session, txn_global->nsnap_oldest_id, NULL));
}
TAILQ_REMOVE(&txn_global->nsnaph, found, q);
__nsnap_destroy(session, found);
@@ -123,14 +123,14 @@ __nsnap_drop_to(WT_SESSION_IMPL *session, WT_CONFIG_ITEM *name, bool inclusive)
/* Now that the queue of named snapshots is updated, update the ID */
WT_ASSERT(session, !__wt_txn_visible_all(
- session, txn_global->nsnap_oldest_id) &&
+ session, txn_global->nsnap_oldest_id, NULL) &&
(new_nsnap_oldest == WT_TXN_NONE ||
WT_TXNID_LE(txn_global->nsnap_oldest_id, new_nsnap_oldest)));
txn_global->nsnap_oldest_id = new_nsnap_oldest;
WT_DIAGNOSTIC_YIELD;
WT_ASSERT(session,
new_nsnap_oldest == WT_TXN_NONE ||
- !__wt_txn_visible_all(session, new_nsnap_oldest));
+ !__wt_txn_visible_all(session, new_nsnap_oldest, NULL));
return (0);
}
@@ -210,10 +210,10 @@ __wt_txn_named_snapshot_begin(WT_SESSION_IMPL *session, const char *cfg[])
if (TAILQ_EMPTY(&txn_global->nsnaph)) {
WT_ASSERT(session, txn_global->nsnap_oldest_id == WT_TXN_NONE &&
- !__wt_txn_visible_all(session, nsnap_new->pinned_id));
- __wt_readlock(session, &txn_global->scan_rwlock);
+ !__wt_txn_visible_all(session, nsnap_new->pinned_id, NULL));
+ __wt_readlock(session, &txn_global->rwlock);
txn_global->nsnap_oldest_id = nsnap_new->pinned_id;
- __wt_readunlock(session, &txn_global->scan_rwlock);
+ __wt_readunlock(session, &txn_global->rwlock);
}
TAILQ_INSERT_TAIL(&txn_global->nsnaph, nsnap_new, q);
WT_STAT_CONN_INCR(session, txn_snapshots_created);
@@ -225,7 +225,8 @@ err: if (started_txn) {
#endif
WT_TRET(__wt_txn_rollback(session, NULL));
WT_DIAGNOSTIC_YIELD;
- WT_ASSERT(session, !__wt_txn_visible_all(session, pinned_id));
+ WT_ASSERT(session,
+ !__wt_txn_visible_all(session, pinned_id, NULL));
}
if (nsnap_new != NULL)
@@ -304,12 +305,12 @@ __wt_txn_named_snapshot_get(WT_SESSION_IMPL *session, WT_CONFIG_ITEM *nameval)
* Acquire the scan lock so the oldest ID can't move
* forward without seeing our pinned ID.
*/
- __wt_readlock(session, &txn_global->scan_rwlock);
+ __wt_readlock(session, &txn_global->rwlock);
txn_state->pinned_id = nsnap->pinned_id;
- __wt_readunlock(session, &txn_global->scan_rwlock);
+ __wt_readunlock(session, &txn_global->rwlock);
WT_ASSERT(session, !__wt_txn_visible_all(
- session, txn_state->pinned_id) &&
+ session, txn_state->pinned_id, NULL) &&
txn_global->nsnap_oldest_id != WT_TXN_NONE &&
WT_TXNID_LE(txn_global->nsnap_oldest_id,
txn_state->pinned_id));
diff --git a/src/third_party/wiredtiger/src/txn/txn_timestamp.c b/src/third_party/wiredtiger/src/txn/txn_timestamp.c
new file mode 100644
index 00000000000..ebef0320d4f
--- /dev/null
+++ b/src/third_party/wiredtiger/src/txn/txn_timestamp.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 2014-2017 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "wt_internal.h"
+
+#ifdef HAVE_TIMESTAMPS
+/*
+ * __wt_txn_parse_timestamp --
+ * Decodes and sets a timestamp.
+ */
+int
+__wt_txn_parse_timestamp(WT_SESSION_IMPL *session,
+ const char *name, uint8_t *timestamp, WT_CONFIG_ITEM *cval)
+{
+ WT_DECL_RET;
+ WT_ITEM ts;
+ wt_timestamp_t tsbuf;
+ size_t hexlen;
+ const char *hexts;
+ char padbuf[2 * WT_TIMESTAMP_SIZE + 1];
+
+ __wt_timestamp_set(timestamp, zero_timestamp);
+
+ if (cval->len == 0)
+ return (0);
+
+ /* Protect against unexpectedly long hex strings. */
+ if (cval->len > 2 * WT_TIMESTAMP_SIZE)
+ WT_RET_MSG(session, EINVAL,
+ "Failed to parse %s timestamp '%.*s': too long",
+ name, (int)cval->len, cval->str);
+
+ /*
+ * The decoding function assumes it is decoding data produced by dump
+ * and so requires an even number of hex digits.
+ */
+ if ((cval->len & 1) == 0) {
+ hexts = cval->str;
+ hexlen = cval->len;
+ } else {
+ padbuf[0] = '0';
+ memcpy(padbuf + 1, cval->str, cval->len);
+ hexts = padbuf;
+ hexlen = cval->len + 1;
+ }
+
+ /* Avoid memory allocation to decode timestamps. */
+ ts.data = ts.mem = tsbuf;
+ ts.memsize = sizeof(tsbuf);
+
+ if ((ret = __wt_nhex_to_raw(session, hexts, hexlen, &ts)) != 0)
+ WT_RET_MSG(session, ret, "Failed to parse %s timestamp '%.*s'",
+ name, (int)cval->len, cval->str);
+ WT_ASSERT(session, ts.size <= WT_TIMESTAMP_SIZE);
+
+ /* Copy the raw value to the end of the timestamp. */
+ memcpy(timestamp + WT_TIMESTAMP_SIZE - ts.size,
+ ts.data, ts.size);
+
+ if (__wt_timestamp_iszero(timestamp))
+ WT_RET_MSG(session, EINVAL,
+ "Failed to parse %s timestamp '%.*s': zero not permitted",
+ name, (int)cval->len, cval->str);
+
+ return (ret);
+}
+
+/*
+ * __txn_global_query_timestamp --
+ * Query a timestamp.
+ */
+static int
+__txn_global_query_timestamp(
+ WT_SESSION_IMPL *session, uint8_t *ts, const char *cfg[])
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_CONFIG_ITEM cval;
+ WT_TXN_GLOBAL *txn_global;
+ WT_TXN_STATE *s;
+ uint32_t i, session_cnt;
+
+ conn = S2C(session);
+ txn_global = &conn->txn_global;
+
+ WT_RET(__wt_config_gets(session, cfg, "get", &cval));
+ if (WT_STRING_MATCH("all_committed", cval.str, cval.len)) {
+ if (!txn_global->has_commit_timestamp)
+ return (WT_NOTFOUND);
+ __wt_readlock(session, &txn_global->rwlock);
+ __wt_timestamp_set(ts, txn_global->commit_timestamp);
+ WT_ORDERED_READ(session_cnt, conn->session_cnt);
+ for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) {
+ if (s->id == WT_TXN_NONE ||
+ __wt_timestamp_iszero(s->commit_timestamp))
+ continue;
+ if (__wt_timestamp_cmp(s->commit_timestamp, ts) < 0)
+ __wt_timestamp_set(ts, s->commit_timestamp);
+ }
+ __wt_readunlock(session, &txn_global->rwlock);
+ } else if (WT_STRING_MATCH("oldest_reader", cval.str, cval.len)) {
+ if (!txn_global->has_oldest_timestamp)
+ return (WT_NOTFOUND);
+ __wt_readlock(session, &txn_global->rwlock);
+ __wt_timestamp_set(ts, txn_global->oldest_timestamp);
+ /* Look at running checkpoints. */
+ s = &txn_global->checkpoint_state;
+ if (s->pinned_id != WT_TXN_NONE &&
+ !__wt_timestamp_iszero(s->read_timestamp) &&
+ __wt_timestamp_cmp(s->read_timestamp, ts) < 0)
+ __wt_timestamp_set(ts, s->read_timestamp);
+ WT_ORDERED_READ(session_cnt, conn->session_cnt);
+ for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) {
+ if (s->pinned_id == WT_TXN_NONE ||
+ __wt_timestamp_iszero(s->read_timestamp))
+ continue;
+ if (__wt_timestamp_cmp(s->read_timestamp, ts) < 0)
+ __wt_timestamp_set(ts, s->read_timestamp);
+ }
+ __wt_readunlock(session, &txn_global->rwlock);
+ } else
+ return (__wt_illegal_value(session, NULL));
+
+ return (0);
+}
+#endif
+
+/*
+ * __wt_txn_global_query_timestamp --
+ * Query a timestamp.
+ */
+int
+__wt_txn_global_query_timestamp(
+ WT_SESSION_IMPL *session, char *hex_timestamp, const char *cfg[])
+{
+#ifdef HAVE_TIMESTAMPS
+ WT_ITEM hexts;
+ wt_timestamp_t ts;
+ size_t len;
+ uint8_t *tsp;
+
+ WT_RET(__txn_global_query_timestamp(session, ts, cfg));
+
+ /* Avoid memory allocation: set up an item guaranteed large enough. */
+ hexts.data = hexts.mem = hex_timestamp;
+ hexts.memsize = 2 * WT_TIMESTAMP_SIZE + 1;
+ /* Trim leading zeros. */
+ for (tsp = ts, len = WT_TIMESTAMP_SIZE;
+ len > 0 && *tsp == 0;
+ ++tsp, --len)
+ ;
+ WT_RET(__wt_raw_to_hex(session, tsp, len, &hexts));
+ return (0);
+#else
+ WT_UNUSED(session);
+ WT_UNUSED(hex_timestamp);
+ WT_UNUSED(cfg);
+
+ return (ENOTSUP);
+#endif
+}
+
+#ifdef HAVE_TIMESTAMPS
+/*
+ * __wt_txn_update_pinned_timestamp --
+ * Update the pinned timestamp (the oldest timestamp that has to be
+ * maintained for current or future readers).
+ */
+int
+__wt_txn_update_pinned_timestamp(WT_SESSION_IMPL *session)
+{
+ WT_DECL_RET;
+ WT_TXN_GLOBAL *txn_global;
+ wt_timestamp_t active_timestamp, oldest_timestamp, pinned_timestamp;
+ const char *query_cfg[] = { WT_CONFIG_BASE(session,
+ WT_CONNECTION_query_timestamp), "get=oldest_reader", NULL };
+
+ txn_global = &S2C(session)->txn_global;
+
+ /* Skip locking and scanning when the oldest timestamp is pinned. */
+ if (txn_global->oldest_is_pinned)
+ return (0);
+
+ __wt_readlock(session, &txn_global->rwlock);
+ __wt_timestamp_set(oldest_timestamp, txn_global->oldest_timestamp);
+ __wt_readunlock(session, &txn_global->rwlock);
+
+ /* Scan to find the global pinned timestamp. */
+ if ((ret = __txn_global_query_timestamp(
+ session, active_timestamp, query_cfg)) != 0)
+ return (ret == WT_NOTFOUND ? 0 : ret);
+
+ if (__wt_timestamp_cmp(oldest_timestamp, active_timestamp) < 0) {
+ __wt_timestamp_set(pinned_timestamp, oldest_timestamp);
+ } else
+ __wt_timestamp_set(pinned_timestamp, active_timestamp);
+
+ __wt_writelock(session, &txn_global->rwlock);
+ if (!txn_global->has_pinned_timestamp || __wt_timestamp_cmp(
+ txn_global->pinned_timestamp, pinned_timestamp) < 0) {
+ __wt_timestamp_set(
+ txn_global->pinned_timestamp, pinned_timestamp);
+ txn_global->has_pinned_timestamp = true;
+ txn_global->oldest_is_pinned = __wt_timestamp_cmp(
+ txn_global->pinned_timestamp,
+ txn_global->oldest_timestamp) == 0;
+ }
+ __wt_writeunlock(session, &txn_global->rwlock);
+
+ return (0);
+}
+#endif
+
+/*
+ * __wt_txn_global_set_timestamp --
+ * Set a global transaction timestamp.
+ */
+int
+__wt_txn_global_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[])
+{
+ WT_CONFIG_ITEM cval;
+
+ /*
+ * Look for a commit timestamp.
+ */
+ WT_RET(
+ __wt_config_gets_def(session, cfg, "oldest_timestamp", 0, &cval));
+ if (cval.len != 0) {
+#ifdef HAVE_TIMESTAMPS
+ WT_TXN_GLOBAL *txn_global;
+ wt_timestamp_t oldest_timestamp;
+
+ WT_RET(__wt_txn_parse_timestamp(
+ session, "oldest", oldest_timestamp, &cval));
+
+ /*
+ * This method can be called from multiple threads, check that
+ * we are moving the global oldest timestamp forwards.
+ */
+ txn_global = &S2C(session)->txn_global;
+ __wt_writelock(session, &txn_global->rwlock);
+ if (!txn_global->has_oldest_timestamp || __wt_timestamp_cmp(
+ txn_global->oldest_timestamp, oldest_timestamp) < 0) {
+ __wt_timestamp_set(
+ txn_global->oldest_timestamp, oldest_timestamp);
+ txn_global->has_oldest_timestamp = true;
+ txn_global->oldest_is_pinned = false;
+ }
+ __wt_writeunlock(session, &txn_global->rwlock);
+
+ WT_RET(__wt_txn_update_pinned_timestamp(session));
+#else
+ WT_RET_MSG(session, EINVAL, "oldest_timestamp requires a "
+ "version of WiredTiger built with timestamp support");
+#endif
+ }
+
+ return (0);
+}
+
+/*
+ * __wt_txn_set_timestamp --
+ * Set a transaction's timestamp.
+ */
+int
+__wt_txn_set_timestamp(WT_SESSION_IMPL *session, const char *cfg[])
+{
+ WT_CONFIG_ITEM cval;
+ WT_DECL_RET;
+
+ /*
+ * Look for a commit timestamp.
+ */
+ ret = __wt_config_gets(session, cfg, "commit_timestamp", &cval);
+ if (ret == 0 && cval.len != 0) {
+#ifdef HAVE_TIMESTAMPS
+ WT_TXN *txn = &session->txn;
+ WT_TXN_GLOBAL *txn_global = &S2C(session)->txn_global;
+ WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session);
+
+ WT_RET(__wt_txn_parse_timestamp(
+ session, "commit", txn->commit_timestamp, &cval));
+ if (!F_ISSET(txn, WT_TXN_HAS_TS_COMMIT)) {
+ __wt_writelock(session, &txn_global->rwlock);
+ __wt_timestamp_set(txn_state->commit_timestamp,
+ txn->commit_timestamp);
+ __wt_writeunlock(session, &txn_global->rwlock);
+ F_SET(txn, WT_TXN_HAS_TS_COMMIT);
+ }
+#else
+ WT_RET_MSG(session, EINVAL, "commit_timestamp requires a "
+ "version of WiredTiger built with timestamp support");
+#endif
+ }
+ WT_RET_NOTFOUND_OK(ret);
+
+ return (0);
+}
diff --git a/src/third_party/wiredtiger/test/checkpoint/checkpointer.c b/src/third_party/wiredtiger/test/checkpoint/checkpointer.c
index 3135caa8cad..c735c0360c2 100644
--- a/src/third_party/wiredtiger/test/checkpoint/checkpointer.c
+++ b/src/third_party/wiredtiger/test/checkpoint/checkpointer.c
@@ -96,15 +96,19 @@ real_checkpointer(void)
if ((ret = g.conn->open_session(g.conn, NULL, NULL, &session)) != 0)
return (log_print_err("conn.open_session", ret, 1));
- if (strncmp(g.checkpoint_name,
- "WiredTigerCheckpoint", strlen("WiredTigerCheckpoint")) == 0)
- checkpoint_config = NULL;
- else {
- testutil_check(__wt_snprintf(
- _buf, sizeof(_buf), "name=%s", g.checkpoint_name));
- checkpoint_config = _buf;
- }
while (g.running) {
+ if (WT_PREFIX_MATCH(g.checkpoint_name, "WiredTigerCheckpoint"))
+ strcpy(_buf, "");
+ else
+ testutil_check(__wt_snprintf(
+ _buf, sizeof(_buf), "name=%s", g.checkpoint_name));
+
+ if (g.use_timestamps && g.timestamp > 0)
+ testutil_check(__wt_snprintf(
+ _buf + strlen(_buf), sizeof(_buf) - strlen(_buf),
+ ",read_timestamp=%" PRIx64, g.timestamp));
+
+ checkpoint_config = strlen(_buf) > 0 ? _buf : NULL;
/* Execute a checkpoint */
if ((ret = session->checkpoint(
session, checkpoint_config)) != 0)
diff --git a/src/third_party/wiredtiger/test/checkpoint/smoke.sh b/src/third_party/wiredtiger/test/checkpoint/smoke.sh
index 39b1f428c2c..3cf0b62094f 100755
--- a/src/third_party/wiredtiger/test/checkpoint/smoke.sh
+++ b/src/third_party/wiredtiger/test/checkpoint/smoke.sh
@@ -6,6 +6,10 @@ set -e
echo "checkpoint: 3 mixed tables"
$TEST_WRAPPER ./t -T 3 -t m
+# Smoke-test timestamps
+echo "checkpoint: 3 mixed tables with timestamps"
+$TEST_WRAPPER ./t -T 3 -t m -s
+
# We are done unless long tests are enabled.
test "$TESTUTIL_ENABLE_LONG_TESTS" = "1" || exit 0
@@ -18,8 +22,14 @@ $TEST_WRAPPER ./t -T 6 -t l
echo "checkpoint: 6 mixed tables"
$TEST_WRAPPER ./t -T 6 -t m
+echo "checkpoint: 6 mixed tables with timestamps"
+$TEST_WRAPPER ./t -T 6 -t m -s
+
echo "checkpoint: 6 row-store tables"
$TEST_WRAPPER ./t -T 6 -t r
echo "checkpoint: 6 row-store tables, named checkpoint"
$TEST_WRAPPER ./t -c 'TeSt' -T 6 -t r
+
+echo "checkpoint: 6 row-store tables, named checkpoint"
+$TEST_WRAPPER ./t -c 'TeSt' -T 6 -t r -s
diff --git a/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.c b/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.c
index cfe5ef1bad4..2ee5aa912e4 100644
--- a/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.c
+++ b/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.c
@@ -65,7 +65,7 @@ main(int argc, char *argv[])
runs = 1;
while ((ch = __wt_getopt(
- progname, argc, argv, "c:C:h:k:l:n:r:t:T:W:")) != EOF)
+ progname, argc, argv, "C:c:h:k:l:n:r:sT:t:W:")) != EOF)
switch (ch) {
case 'c':
g.checkpoint_name = __wt_optarg;
@@ -92,6 +92,11 @@ main(int argc, char *argv[])
case 'r': /* runs */
runs = atoi(__wt_optarg);
break;
+ case 's':
+#ifdef HAVE_TIMESTAMPS
+ g.use_timestamps = true;
+#endif
+ break;
case 't':
switch (__wt_optarg[0]) {
case 'c':
@@ -320,19 +325,25 @@ type_to_string(table_type type)
static int
usage(void)
{
+ // progname, argc, argv, "c:C:h:k:l:n:r:t:T:W:")) != EOF)
+
fprintf(stderr,
"usage: %s "
- "[-S] [-C wiredtiger-config] [-k keys] [-l log]\n\t"
- "[-n ops] [-c checkpoint] [-r runs] [-t f|r|v] [-W workers]\n",
+ "[-C wiredtiger-config] [-c checkpoint] [-h home] [-k keys]\n\t"
+ "[-l log] [-n ops] [-r runs] [-s] [-t f|r|v] [-T table-config]\n\t"
+ "[-W workers]\n",
progname);
fprintf(stderr, "%s",
"\t-C specify wiredtiger_open configuration arguments\n"
"\t-c checkpoint name to used named checkpoints\n"
+ "\t-h set a database home directory\n"
"\t-k set number of keys to load\n"
"\t-l specify a log file\n"
"\t-n set number of operations each thread does\n"
"\t-r set number of runs (0 for continuous)\n"
+ "\t-s enable transaction timestamps\n"
"\t-t set a file type ( col | mix | row | lsm )\n"
+ "\t-T specify a table configuration\n"
"\t-W set number of worker threads\n");
return (EXIT_FAILURE);
}
diff --git a/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.h b/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.h
index 36551211b7e..3737131eb01 100644
--- a/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.h
+++ b/src/third_party/wiredtiger/test/checkpoint/test_checkpoint.h
@@ -57,6 +57,8 @@ typedef struct {
WT_CONNECTION *conn; /* WiredTiger connection */
u_int nkeys; /* Keys to load */
u_int nops; /* Operations per thread */
+ uint64_t timestamp; /* Current timestamp */
+ bool use_timestamps; /* Test with timestamps */
FILE *logfp; /* Message log file. */
int nworkers; /* Number workers configured */
int ntables; /* Number tables configured */
diff --git a/src/third_party/wiredtiger/test/checkpoint/workers.c b/src/third_party/wiredtiger/test/checkpoint/workers.c
index 724475926ee..8d6d2c53188 100644
--- a/src/third_party/wiredtiger/test/checkpoint/workers.c
+++ b/src/third_party/wiredtiger/test/checkpoint/workers.c
@@ -166,8 +166,10 @@ real_worker(void)
WT_CURSOR **cursors;
WT_SESSION *session;
WT_RAND_STATE rnd;
+ uint64_t ts;
u_int i, keyno;
int j, ret, t_ret;
+ char config_buf[64];
ret = t_ret = 0;
@@ -202,8 +204,23 @@ real_worker(void)
break;
}
if (ret == 0) {
- if ((ret = session->commit_transaction(
- session, NULL)) != 0) {
+ if (g.use_timestamps) {
+ ts = __wt_atomic_add64(&g.timestamp, 1);
+ if (ts > 100 && ts % 100 == 0) {
+ testutil_check(__wt_snprintf(
+ config_buf, sizeof(config_buf),
+ "oldest_timestamp=%" PRIx64,
+ ts - 100));
+ testutil_check(g.conn->set_timestamp(
+ g.conn, config_buf));
+ }
+ testutil_check(__wt_snprintf(
+ config_buf, sizeof(config_buf),
+ "commit_timestamp=%" PRIx64, ts));
+ }
+
+ if ((ret = session->commit_transaction(session,
+ g.use_timestamps ? config_buf : NULL)) != 0) {
(void)log_print_err(
"real_worker:commit_transaction", ret, 1);
goto err;
diff --git a/src/third_party/wiredtiger/test/csuite/Makefile.am b/src/third_party/wiredtiger/test/csuite/Makefile.am
index f2b4fcacdc8..0b117a6588b 100644
--- a/src/third_party/wiredtiger/test/csuite/Makefile.am
+++ b/src/third_party/wiredtiger/test/csuite/Makefile.am
@@ -57,6 +57,9 @@ noinst_PROGRAMS += test_wt3135_search_near_collator
test_wt3184_dup_index_collator_SOURCES = wt3184_dup_index_collator/main.c
noinst_PROGRAMS += test_wt3184_dup_index_collator
+test_wt3363_checkpoint_op_races_SOURCES = wt3363_checkpoint_op_races/main.c
+noinst_PROGRAMS += test_wt3363_checkpoint_op_races
+
test_rwlock_SOURCES = rwlock/main.c
noinst_PROGRAMS += test_rwlock
diff --git a/src/third_party/wiredtiger/test/csuite/rwlock/main.c b/src/third_party/wiredtiger/test/csuite/rwlock/main.c
index 04813182478..3610953a7eb 100644
--- a/src/third_party/wiredtiger/test/csuite/rwlock/main.c
+++ b/src/third_party/wiredtiger/test/csuite/rwlock/main.c
@@ -55,7 +55,8 @@ main(int argc, char *argv[])
pthread_t dump_id, id[MAX_THREADS];
int i;
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt2246_col_append/main.c b/src/third_party/wiredtiger/test/csuite/wt2246_col_append/main.c
index de7916b6859..c71edf6a0a9 100644
--- a/src/third_party/wiredtiger/test/csuite/wt2246_col_append/main.c
+++ b/src/third_party/wiredtiger/test/csuite/wt2246_col_append/main.c
@@ -101,7 +101,8 @@ main(int argc, char *argv[])
uint64_t i, id;
char buf[100];
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt2323_join_visibility/main.c b/src/third_party/wiredtiger/test/csuite/wt2323_join_visibility/main.c
index a3ab8c153ed..89f9eeefb69 100644
--- a/src/third_party/wiredtiger/test/csuite/wt2323_join_visibility/main.c
+++ b/src/third_party/wiredtiger/test/csuite/wt2323_join_visibility/main.c
@@ -92,7 +92,8 @@ main(int argc, char *argv[])
TEST_OPTS *opts, _opts;
const char *tablename;
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt2535_insert_race/main.c b/src/third_party/wiredtiger/test/csuite/wt2535_insert_race/main.c
index 6ea599fc118..92e69c5920c 100644
--- a/src/third_party/wiredtiger/test/csuite/wt2535_insert_race/main.c
+++ b/src/third_party/wiredtiger/test/csuite/wt2535_insert_race/main.c
@@ -49,7 +49,8 @@ main(int argc, char *argv[])
uint64_t current_value;
int i;
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt2834_join_bloom_fix/main.c b/src/third_party/wiredtiger/test/csuite/wt2834_join_bloom_fix/main.c
index 74128406a8e..8625db9b92b 100644
--- a/src/third_party/wiredtiger/test/csuite/wt2834_join_bloom_fix/main.c
+++ b/src/third_party/wiredtiger/test/csuite/wt2834_join_bloom_fix/main.c
@@ -59,7 +59,8 @@ main(int argc, char *argv[])
char flaguri[256];
char joinuri[256];
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt2853_perf/main.c b/src/third_party/wiredtiger/test/csuite/wt2853_perf/main.c
index 096bc64cf82..69e6b871dae 100644
--- a/src/third_party/wiredtiger/test/csuite/wt2853_perf/main.c
+++ b/src/third_party/wiredtiger/test/csuite/wt2853_perf/main.c
@@ -82,7 +82,8 @@ main(int argc, char *argv[])
int i, nfail;
const char *tablename;
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt2909_checkpoint_integrity/main.c b/src/third_party/wiredtiger/test/csuite/wt2909_checkpoint_integrity/main.c
index c93da4c1068..71ab7fda319 100644
--- a/src/third_party/wiredtiger/test/csuite/wt2909_checkpoint_integrity/main.c
+++ b/src/third_party/wiredtiger/test/csuite/wt2909_checkpoint_integrity/main.c
@@ -648,7 +648,8 @@ main(int argc, char *argv[])
uint64_t nresults;
const char *debugger;
- if (!testutil_enable_long_tests()) /* Ignore unless requested */
+ /* Ignore unless requested */
+ if (!testutil_is_flag_set("TESTUTIL_ENABLE_LONG_TESTS"))
return (EXIT_SUCCESS);
opts = &_opts;
diff --git a/src/third_party/wiredtiger/test/csuite/wt3363_checkpoint_op_races/main.c b/src/third_party/wiredtiger/test/csuite/wt3363_checkpoint_op_races/main.c
new file mode 100644
index 00000000000..5c9c3d96454
--- /dev/null
+++ b/src/third_party/wiredtiger/test/csuite/wt3363_checkpoint_op_races/main.c
@@ -0,0 +1,268 @@
+/*-
+ * Public Domain 2014-2017 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 "test_util.h"
+
+/*
+ * JIRA ticket reference: WT-3363
+ *
+ * Test case description: There are a number of operations that we run that we
+ * expect not to conflict with or block against a running checkpoint. This test
+ * aims to run repeated checkpoints in a thread, while running an assortment
+ * of operations that we expect to execute quickly on further threads. To
+ * ensure that we catch any blockages we introduce a very large delay into the
+ * checkpoint and measure that no operation takes 1/2 the length of this delay.
+ *
+ * Failure mode: We monitor the execution time of all operations and if we find
+ * any operation taking longer than 1/2 the delay time, we abort dumping a core
+ * file which can be used to determine what operation was blocked.
+ */
+void* do_checkpoints(void *);
+void* do_ops(void *);
+void* monitor(void *);
+
+/*
+ * Time delay to introduce into checkpoints in seconds. Should be at-least
+ * double the maximum time that any one of the operations should take. Currently
+ * this is set to 10 seconds and we expect no single operation to take longer
+ * than 5 seconds.
+ */
+#define MAX_EXECUTION_TIME 10
+#define N_THREADS 10
+
+/*
+ * Number of seconds to execute for. Initially set to 15 minutes, as we need to
+ * run long enough to be certain we have captured any blockages. In initial
+ * testing 5 minutes was enough to reproduce the issue, so we run for 3x that
+ * here to ensure we reproduce before declaring success.
+ */
+#define RUNTIME 900.0
+
+static WT_EVENT_HANDLER event_handler = {
+ handle_op_error,
+ handle_op_message,
+ NULL,
+ NULL
+};
+
+int
+main(int argc, char *argv[])
+{
+ TEST_PER_THREAD_OPTS thread_args[N_THREADS];
+ TEST_OPTS *opts, _opts;
+ pthread_t ckpt_thread, mon_thread, threads[N_THREADS];
+ int i;
+ bool diagnostic;
+
+#ifdef HAVE_DIAGNOSTIC
+ diagnostic = true;
+#else
+ diagnostic = false;
+#endif
+
+ /*
+ * This test should not run unless we have compiled with diagnostic
+ * support and the long tests flag is set. The test will fail when
+ * attempting to set the option to add the delays to checkpoints if
+ * diagnostic mode is not enable and runs for 15 minutes.
+ */
+ if (!testutil_is_flag_set("WT3363_CHECKPOINT_OP_RACES") || !diagnostic)
+ return (EXIT_SUCCESS);
+
+ opts = &_opts;
+ opts->unique_id = 0;
+ memset(opts, 0, sizeof(*opts));
+
+ testutil_check(testutil_parse_opts(argc, argv, opts));
+ testutil_make_work_dir(opts->home);
+
+ testutil_check(wiredtiger_open(opts->home, &event_handler,
+ "create,cache_size=1G,diagnostic_timing_stress=[checkpoint_slow]",
+ &opts->conn));
+
+ testutil_check(pthread_create(
+ &ckpt_thread, NULL, do_checkpoints, (void *)opts));
+
+ for (i = 0; i < N_THREADS; ++i) {
+ thread_args[i].testopts = opts;
+ thread_args[i].thread_counter = 0;
+ thread_args[i].threadnum = i;
+ testutil_check(pthread_create(
+ &threads[i], NULL, do_ops, (void *)&thread_args[i]));
+ }
+
+ /*
+ * Pass the whole array of thread arguments to the monitoring thread.
+ * This thread will need to monitor each threads counter to track if it
+ * is stuck.
+ */
+ testutil_check(
+ pthread_create(&mon_thread, NULL, monitor, &thread_args));
+
+ for (i = 0; i < N_THREADS; ++i)
+ testutil_check(pthread_join(threads[i], NULL));
+
+ testutil_check(pthread_join(mon_thread, NULL));
+
+ testutil_check(pthread_join(ckpt_thread, NULL));
+
+ printf("Success\n");
+
+ testutil_cleanup(opts);
+ return (EXIT_SUCCESS);
+}
+
+/*
+ * Function for repeatedly running checkpoint operations.
+ */
+void *
+do_checkpoints(void *_opts)
+{
+ TEST_OPTS *opts;
+ WT_SESSION *session;
+ time_t now, start;
+ int ret;
+
+ opts = (TEST_OPTS *)_opts;
+ (void)time(&start);
+ (void)time(&now);
+
+ while (difftime(now, start) < RUNTIME) {
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ if ((ret = session->checkpoint(session, "force")) != 0)
+ if (ret != EBUSY && ret != ENOENT)
+ testutil_die(ret, "session.checkpoint");
+
+ testutil_check(session->close(session, NULL));
+
+ /*
+ * A short sleep to let operations process and avoid back to
+ * back checkpoints locking up resources.
+ */
+ sleep(1);
+ (void)time(&now);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Function to monitor running operations and abort to dump core in the event
+ * that we catch an operation running long.
+ */
+void *
+monitor(void *args)
+{
+ TEST_PER_THREAD_OPTS *thread_args;
+ time_t now, start;
+ int ctr, i, last_ops[N_THREADS];
+
+ thread_args = (TEST_PER_THREAD_OPTS*)args;
+
+ (void)time(&start);
+ (void)time(&now);
+
+ memset(last_ops, 0, sizeof(int) + N_THREADS);
+
+ while (difftime(now, start) < RUNTIME) {
+
+ /*
+ * Checkpoints will run for slightly over MAX_EXECUTION_TIME.
+ * MAX_EXECUTION_TIME should always be long enough that we can
+ * complete any single operation in 1/2 that time.
+ */
+ sleep(MAX_EXECUTION_TIME/2);
+
+ for (i = 0; i < N_THREADS; i++) {
+ ctr = thread_args[i].thread_counter;
+
+ /* Ignore any threads which may not have started yet. */
+ if (ctr == 0)
+ continue;
+
+ /*
+ * We track how many operations each thread has done. If
+ * we have slept and the counter remains the same for a
+ * thread it is stuck and should drop a core so the
+ * cause of the hang can be investigated.
+ */
+ if (ctr != last_ops[i])
+ last_ops[i] = ctr;
+ else {
+ printf("Thread %d had a task running"
+ " for more than %d seconds\n",
+ i, MAX_EXECUTION_TIME/2);
+ abort();
+ }
+ }
+ (void)time(&now);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Worker thread. Executes random operations from the set of 6.
+ */
+void *
+do_ops(void *args)
+{
+ WT_RAND_STATE rnd;
+ time_t now, start;
+
+ __wt_random_init_seed(NULL, &rnd);
+ (void)time(&start);
+ (void)time(&now);
+
+ while (difftime(now, start) < RUNTIME) {
+ switch (__wt_random(&rnd) % 6) {
+ case 0:
+ op_bulk(args);
+ break;
+ case 1:
+ op_create(args);
+ break;
+ case 2:
+ op_cursor(args);
+ break;
+ case 3:
+ op_drop(args);
+ break;
+ case 4:
+ op_bulk_unique(args);
+ break;
+ case 5:
+ op_create_unique(args);
+ break;
+ }
+ (void)time(&now);
+ }
+
+ return (NULL);
+}
diff --git a/src/third_party/wiredtiger/test/format/config.h b/src/third_party/wiredtiger/test/format/config.h
index 3a41411e104..ea30986f453 100644
--- a/src/third_party/wiredtiger/test/format/config.h
+++ b/src/third_party/wiredtiger/test/format/config.h
@@ -306,6 +306,10 @@ static CONFIG c[] = {
"maximum time to run in minutes (default 20 minutes)",
C_IGNORE, 0, UINT_MAX, UINT_MAX, &g.c_timer, NULL },
+ { "transaction_timestamps", /* 10% */
+ "enable transaction timestamp support",
+ C_BOOL, 10, 0, 0, &g.c_txn_timestamps, NULL },
+
{ "transaction-frequency",
"percent operations done inside an explicit transaction",
0x0, 1, 100, 100, &g.c_txn_freq, NULL },
diff --git a/src/third_party/wiredtiger/test/format/format.h b/src/third_party/wiredtiger/test/format/format.h
index 602c1cc6d59..7860bb539ed 100644
--- a/src/third_party/wiredtiger/test/format/format.h
+++ b/src/third_party/wiredtiger/test/format/format.h
@@ -123,6 +123,8 @@ typedef struct {
WT_RAND_STATE rnd; /* Global RNG state */
+ uint64_t timestamp; /* Counter for timestamps. */
+
/*
* We have a list of records that are appended, but not yet "resolved",
* that is, we haven't yet incremented the g.rows value to reflect the
@@ -202,6 +204,7 @@ typedef struct {
uint32_t c_threads;
uint32_t c_timer;
uint32_t c_txn_freq;
+ uint32_t c_txn_timestamps;
uint32_t c_value_max;
uint32_t c_value_min;
uint32_t c_verify;
@@ -315,10 +318,17 @@ void wts_verify(const char *);
/*
* mmrand --
- * Return a random value between a min/max pair.
+ * Return a random value between a min/max pair, inclusive.
*/
static inline uint32_t
mmrand(WT_RAND_STATE *rnd, u_int min, u_int max)
{
- return (rng(rnd) % (((max) + 1) - (min)) + (min));
+ uint32_t v;
+ u_int range;
+
+ v = rng(rnd);
+ range = (max - min) + 1;
+ v %= range;
+ v += min;
+ return (v);
}
diff --git a/src/third_party/wiredtiger/test/format/ops.c b/src/third_party/wiredtiger/test/format/ops.c
index a5e761d53a4..76b1261e9ab 100644
--- a/src/third_party/wiredtiger/test/format/ops.c
+++ b/src/third_party/wiredtiger/test/format/ops.c
@@ -405,6 +405,41 @@ snap_check(WT_CURSOR *cursor,
}
/*
+ * commit_transaction --
+ * Commit a transaction
+ */
+static void
+commit_transaction(TINFO *tinfo, WT_SESSION *session)
+{
+ WT_CONNECTION *conn;
+ uint64_t ts;
+ char *commit_conf, config_buf[64];
+
+ conn = g.wts_conn;
+
+ if (g.c_txn_timestamps) {
+ ts = __wt_atomic_addv64(&g.timestamp, 1);
+
+ /* Periodically bump the oldest timestamp. */
+ if (ts > 100 && ts % 100 == 0) {
+ testutil_check(__wt_snprintf(
+ config_buf, sizeof(config_buf),
+ "oldest_timestamp=%" PRIx64, ts));
+ testutil_check(conn->set_timestamp(conn, config_buf));
+ }
+
+ testutil_check(__wt_snprintf(
+ config_buf, sizeof(config_buf),
+ "commit_timestamp=%" PRIx64, ts));
+ commit_conf = config_buf;
+ } else
+ commit_conf = NULL;
+
+ testutil_check(session->commit_transaction(session, commit_conf));
+ ++tinfo->commit;
+}
+
+/*
* ops --
* Per-thread operations.
*/
@@ -464,9 +499,7 @@ ops(void *arg)
*/
if (intxn &&
(tinfo->ops == ckpt_op || tinfo->ops == session_op)) {
- testutil_check(
- session->commit_transaction(session, NULL));
- ++tinfo->commit;
+ commit_transaction(tinfo, session);
intxn = false;
}
@@ -839,9 +872,7 @@ update_instead_of_insert:
*/
switch (rnd) {
case 1: case 2: case 3: case 4: /* 40% */
- testutil_check(
- session->commit_transaction(session, NULL));
- ++tinfo->commit;
+ commit_transaction(tinfo, session);
break;
case 5: /* 10% */
if (0) {
diff --git a/src/third_party/wiredtiger/test/format/wts.c b/src/third_party/wiredtiger/test/format/wts.c
index 673b65794f5..6bfec79436c 100644
--- a/src/third_party/wiredtiger/test/format/wts.c
+++ b/src/third_party/wiredtiger/test/format/wts.c
@@ -528,6 +528,7 @@ wts_verify(const char *tag)
WT_CONNECTION *conn;
WT_DECL_RET;
WT_SESSION *session;
+ char config_buf[64];
if (g.c_verify == 0)
return;
@@ -540,6 +541,17 @@ wts_verify(const char *tag)
(void)g.wt_api->msg_printf(g.wt_api, session,
"=============== verify start ===============");
+ if (g.c_txn_timestamps && g.timestamp > 0) {
+ /*
+ * Bump the oldest timestamp, otherwise recent operation will
+ * prevent verify from running.
+ */
+ testutil_check(__wt_snprintf(
+ config_buf, sizeof(config_buf),
+ "oldest_timestamp=%" PRIx64, g.timestamp));
+ testutil_check(conn->set_timestamp(conn, config_buf));
+ }
+
/* Session operations for LSM can return EBUSY. */
ret = session->verify(session, g.uri, "strict");
if (ret != 0 && !(ret == EBUSY && DATASOURCE("lsm")))
diff --git a/src/third_party/wiredtiger/test/suite/test_timestamp01.py b/src/third_party/wiredtiger/test/suite/test_timestamp01.py
new file mode 100644
index 00000000000..a934753488d
--- /dev/null
+++ b/src/third_party/wiredtiger/test/suite/test_timestamp01.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-2017 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.
+#
+# test_timestamp01.py
+# Timestamps: basic semantics
+#
+
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+
+def timestamp_str(t):
+ return '%x' % t
+
+class test_timestamp01(wttest.WiredTigerTestCase, suite_subprocess):
+ def test_timestamp_range(self):
+ if not wiredtiger.timestamp_build():
+ self.skipTest('requires a timestamp build')
+
+ # Zero is not permitted
+ self.session.begin_transaction()
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: self.session.commit_transaction(
+ 'commit_timestamp=' + timestamp_str(0)),
+ '/zero not permitted/')
+
+ # Too big is also not permitted
+ self.session.begin_transaction()
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: self.session.commit_transaction(
+ 'commit_timestamp=' + timestamp_str(1 << 100)),
+ '/too long/')
+
+ # One is okay, as is 2**64 - 1
+ self.session.begin_transaction()
+ self.session.commit_transaction(
+ 'commit_timestamp=' + timestamp_str(1))
+ self.session.begin_transaction()
+ self.session.commit_transaction(
+ 'commit_timestamp=' + timestamp_str(1 << 64 - 1))
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/src/third_party/wiredtiger/test/suite/test_timestamp02.py b/src/third_party/wiredtiger/test/suite/test_timestamp02.py
new file mode 100644
index 00000000000..0ad007ec8e2
--- /dev/null
+++ b/src/third_party/wiredtiger/test/suite/test_timestamp02.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-2017 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.
+#
+# test_timestamp02.py
+# Timestamps: basic semantics
+#
+
+import random
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+from wtscenario import make_scenarios
+
+def timestamp_str(t):
+ return '%x' % t
+
+def timestamp_ret_str(t):
+ s = timestamp_str(t)
+ if len(s) % 2 == 1:
+ s = '0' + s
+ return s
+
+class test_timestamp02(wttest.WiredTigerTestCase, suite_subprocess):
+ tablename = 'test_timestamp02'
+ uri = 'table:' + tablename
+
+ scenarios = make_scenarios([
+ ('col', dict(extra_config=',key_format=r')),
+ ('lsm', dict(extra_config=',type=lsm')),
+ ('row', dict(extra_config='')),
+ ])
+
+ conn_config = 'log=(enabled)'
+
+ # Check that a cursor (optionally started in a new transaction), sees the
+ # expected values.
+ def check(self, session, txn_config, expected):
+ if txn_config:
+ session.begin_transaction(txn_config)
+ c = session.open_cursor(self.uri, None)
+ actual = dict((k, v) for k, v in c if v != 0)
+ self.assertEqual(actual, expected)
+ # Search for the expected items as well as iterating
+ for k, v in expected.iteritems():
+ self.assertEqual(c[k], v, "for key " + str(k))
+ c.close()
+ if txn_config:
+ session.commit_transaction()
+
+ def test_basic(self):
+ if not wiredtiger.timestamp_build():
+ self.skipTest('requires a timestamp build')
+
+ self.session.create(self.uri,
+ 'key_format=i,value_format=i' + self.extra_config)
+ c = self.session.open_cursor(self.uri)
+
+ # Insert keys 1..100 each with timestamp=key, in some order
+ orig_keys = range(1, 101)
+ keys = orig_keys[:]
+ random.shuffle(keys)
+
+ for k in keys:
+ self.session.begin_transaction()
+ c[k] = 1
+ self.session.commit_transaction('commit_timestamp=' + timestamp_str(k))
+
+ # Now check that we see the expected state when reading at each
+ # timestamp
+ for i, t in enumerate(orig_keys):
+ self.check(self.session, 'read_timestamp=' + timestamp_str(t),
+ dict((k, 1) for k in orig_keys[:i+1]))
+
+ # Bump the oldest timestamp, we're not going back...
+ self.assertEqual(self.conn.query_timestamp(), timestamp_ret_str(100))
+ self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(100))
+
+ # Update them and retry.
+ random.shuffle(keys)
+ for k in keys:
+ self.session.begin_transaction()
+ c[k] = 2
+ self.session.commit_transaction('commit_timestamp=' + timestamp_str(k + 100))
+
+ for i, t in enumerate(orig_keys):
+ self.check(self.session, 'read_timestamp=' + timestamp_str(t + 100),
+ dict((k, (2 if j <= i else 1)) for j, k in enumerate(orig_keys)))
+
+ # Bump the oldest timestamp, we're not going back...
+ self.assertEqual(self.conn.query_timestamp(), timestamp_ret_str(200))
+ self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(200))
+
+ # Remove them and retry
+ random.shuffle(keys)
+ for k in keys:
+ self.session.begin_transaction()
+ del c[k]
+ self.session.commit_transaction('commit_timestamp=' + timestamp_str(k + 200))
+
+ for i, t in enumerate(orig_keys):
+ self.check(self.session, 'read_timestamp=' + timestamp_str(t + 200),
+ dict((k, 2) for k in orig_keys[i+1:]))
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/src/third_party/wiredtiger/test/utility/misc.c b/src/third_party/wiredtiger/test/utility/misc.c
index e119fef47f1..cb0e8ed29ff 100644
--- a/src/third_party/wiredtiger/test/utility/misc.c
+++ b/src/third_party/wiredtiger/test/utility/misc.c
@@ -128,7 +128,7 @@ testutil_clean_work_dir(const char *dir)
* Delete the existing work directory, then create a new one.
*/
void
-testutil_make_work_dir(char *dir)
+testutil_make_work_dir(const char *dir)
{
size_t len;
int ret;
@@ -166,20 +166,22 @@ testutil_cleanup(TEST_OPTS *opts)
}
/*
- * testutil_enable_long_tests --
- * Return if TESTUTIL_ENABLE_LONG_TESTS is set.
+ * testutil_is_flag_set --
+ * Return if an environment variable flag is set.
*/
bool
-testutil_enable_long_tests(void)
+testutil_is_flag_set(const char *flag)
{
const char *res;
bool enable_long_tests;
- if (__wt_getenv(NULL,
- "TESTUTIL_ENABLE_LONG_TESTS", &res) == WT_NOTFOUND)
+ if (__wt_getenv(NULL, flag, &res) == WT_NOTFOUND)
return (false);
- /* Accept anything other than "TESTUTIL_ENABLE_LONG_TESTS=0". */
+ /*
+ * This is a boolean test. So if the environment variable is set to any
+ * value other than 0, we return success.
+ */
enable_long_tests = res[0] != '0';
free((void *)res);
@@ -256,3 +258,26 @@ dstrndup(const char *str, size_t len)
memcpy(p, str, len);
return (p);
}
+
+/*
+ * example_setup --
+ * Set the program name, create a home directory for the example programs.
+ */
+const char *
+example_setup(int argc, char * const *argv)
+{
+ const char *home;
+
+ (void)argc; /* Unused variable */
+
+ (void)testutil_set_progname(argv);
+
+ /*
+ * Create a clean test directory for this run of the test program if the
+ * environment variable isn't already set (as is done by make check).
+ */
+ if ((home = getenv("WIREDTIGER_HOME")) == NULL)
+ home = "WT_HOME";
+ testutil_make_work_dir(home);
+ return (home);
+}
diff --git a/src/third_party/wiredtiger/test/utility/test_util.h b/src/third_party/wiredtiger/test/utility/test_util.h
index 9c67bde2457..f07fec98bfe 100644
--- a/src/third_party/wiredtiger/test/utility/test_util.h
+++ b/src/third_party/wiredtiger/test/utility/test_util.h
@@ -72,10 +72,21 @@ typedef struct {
bool running;
char *uri;
volatile uint64_t next_threadid;
+ uint64_t unique_id;
uint64_t max_inserted_id;
} TEST_OPTS;
/*
+ * A structure for the data specific to a single thread of those used by the
+ * group of threads defined below.
+ */
+typedef struct {
+ TEST_OPTS *testopts;
+ int threadnum;
+ int thread_counter;
+} TEST_PER_THREAD_OPTS;
+
+/*
* testutil_assert --
* Complain and quit if something isn't true.
*/
@@ -117,6 +128,20 @@ typedef struct {
} while (0)
/*
+ * error_check --
+ * Complain and quit if a function call fails. The same as testutil_check,
+ * but with a different name because it appears in the documentation.
+ */
+#define error_check(call) testutil_check(call)
+
+/*
+ * scan_end_check --
+ * Complain and quit if something isn't true. The same as testutil_assert,
+ * with a different name because it appears in the documentation.
+ */
+#define scan_end_check(a) testutil_assert(a)
+
+/*
* u64_to_string --
* Convert a uint64_t to a text string.
*
@@ -183,10 +208,25 @@ void *dmalloc(size_t);
void *drealloc(void *, size_t);
void *dstrdup(const void *);
void *dstrndup(const char *, size_t);
+const char *example_setup(int, char * const *);
+
+/*
+ * The functions below can generate errors that we wish to ignore. We have
+ * handler functions available for them here, to avoid making tests crash
+ * prematurely.
+ */
+int handle_op_error(WT_EVENT_HANDLER *, WT_SESSION *, int, const char *);
+int handle_op_message(WT_EVENT_HANDLER *, WT_SESSION *, const char *);
+void *op_bulk(void *);
+void *op_bulk_unique(void *);
+void *op_cursor(void *);
+void *op_create(void *);
+void *op_create_unique(void *);
+void *op_drop(void *);
void testutil_clean_work_dir(const char *);
void testutil_cleanup(TEST_OPTS *);
-bool testutil_enable_long_tests(void);
-void testutil_make_work_dir(char *);
+bool testutil_is_flag_set(const char *);
+void testutil_make_work_dir(const char *);
int testutil_parse_opts(int, char * const *, TEST_OPTS *);
void testutil_work_dir_from_path(char *, size_t, const char *);
void *thread_append(void *);
diff --git a/src/third_party/wiredtiger/test/utility/thread.c b/src/third_party/wiredtiger/test/utility/thread.c
index 08f49c54c5e..4c5202016a5 100644
--- a/src/third_party/wiredtiger/test/utility/thread.c
+++ b/src/third_party/wiredtiger/test/utility/thread.c
@@ -140,3 +140,285 @@ thread_prev(void *arg)
testutil_check(session->close(session, NULL));
return (NULL);
}
+
+/*
+ * Below are a series of functions originally designed for test/fops. These
+ * threads perform a series of simple API access calls, such as opening and
+ * closing sessions and cursors. These functions require use of the
+ * TEST_PER_THREAD_OPTS structure in test_util.h. Additionally there are two
+ * event handler functions that should be used to suppress "expected" errors
+ * that these functions generate. An example of the use of these functions and
+ * structures is in the csuite test wt3363_checkpoint_op_races.
+ */
+
+/*
+ * Handle errors that generated by series of functions below that we can safely
+ * ignore.
+ */
+int
+handle_op_error(WT_EVENT_HANDLER *handler,
+ WT_SESSION *session, int error, const char *errmsg)
+{
+ (void)(handler);
+ (void)(session);
+
+ /*
+ * Ignore complaints about missing files. It's unlikely but possible
+ * that checkpoints and cursor open operations can return this due to
+ * the sequencing of the various ops.
+ */
+ if (error == ENOENT)
+ return (0);
+
+ /* Ignore complaints about failure to open bulk cursors. */
+ if (strstr(
+ errmsg, "bulk-load is only supported on newly created") != NULL)
+ return (0);
+
+ return (fprintf(stderr, "%s\n", errmsg) < 0 ? -1 : 0);
+}
+
+/*
+ * Handle messages generated by the functions below that we can safely ignore.
+ */
+int
+handle_op_message(WT_EVENT_HANDLER *handler,
+ WT_SESSION *session, const char *message)
+{
+ (void)(handler);
+ (void)(session);
+
+ /* Ignore messages about failing to create forced checkpoints. */
+ if (strstr(message, "forced or named checkpoint") != NULL)
+ return (0);
+
+ return (printf("%s\n", message) < 0 ? -1 : 0);
+}
+
+/*
+ * Create a table and open a bulk cursor on it.
+ */
+void *
+op_bulk(void *arg)
+{
+ TEST_OPTS *opts;
+ TEST_PER_THREAD_OPTS *args;
+ WT_CURSOR *c;
+ WT_SESSION *session;
+ int ret;
+
+ args = (TEST_PER_THREAD_OPTS *)arg;
+ opts = args->testopts;
+
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ if ((ret = session->create(session, opts->uri, NULL)) != 0)
+ if (ret != EEXIST && ret != EBUSY)
+ testutil_die(ret, "session.create");
+
+ if (ret == 0) {
+ __wt_yield();
+ if ((ret = session->open_cursor(session,
+ opts->uri, NULL, "bulk,checkpoint_wait=false", &c)) == 0) {
+ testutil_check(c->close(c));
+ } else if (ret != ENOENT && ret != EBUSY && ret != EINVAL)
+ testutil_die(ret, "session.open_cursor bulk");
+ }
+
+ testutil_check(session->close(session, NULL));
+ args->thread_counter++;
+
+ return (NULL);
+}
+
+/*
+ * Create a guaranteed unique table and open and close a bulk cursor on it.
+ */
+void *
+op_bulk_unique(void *arg)
+{
+ TEST_OPTS *opts;
+ TEST_PER_THREAD_OPTS *args;
+ WT_CURSOR *c;
+ WT_RAND_STATE rnd;
+ WT_SESSION *session;
+ int ret;
+ char new_uri[64];
+
+ args = (TEST_PER_THREAD_OPTS *)arg;
+ opts = args->testopts;
+ __wt_random_init_seed(NULL, &rnd);
+
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ /* Generate a unique object name. */
+ testutil_check(__wt_snprintf(
+ new_uri, sizeof(new_uri), "%s.%u",
+ opts->uri, __wt_atomic_add64(&opts->unique_id, 1)));
+ testutil_check(session->create(session, new_uri, NULL));
+
+ __wt_yield();
+
+ /*
+ * Opening a bulk cursor may have raced with a forced checkpoint
+ * which created a checkpoint of the empty file, and triggers an EINVAL.
+ */
+ if ((ret = session->open_cursor(
+ session, new_uri, NULL, "bulk,checkpoint_wait=false", &c)) == 0) {
+ testutil_check(c->close(c));
+ } else if (ret != EINVAL && ret != EBUSY)
+ testutil_die(ret,
+ "session.open_cursor bulk unique: %s", new_uri);
+
+ while ((ret = session->drop(session, new_uri, __wt_random(&rnd) & 1 ?
+ "force,checkpoint_wait=false" : "checkpoint_wait=false")) != 0)
+ if (ret != EBUSY)
+ testutil_die(ret, "session.drop: %s", new_uri);
+ else
+ /*
+ * The EBUSY is expected when we run with
+ * checkpoint_wait set to false, so we increment the
+ * counter while in this loop to avoid false positives.
+ */
+ args->thread_counter++;
+
+ testutil_check(session->close(session, NULL));
+ args->thread_counter++;
+
+ return (NULL);
+}
+
+/*
+ * Open and close cursor on a table.
+ */
+void *
+op_cursor(void *arg)
+{
+ TEST_OPTS *opts;
+ TEST_PER_THREAD_OPTS *args;
+ WT_SESSION *session;
+ WT_CURSOR *cursor;
+ int ret;
+
+ args = (TEST_PER_THREAD_OPTS *)arg;
+ opts = args->testopts;
+
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ if ((ret = session->open_cursor(
+ session, opts->uri, NULL, NULL, &cursor)) != 0) {
+ if (ret != ENOENT && ret != EBUSY)
+ testutil_die(ret, "session.open_cursor");
+ } else
+ testutil_check(cursor->close(cursor));
+
+ testutil_check(session->close(session, NULL));
+ args->thread_counter++;
+
+ return (NULL);
+}
+
+/*
+ * Create a table.
+ */
+void *
+op_create(void *arg)
+{
+ TEST_OPTS *opts;
+ TEST_PER_THREAD_OPTS *args;
+ WT_SESSION *session;
+ int ret;
+
+ args = (TEST_PER_THREAD_OPTS *)arg;
+ opts = args->testopts;
+
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ if ((ret = session->create(session, opts->uri, NULL)) != 0)
+ if (ret != EEXIST && ret != EBUSY)
+ testutil_die(ret, "session.create");
+
+ testutil_check(session->close(session, NULL));
+ args->thread_counter++;
+
+ return (NULL);
+}
+
+/*
+ * Create and drop a unique guaranteed table.
+ */
+void *
+op_create_unique(void *arg)
+{
+ TEST_OPTS *opts;
+ TEST_PER_THREAD_OPTS *args;
+ WT_RAND_STATE rnd;
+ WT_SESSION *session;
+ int ret;
+ char new_uri[64];
+
+ args = (TEST_PER_THREAD_OPTS *)arg;
+ opts = args->testopts;
+ __wt_random_init_seed(NULL, &rnd);
+
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ /* Generate a unique object name. */
+ testutil_check(__wt_snprintf(
+ new_uri, sizeof(new_uri), "%s.%u",
+ opts->uri, __wt_atomic_add64(&opts->unique_id, 1)));
+ testutil_check(session->create(session, new_uri, NULL));
+
+ __wt_yield();
+ while ((ret = session->drop(session, new_uri, __wt_random(&rnd) & 1 ?
+ "force,checkpoint_wait=false" : "checkpoint_wait=false")) != 0)
+ if (ret != EBUSY)
+ testutil_die(ret, "session.drop: %s", new_uri);
+ else
+ /*
+ * The EBUSY is expected when we run with
+ * checkpoint_wait set to false, so we increment the
+ * counter while in this loop to avoid false positives.
+ */
+ args->thread_counter++;
+
+ testutil_check(session->close(session, NULL));
+ args->thread_counter++;
+
+ return (NULL);
+}
+
+/*
+ * Drop a table.
+ */
+void *
+op_drop(void *arg)
+{
+ TEST_PER_THREAD_OPTS *args;
+ TEST_OPTS *opts;
+ WT_RAND_STATE rnd;
+ WT_SESSION *session;
+ int ret;
+
+ args = (TEST_PER_THREAD_OPTS *)arg;
+ opts = args->testopts;
+ __wt_random_init_seed(NULL, &rnd);
+
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ if ((ret = session->drop(session, opts->uri, __wt_random(&rnd) & 1 ?
+ "force,checkpoint_wait=false" : "checkpoint_wait=false")) != 0)
+ if (ret != ENOENT && ret != EBUSY)
+ testutil_die(ret, "session.drop");
+
+ testutil_check(session->close(session, NULL));
+ args->thread_counter++;
+
+ return (NULL);
+}
diff --git a/src/third_party/wiredtiger/test/windows/windows_shim.h b/src/third_party/wiredtiger/test/windows/windows_shim.h
index 88b707f9ad9..ad9de676deb 100644
--- a/src/third_party/wiredtiger/test/windows/windows_shim.h
+++ b/src/third_party/wiredtiger/test/windows/windows_shim.h
@@ -43,6 +43,8 @@
#define snprintf __wt_snprintf
#endif
+#define strcasecmp stricmp
+
/*
* Emulate <sys/stat.h>
*/