diff options
author | Alex Gorrod <alexander.gorrod@mongodb.com> | 2017-06-29 11:38:10 +1000 |
---|---|---|
committer | Alex Gorrod <alexander.gorrod@mongodb.com> | 2017-06-29 11:40:58 +1000 |
commit | 690302a49b61d5be3f4dcc285921eb362648055c (patch) | |
tree | d0bac8380e27a4ed7a38b9c82fc2996af87b2845 | |
parent | a72d5e357fc0e8b31e705cba539762cd79093773 (diff) | |
download | mongo-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
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, ¤t_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, ¤t_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> */ |