diff options
author | Ramon Fernandez <ramon@mongodb.com> | 2016-01-27 17:17:17 -0500 |
---|---|---|
committer | Ramon Fernandez <ramon@mongodb.com> | 2016-01-27 17:17:21 -0500 |
commit | 90118b147a6943b19dc929862a11071538db1438 (patch) | |
tree | d1e2c409595332174953e7dbe2db262935d89ae5 /src/third_party/wiredtiger/examples | |
parent | b8cad6a59cbce2831e69e6b94f9544d83d6e00b0 (diff) | |
download | mongo-90118b147a6943b19dc929862a11071538db1438.tar.gz |
Import wiredtiger-wiredtiger-2.7.0-505-g7fea169.tar.gz from wiredtiger branch mongodb-3.4
ref: 44463c5..7fea169
WT-2355 Fix minor scratch buffer usage in logging.
WT-2348 xargs -P isn't portable
WT-2347 Java: schema format edge cases
WT-2344 OS X compiler warning
WT-2342 Enhance wtperf to support background create and drop operations
WT-2340 Add logging guarantee assertions, whitespace
WT-2339 format post-rebalance verify failure (stress run #11586)
WT-2338 Disable using pre-allocated log files when backup cursor is open
WT-2335 NULL pointer crash in config_check_search with invalid configuration string
WT-2333 Add a flag so drop doesn't block
WT-2332 Bug in logging write-no-sync mode
WT-2331 Checking of search() result for reference cursors before join()
WT-2328 schema drop does direct unlink, it should use a block manager interface.
WT-2326 Change WTPERF to use new memory allocation functions instead of the standard
WT-2321 WT-2321: race between eviction and worker threads on the eviction queue
WT-2320 Only check copyright when cutting releases
WT-2316 stress test failure: WT_CURSOR.prev out-of-order returns
WT-2314 page-swap error handling is inconsistent
WT-2313 sweep-server: conn_dhandle.c, 610: dhandle != conn->cache->evict_file_next
WT-2312 re-creating a deleted column-store page can corrupt the in-memory tree
WT-2308 custom extractor for ref_cursors in join cursor
WT-2305 Fix coverity scan issues on 23/12/2015
WT-2296 New log algorithm needs improving for sync/flush settings
WT-2295 WT_SESSION.create does a full-scan of the main table
WT-2287 WT_SESSION.rebalance
WT-2275 broken DB after application crash
WT-2267 Improve wtperf throttling implementation to provide steady load
WT-2247 variable-length column-store in-memory page splits
WT-2242 WiredTiger treats dead trees the same as other trees in eviction
WT-2142 Connection cleanup in Python tests
WT-2073 metadata cleanups
WT-1801 Add a directory sync after rollback of a WT_SESSION::rename operation
WT-1517 schema format edge cases
SERVER-22064 Coverity analysis defect 77699: Unchecked return value
SERVER-21619 sys-perf: WT crash during core_workloads_WT execution
Diffstat (limited to 'src/third_party/wiredtiger/examples')
34 files changed, 9276 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/examples/c/Makefile.am b/src/third_party/wiredtiger/examples/c/Makefile.am new file mode 100644 index 00000000000..587204efff1 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/Makefile.am @@ -0,0 +1,38 @@ +LDADD = $(top_builddir)/libwiredtiger.la +AM_CPPFLAGS = -I$(top_srcdir)/src/include + +noinst_PROGRAMS = \ + ex_access \ + ex_all \ + ex_async \ + ex_backup \ + ex_call_center \ + ex_config \ + ex_config_parse \ + ex_cursor \ + ex_data_source \ + ex_encrypt \ + ex_extending \ + ex_extractor \ + ex_hello \ + ex_log \ + ex_pack \ + ex_process \ + ex_schema \ + ex_scope \ + ex_stat \ + ex_sync \ + ex_thread + +ex_encrypt_LDFLAGS = -rdynamic + +# The examples can be run with no arguments as simple smoke tests +TESTS = $(noinst_PROGRAMS) + +AM_TESTS_ENVIRONMENT = WIREDTIGER_HOME=`mktemp -d WT_HOME.XXXX` ; export WIREDTIGER_HOME ; rm -rf $$WIREDTIGER_HOME ; mkdir $$WIREDTIGER_HOME ; + +# Inject valgrind or similar +LOG_COMPILER = $(TEST_WRAPPER) + +clean-local: + rm -rf WT_HOME* *.core backup_full.* backup_incr.* diff --git a/src/third_party/wiredtiger/examples/c/ex_access.c b/src/third_party/wiredtiger/examples/c/ex_access.c new file mode 100644 index 00000000000..cc42982617b --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_access.c @@ -0,0 +1,99 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_access.c + * demonstrates how to create and access a simple table. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <wiredtiger.h> + +static const char *home; + +int +main(void) +{ + /*! [access example connection] */ + WT_CONNECTION *conn; + WT_CURSOR *cursor; + WT_SESSION *session; + 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, wiredtiger_strerror(ret)); + return (ret); + } + /*! [access example connection] */ + + /*! [access example table create] */ + ret = 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); + /*! [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); + /*! [access example cursor insert] */ + + /*! [access example cursor list] */ + ret = cursor->reset(cursor); /* Restart the scan. */ + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &key); + ret = cursor->get_value(cursor, &value); + + printf("Got record: %s : %s\n", key, value); + } + /*! [access example cursor list] */ + + /*! [access example close] */ + ret = conn->close(conn, NULL); + /*! [access example close] */ + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_all.c b/src/third_party/wiredtiger/examples/c/ex_all.c new file mode 100644 index 00000000000..f7ee857a7c7 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_all.c @@ -0,0 +1,1226 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_all.c + * Containing a call to every method in the WiredTiger API. + * + * It doesn't do anything very useful, just demonstrates how to call each + * method. This file is used to populate the API reference with code + * fragments. + */ + +#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; + +int +cursor_ops(WT_SESSION *session) +{ + WT_CURSOR *cursor; + int ret; + + /*! [Open a cursor] */ + ret = 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); + /*! [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); + cursor->set_key(cursor, key); + ret = cursor->search(cursor); + + /* Duplicate the cursor. */ + ret = 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); + 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); + /*! [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); + /*! [boolean configuration string example] */ + } + + { + /*! [open a named checkpoint] */ + ret = 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); + /*! [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); + /*! [Get the cursor's string key] */ + } + + { + /*! [Set the cursor's string key] */ + /* Set the cursor's string key. */ + const char *key = "another key"; + cursor->set_key(cursor, key); + /*! [Set the cursor's string key] */ + } + + { + /*! [Get the cursor's record number key] */ + uint64_t recno; /* Get the cursor's record number key. */ + ret = cursor->get_key(cursor, &recno); + /*! [Get the cursor's record number key] */ + } + + { + /*! [Set the cursor's record number key] */ + uint64_t recno = 37; /* Set the cursor's record number key. */ + cursor->set_key(cursor, recno); + /*! [Set the cursor's record number key] */ + } + + { + /*! [Get the cursor's composite key] */ + /* Get the cursor's "SiH" format composite key. */ + const char *first; + int32_t second; + uint16_t third; + ret = cursor->get_key(cursor, &first, &second, &third); + /*! [Get the cursor's composite key] */ + } + + { + /*! [Set the cursor's composite key] */ + /* Set the cursor's "SiH" format composite key. */ + cursor->set_key(cursor, "first", (int32_t)5, (uint16_t)7); + /*! [Set the cursor's composite key] */ + } + + { + /*! [Get the cursor's string value] */ + const char *value; /* Get the cursor's string value. */ + ret = cursor->get_value(cursor, &value); + /*! [Get the cursor's string value] */ + } + + { + /*! [Set the cursor's string value] */ + /* Set the cursor's string value. */ + const char *value = "another value"; + cursor->set_value(cursor, value); + /*! [Set the cursor's string value] */ + } + + { + /*! [Get the cursor's raw value] */ + WT_ITEM value; /* Get the cursor's raw value. */ + ret = cursor->get_value(cursor, &value); + /*! [Get the cursor's raw value] */ + } + + { + /*! [Set the cursor's raw value] */ + WT_ITEM value; /* Set the cursor's raw value. */ + value.data = "another value"; + value.size = strlen("another value"); + cursor->set_value(cursor, &value); + /*! [Set the cursor's raw value] */ + } + + /*! [Return the next record] */ + ret = cursor->next(cursor); + /*! [Return the next record] */ + + /*! [Return the previous record] */ + ret = cursor->prev(cursor); + /*! [Return the previous record] */ + + /*! [Reset the cursor] */ + ret = cursor->reset(cursor); + /*! [Reset the cursor] */ + + { + WT_CURSOR *other = NULL; + /*! [Cursor comparison] */ + int compare; + ret = cursor->compare(cursor, other, &compare); + if (compare == 0) { + /* Cursors reference the same key */ + } else if (compare < 0) { + /* Cursor key less than other key */ + } else if (compare > 0) { + /* Cursor key greater than other key */ + } + /*! [Cursor comparison] */ + } + + { + WT_CURSOR *other = NULL; + /*! [Cursor equality] */ + int equal; + ret = cursor->equals(cursor, other, &equal); + if (equal) { + /* Cursors reference the same key */ + } else { + /* Cursors don't reference the same key */ + } + /*! [Cursor equality] */ + } + + { + /*! [Search for an exact match] */ + const char *key = "some key"; + cursor->set_key(cursor, key); + ret = cursor->search(cursor); + /*! [Search for an exact match] */ + } + + ret = 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); + cursor->set_key(cursor, key); + cursor->set_value(cursor, value); + ret = cursor->insert(cursor); + /*! [Insert a new record or overwrite an existing record] */ + } + + { + /*! [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); + cursor->set_key(cursor, key); + cursor->set_value(cursor, value); + ret = cursor->insert(cursor); + /*! [Insert a new record and fail if the record exists] */ + } + + { + /*! [Insert a new record and assign a record number] */ + /* 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); + cursor->set_value(cursor, value); + ret = cursor->insert(cursor); + if (ret == 0) + ret = cursor->get_key(cursor, &recno); + /*! [Insert a new record and assign a record number] */ + } + + { + /*! [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); + cursor->set_key(cursor, key); + cursor->set_value(cursor, value); + ret = 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); + cursor->set_key(cursor, key); + cursor->set_value(cursor, value); + ret = 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); + cursor->set_key(cursor, key); + ret = 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); + cursor->set_key(cursor, key); + ret = cursor->remove(cursor); + /*! [Remove a record and fail if DNE] */ + } + + { + /*! [Display an error] */ + const char *key = "non-existent key"; + cursor->set_key(cursor, key); + if ((ret = cursor->remove(cursor)) != 0) { + fprintf(stderr, + "cursor.remove: %s\n", + cursor->session->strerror(cursor->session, ret)); + return (ret); + } + /*! [Display an error] */ + } + + { + /*! [Display an error thread safe] */ + const char *key = "non-existent key"; + cursor->set_key(cursor, key); + if ((ret = cursor->remove(cursor)) != 0) { + fprintf(stderr, + "cursor.remove: %s\n", session->strerror(session, ret)); + return (ret); + } + /*! [Display an error thread safe] */ + } + + /*! [Close the cursor] */ + ret = cursor->close(cursor); + /*! [Close the cursor] */ + + return (ret); +} + +int +cursor_search_near(WT_CURSOR *cursor) +{ + int exact, ret; + const char *key = "some key"; + + /*! [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 */ + } + } + /*! [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) { + /* include first key returned in the scan */ + } + + while ((ret = cursor->next(cursor)) == 0) { + /* the rest of the scan */ + } + /*! [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) { + /* include first key returned in the scan */ + } + + while ((ret = cursor->prev(cursor)) == 0) { + /* the rest of the scan */ + } + /*! [Backward scan less than] */ + + return (ret); +} + +int +checkpoint_ops(WT_SESSION *session) +{ + int ret; + + /*! [Checkpoint examples] */ + /* Checkpoint the database. */ + ret = session->checkpoint(session, NULL); + + /* Checkpoint of the database, creating a named snapshot. */ + ret = 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\")"); + + /* + * 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"); + + /* Checkpoint the database, discarding all previous snapshots. */ + ret = session->checkpoint(session, "drop=(from=all)"); + + /* Checkpoint the database, discarding the "midnight" snapshot. */ + ret = session->checkpoint(session, "drop=(midnight)"); + + /* + * Checkpoint the database, discarding all snapshots after and + * including "noon". + */ + ret = session->checkpoint(session, "drop=(from=noon)"); + + /* + * Checkpoint the database, discarding all snapshots before and + * including "midnight". + */ + ret = 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)"); + /*! [Checkpoint examples] */ + + /*! [JSON quoting example] */ + /* + * Checkpoint a list of objects. + * JSON parsing requires quoting the list of target URIs. + */ + ret = session-> + checkpoint(session, "target=(\"table:table1\",\"table:table2\")"); + /*! [JSON quoting example] */ + + return (ret); +} + +int +cursor_statistics(WT_SESSION *session) +{ + WT_CURSOR *cursor; + int ret; + + /*! [Statistics cursor database] */ + ret = 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); + /*! [Statistics cursor table] */ + + /*! [Statistics cursor table fast] */ + ret = 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); + /*! [Statistics clear configuration] */ + + /*! [Statistics cursor clear configuration] */ + ret = session->open_cursor(session, + "statistics:table:mytable", + NULL, "statistics=(all,clear)", &cursor); + /*! [Statistics cursor clear configuration] */ + + return (ret); +} + +int +named_snapshot_ops(WT_SESSION *session) +{ + int ret; + + /*! [Snapshot examples] */ + + /* Create a named snapshot */ + ret = session->snapshot(session, "name=June01"); + + /* Open a transaction at a given snapshot */ + ret = session->begin_transaction(session, "snapshot=June01"); + + /* Drop all named snapshots */ + ret = session->snapshot(session, "drop=(all)"); + /*! [Snapshot examples] */ + + return (ret); +} + +int +session_ops(WT_SESSION *session) +{ + int ret; + + /*! [Reconfigure a session] */ + ret = session->reconfigure(session, "isolation=snapshot"); + /*! [Reconfigure a session] */ + + /*! [Create a table] */ + ret = session->create(session, + "table:mytable", "key_format=S,value_format=S"); + /*! [Create a table] */ + ret = session->drop(session, "table:mytable", NULL); + + /*! [Create a column-store table] */ + ret = session->create(session, + "table:mytable", "key_format=r,value_format=S"); + /*! [Create a column-store table] */ + ret = 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", + "key_format=r,value_format=SiH," + "columns=(id,department,salary,year-started)"); + /*! [Create a table with columns] */ + ret = session->drop(session, "table:mytable", NULL); + + /*! [Create a table and configure the page size] */ + ret = session->create(session, + "table:mytable", "key_format=S,value_format=S," + "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); + + /*! [Create a table and configure a large leaf value max] */ + ret = session->create(session, + "table:mytable", "key_format=S,value_format=S," + "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); + + /* + * This example code gets run, and the compression libraries might not + * be loaded, causing the create to fail. The documentation requires + * the code snippets, use #ifdef's to avoid running it. + */ +#ifdef MIGHT_NOT_RUN + /*! [Create a bzip2 compressed table] */ + ret = session->create(session, + "table:mytable", + "block_compressor=bzip2,key_format=S,value_format=S"); + /*! [Create a bzip2 compressed table] */ + ret = session->drop(session, "table:mytable", NULL); + + /*! [Create a lz4 compressed table] */ + ret = session->create(session, + "table:mytable", + "block_compressor=lz4,key_format=S,value_format=S"); + /*! [Create a lz4 compressed table] */ + ret = session->drop(session, "table:mytable", NULL); + + /*! [Create a snappy compressed table] */ + ret = session->create(session, + "table:mytable", + "block_compressor=snappy,key_format=S,value_format=S"); + /*! [Create a snappy compressed table] */ + ret = session->drop(session, "table:mytable", NULL); + + /*! [Create a zlib compressed table] */ + ret = session->create(session, + "table:mytable", + "block_compressor=zlib,key_format=S,value_format=S"); + /*! [Create a zlib compressed table] */ + ret = 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"); + /*! [Configure checksums to uncompressed] */ + ret = session->drop(session, "table:mytable", NULL); + + /*! [Configure dictionary compression on] */ + ret = session->create(session, "table:mytable", + "key_format=S,value_format=S,dictionary=1000"); + /*! [Configure dictionary compression on] */ + ret = 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"); + /*! [Configure key prefix compression on] */ + ret = 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"); + /*! [os_cache_dirty_max configuration] */ + ret = session->drop(session, "table:mytable", NULL); + + /* Requires posix_fadvise */ + /*! [os_cache_max configuration] */ + ret = session->create(session, "table:mytable", "os_cache_max=1GB"); + /*! [os_cache_max configuration] */ + ret = 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"); + /*! [Configure block_allocation] */ + ret = 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"); + /*! [Create a cache-resident object] */ + ret = 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"); + + /*! [Compact a table] */ + ret = session->compact(session, "table:mytable", NULL); + /*! [Compact a table] */ + + /*! [Rebalance a table] */ + ret = session->rebalance(session, "table:mytable", NULL); + /*! [Rebalance a table] */ + + /*! [Rename a table] */ + ret = session->rename(session, "table:old", "table:new", NULL); + /*! [Rename a table] */ + + /*! [Salvage a table] */ + ret = session->salvage(session, "table:mytable", NULL); + /*! [Salvage a table] */ + + /*! [Truncate a table] */ + ret = session->truncate(session, "table:mytable", NULL, NULL, NULL); + /*! [Truncate a table] */ + + /*! [Transaction sync] */ + ret = session->transaction_sync(session, NULL); + /*! [Transaction sync] */ + + /*! [Reset the session] */ + ret = session->reset(session); + /*! [Reset the 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); + cursor->set_key(cursor, "June01"); + cursor->set_value(cursor, "value"); + ret = cursor->update(cursor); + cursor->set_key(cursor, "June30"); + cursor->set_value(cursor, "value"); + ret = cursor->update(cursor); + ret = cursor->close(cursor); + + { + /*! [Truncate a range] */ + WT_CURSOR *start, *stop; + + ret = session->open_cursor( + session, "table:mytable", NULL, NULL, &start); + start->set_key(start, "June01"); + ret = start->search(start); + + ret = session->open_cursor( + session, "table:mytable", NULL, NULL, &stop); + stop->set_key(stop, "June30"); + ret = stop->search(stop); + + ret = session->truncate(session, NULL, start, stop, NULL); + /*! [Truncate a range] */ + } + } + + /*! [Upgrade a table] */ + ret = session->upgrade(session, "table:mytable", NULL); + /*! [Upgrade a table] */ + + /*! [Verify a table] */ + ret = session->verify(session, "table:mytable", NULL); + /*! [Verify a table] */ + + /*! [Drop a table] */ + ret = session->drop(session, "table:mytable", NULL); + /*! [Drop a table] */ + } + + /*! [Close a session] */ + ret = session->close(session, NULL); + /*! [Close a session] */ + + return (ret); +} + +int +transaction_ops(WT_CONNECTION *conn, WT_SESSION *session) +{ + WT_CURSOR *cursor; + int ret; + + /*! [transaction commit/rollback] */ + /* + * Cursors may be opened before or after the transaction begins, and in + * either case, subsequent operations are included in the transaction. + * 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); + + cursor->set_key(cursor, "key"); + cursor->set_value(cursor, "value"); + switch (ret = cursor->update(cursor)) { + case 0: /* Update success */ + ret = session->commit_transaction(session, NULL); + /* + * If commit_transaction succeeds, cursors remain positioned; if + * commit_transaction fails, the transaction was rolled-back and + * and all cursors are reset. + */ + break; + case WT_ROLLBACK: /* Update conflict */ + default: /* Other error */ + ret = session->rollback_transaction(session, NULL); + /* The rollback_transaction call resets all cursors. */ + break; + } + + /* + * Cursors remain open and may be used for multiple transactions. + */ + /*! [transaction commit/rollback] */ + ret = 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"); + cursor->set_key(cursor, "some-key"); + cursor->set_value(cursor, "some-value"); + ret = cursor->update(cursor); + ret = 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); + /*! [session isolation configuration] */ + + /*! [session isolation re-configuration] */ + /* Re-configure a session for snapshot isolation. */ + ret = session->reconfigure(session, "isolation=snapshot"); + /*! [session isolation re-configuration] */ + + { + /*! [transaction pinned range] */ + /* Check the transaction ID range pinned by the session handle. */ + uint64_t range; + + ret = session->transaction_pinned_range(session, &range); + /*! [transaction pinned range] */ + } + + return (ret); +} + +/*! [Implement WT_COLLATOR] */ +/* + * A simple example of the collator API: compare the keys as strings. + */ +static int +my_compare(WT_COLLATOR *collator, WT_SESSION *session, + const WT_ITEM *value1, const WT_ITEM *value2, int *cmp) +{ + const char *p1, *p2; + + /* Unused parameters */ + (void)collator; + (void)session; + + p1 = (const char *)value1->data; + p2 = (const char *)value2->data; + while (*p1 != '\0' && *p1 == *p2) + p1++, p2++; + + *cmp = (int)*p2 - (int)*p1; + return (0); +} +/*! [Implement WT_COLLATOR] */ + +int +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); + /*! [WT_COLLATOR register] */ + + return (ret); +} + +/*! [WT_EXTRACTOR] */ +static int +my_extract(WT_EXTRACTOR *extractor, WT_SESSION *session, + const WT_ITEM *key, const WT_ITEM *value, + WT_CURSOR *result_cursor) +{ + /* Unused parameters */ + (void)extractor; + (void)session; + (void)key; + + result_cursor->set_key(result_cursor, value); + return (result_cursor->insert(result_cursor)); +} +/*! [WT_EXTRACTOR] */ + +int +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); + /*! [WT_EXTRACTOR register] */ + + return (ret); +} + +int +connection_ops(WT_CONNECTION *conn) +{ + int ret; + +#ifdef MIGHT_NOT_RUN + /*! [Load an extension] */ + ret = conn->load_extension(conn, "my_extension.dll", NULL); + + ret = conn->load_extension(conn, + "datasource/libdatasource.so", + "config=[device=/dev/sd1,alignment=64]"); + /*! [Load an extension] */ +#endif + + ret = add_collator(conn); + ret = add_extractor(conn); + + /*! [Reconfigure a connection] */ + ret = conn->reconfigure(conn, "eviction_target=75"); + /*! [Reconfigure a connection] */ + + /*! [Get the database home directory] */ + printf("The database home is %s\n", conn->get_home(conn)); + /*! [Get the database home directory] */ + + /*! [Check if the database is newly created] */ + if (conn->is_new(conn)) { + /* First time initialization. */ + } + /*! [Check if the database is newly created] */ + + /*! [Validate a configuration string] */ + /* + * Validate a configuration string for a WiredTiger function or method. + * + * Functions are specified by name (for example, "wiredtiger_open"). + * + * Methods are specified using a concatenation of the handle name, a + * 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"); + /*! [Validate a configuration string] */ + + { + /*! [Open a session] */ + WT_SESSION *session; + ret = conn->open_session(conn, NULL, NULL, &session); + /*! [Open a session] */ + + ret = session_ops(session); + } + + /*! [Configure method configuration] */ + /* + * Applications opening a cursor for the data-source object "my_data" + * have an additional configuration option "entries", which is an + * integer type, defaults to 5, and must be an integer between 1 and 10. + * + * The method being configured is specified using a concatenation of the + * handle name, a period and the method name. + */ + ret = conn->configure_method(conn, + "WT_SESSION.open_cursor", + "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); + /*! [Configure method configuration] */ + + /*! [Close a connection] */ + ret = conn->close(conn, NULL); + /*! [Close a connection] */ + + return (ret); +} + +int +pack_ops(WT_SESSION *session) +{ + int ret; + + { + /*! [Get the packed size] */ + size_t size; + ret = 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); + /*! [Pack fields into a buffer] */ + + { + /*! [Unpack fields from a buffer] */ + int i; + char *s; + short h; + ret = wiredtiger_struct_unpack( + session, buf, sizeof(buf), "iSh", &i, &s, &h); + /*! [Unpack fields from a buffer] */ + } + } + + return (ret); +} + +int +backup(WT_SESSION *session) +{ + char buf[1024]; + + /*! [backup]*/ + WT_CURSOR *cursor; + const char *filename; + int ret; + + /* Create the backup directory. */ + ret = mkdir("/path/database.backup", 077); + + /* Open the backup data source. */ + ret = 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) { + (void)snprintf(buf, sizeof(buf), + "cp /path/database/%s /path/database.backup/%s", + filename, filename); + ret = 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)); + + ret = cursor->close(cursor); + /*! [backup]*/ + + /*! [backup of a checkpoint]*/ + ret = session->checkpoint(session, "drop=(from=June01),name=June01"); + /*! [backup of a checkpoint]*/ + + return (ret); +} + +int +main(void) +{ + 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; + + /*! [Open a connection] */ + ret = wiredtiger_open(home, NULL, + "create,cache_size=5GB,log=(enabled,recover=on)", &conn); + /*! [Open a connection] */ + + if (ret == 0) + ret = connection_ops(conn); + /* + * The connection has been closed. + */ + +#ifdef MIGHT_NOT_RUN + /* + * This example code gets run, and the compression libraries might not + * be installed, causing the open to fail. The documentation requires + * the code snippets, use #ifdef's to avoid running it. + */ + /*! [Configure bzip2 extension] */ + ret = wiredtiger_open(home, NULL, + "create," + "extensions=[/usr/local/lib/libwiredtiger_bzip2.so]", &conn); + /*! [Configure bzip2 extension] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Configure lz4 extension] */ + ret = wiredtiger_open(home, NULL, + "create," + "extensions=[/usr/local/lib/libwiredtiger_lz4.so]", &conn); + /*! [Configure lz4 extension] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Configure snappy extension] */ + ret = wiredtiger_open(home, NULL, + "create," + "extensions=[/usr/local/lib/libwiredtiger_snappy.so]", &conn); + /*! [Configure snappy extension] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Configure zlib extension] */ + ret = wiredtiger_open(home, NULL, + "create," + "extensions=[/usr/local/lib/libwiredtiger_zlib.so]", &conn); + /*! [Configure zlib extension] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /* + * This example code gets run, and direct I/O might not be available, + * causing the open to fail. The documentation requires code snippets, + * use #ifdef's to avoid running it. + */ + /* 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); + /*! [Configure direct_io for data files] */ + if (ret == 0) + (void)conn->close(conn, NULL); +#endif + + /*! [Configure file_extend] */ + ret = wiredtiger_open( + home, NULL, "create,file_extend=(data=16MB)", &conn); + /*! [Configure file_extend] */ + if (ret == 0) + (void)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); + /*! [Eviction configuration] */ + if (ret == 0) + (void)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); + /*! [Eviction worker configuration] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Statistics configuration] */ + ret = wiredtiger_open(home, NULL, "create,statistics=(all)", &conn); + /*! [Statistics configuration] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Statistics logging] */ + ret = wiredtiger_open( + home, NULL, "create,statistics_log=(wait=30)", &conn); + /*! [Statistics logging] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Statistics logging with a table] */ + ret = wiredtiger_open(home, NULL, + "create, statistics_log=(" + "sources=(\"lsm:table1\",\"lsm:table2\"), wait=5)", + &conn); + /*! [Statistics logging with a table] */ + if (ret == 0) + (void)conn->close(conn, NULL); + + /*! [Statistics logging with all tables] */ + ret = wiredtiger_open(home, NULL, + "create, statistics_log=(sources=(\"lsm:\"), wait=5)", + &conn); + /*! [Statistics logging with all tables] */ + if (ret == 0) + (void)conn->close(conn, NULL); + +#ifdef MIGHT_NOT_RUN + /* + * This example code gets run, and a non-existent log file path might + * cause the open to fail. The documentation requires code snippets, + * use #ifdef's to avoid running it. + */ + /*! [Statistics logging with path] */ + ret = wiredtiger_open(home, NULL, + "create," + "statistics_log=(wait=120,path=/log/log.%m.%d.%y)", &conn); + /*! [Statistics logging with path] */ + if (ret == 0) + (void)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); + /*! [Connection close leaking memory] */ + ret = conn->close(conn, "leak_memory=true"); + /*! [Connection close leaking memory] */ +#endif + + /*! [Get the WiredTiger library version #1] */ + printf("WiredTiger version %s\n", wiredtiger_version(NULL, NULL, NULL)); + /*! [Get the WiredTiger library version #1] */ + + { + /*! [Get the WiredTiger library version #2] */ + int major_v, minor_v, patch; + (void)wiredtiger_version(&major_v, &minor_v, &patch); + printf("WiredTiger version is %d, %d (patch %d)\n", + major_v, minor_v, patch); + /*! [Get the WiredTiger library version #2] */ + } + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_async.c b/src/third_party/wiredtiger/examples/c/ex_async.c new file mode 100644 index 00000000000..584c3e54b87 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_async.c @@ -0,0 +1,224 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_async.c + * demonstrates how to use the asynchronous API. + */ +#include <errno.h> +#include <inttypes.h> +#include <stdio.h> +#include <string.h> +#ifndef _WIN32 +#include <unistd.h> +#else +#include "windows_shim.h" +#endif + +#include <wiredtiger.h> + +#if defined(_lint) +#define ATOMIC_ADD(v, val) ((v) += (val), (v)) +#elif defined(_WIN32) +#define ATOMIC_ADD(v, val) (_InterlockedExchangeAdd(&(v), val) + val) +#else +#define ATOMIC_ADD(v, val) __sync_add_and_fetch(&(v), val) +#endif + +static const char * const home = NULL; +static int global_error = 0; + +/*! [async example callback implementation] */ +typedef struct { + WT_ASYNC_CALLBACK iface; + uint32_t num_keys; +} ASYNC_KEYS; + +static int +async_callback(WT_ASYNC_CALLBACK *cb, + WT_ASYNC_OP *op, int wiredtiger_error, uint32_t flags) +{ + ASYNC_KEYS *asynckey = (ASYNC_KEYS *)cb; + WT_ASYNC_OPTYPE type; + 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); + /*! [async get type] */ + + /*! [async get identifier] */ + /* Retrieve the operation's 64-bit identifier. */ + id = op->get_id(op); + /*! [async get identifier] */ + + /* Check for a WiredTiger error. */ + if (wiredtiger_error != 0) { + fprintf(stderr, + "ID %" PRIu64 " error %d: %s\n", + id, wiredtiger_error, + wiredtiger_strerror(wiredtiger_error)); + global_error = wiredtiger_error; + return (1); + } + + /* 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); + key = k.data; + /*! [async get the operation's string key] */ + /*! [async get the operation's string value] */ + ret = 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); +} +/*! [async example callback implementation] */ + +static ASYNC_KEYS ex_asynckeys = { {async_callback}, 0 }; + +#define MAX_KEYS 15 + +int +main(void) +{ + WT_ASYNC_OP *op; + WT_CONNECTION *conn; + WT_SESSION *session; + int i, ret; + char k[MAX_KEYS][16], v[MAX_KEYS][16]; + + /*! [async example connection] */ + ret = wiredtiger_open(home, NULL, + "create,cache_size=100MB," + "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"); + /*! [async example table create] */ + + /* Insert a set of keys asynchronously. */ + for (i = 0; i < MAX_KEYS; i++) { + /*! [async handle allocation] */ + while ((ret = conn->async_new_op(conn, + "table:async", NULL, &ex_asynckeys.iface, &op)) != 0) { + /* + * If we used up all the handles, pause and retry to + * give the workers a chance to catch up. + */ + fprintf(stderr, + "asynchronous operation handle not available\n"); + if (ret == EBUSY) + sleep(1); + else + return (ret); + } + /*! [async handle allocation] */ + + /*! [async insert] */ + /* + * Set the operation's string key and value, and then do + * an asynchronous insert. + */ + /*! [async set the operation's string key] */ + snprintf(k[i], sizeof(k), "key%d", i); + op->set_key(op, k[i]); + /*! [async set the operation's string key] */ + + /*! [async set the operation's string value] */ + snprintf(v[i], sizeof(v), "value%d", i); + op->set_value(op, v[i]); + /*! [async set the operation's string value] */ + + ret = op->insert(op); + /*! [async insert] */ + } + + /*! [async flush] */ + /* Wait for all outstanding operations to complete. */ + ret = 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); + /*! [async compaction] */ + + /* Search for the keys we just inserted, asynchronously. */ + for (i = 0; i < MAX_KEYS; i++) { + while ((ret = conn->async_new_op(conn, + "table:async", NULL, &ex_asynckeys.iface, &op)) != 0) { + /* + * If we used up all the handles, pause and retry to + * give the workers a chance to catch up. + */ + fprintf(stderr, + "asynchronous operation handle not available\n"); + if (ret == EBUSY) + sleep(1); + else + return (ret); + } + + /*! [async search] */ + /* + * Set the operation's string key and value, and then do + * an asynchronous search. + */ + snprintf(k[i], sizeof(k), "key%d", i); + op->set_key(op, k[i]); + ret = op->search(op); + /*! [async search] */ + } + + /* + * Connection close automatically does an async_flush so it will wait + * for all queued search operations to complete. + */ + ret = conn->close(conn, NULL); + + printf("Searched for %d keys\n", ex_asynckeys.num_keys); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_backup.c b/src/third_party/wiredtiger/examples/c/ex_backup.c new file mode 100644 index 00000000000..12eeaa4b7c3 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_backup.c @@ -0,0 +1,326 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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> + +static const char * const home = "WT_HOME_LOG"; +static const char * const home_full = "WT_HOME_LOG_FULL"; +static const char * const home_incr = "WT_HOME_LOG_INCR"; + +static const char * const full_out = "./backup_full"; +static const char * const incr_out = "./backup_incr"; + +static const char * const uri = "table:logtest"; + +#define CONN_CONFIG \ + "create,cache_size=100MB,log=(archive=false,enabled=true,file_max=100K)" +#define MAX_ITERATIONS 5 +#define MAX_KEYS 10000 + +static int +compare_backups(int i) +{ + int ret; + char buf[1024], msg[8]; + + /* + * We run 'wt dump' on both the full backup directory and the + * incremental backup directory for this iteration. Since running + * 'wt' runs recovery and makes both directories "live", we need + * a new directory for each iteration. + * + * If i == 0, we're comparing against the main, original directory + * with the final incremental directory. + */ + if (i == 0) + (void)snprintf(buf, sizeof(buf), + "../../wt -R -h %s dump logtest > %s.%d", + home, full_out, i); + else + (void)snprintf(buf, sizeof(buf), + "../../wt -R -h %s.%d dump logtest > %s.%d", + home_full, i, full_out, i); + ret = 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); + + /* + * Compare the files. + */ + (void)snprintf(buf, sizeof(buf), "cmp %s.%d %s.%d", + full_out, i, incr_out, i); + ret = system(buf); + if (i == 0) + (void)strncpy(msg, "MAIN", sizeof(msg)); + else + snprintf(msg, sizeof(msg), "%d", i); + printf( + "Iteration %s: Tables %s.%d and %s.%d %s\n", + msg, full_out, i, incr_out, i, ret == 0 ? "identical" : "differ"); + if (ret != 0) + exit (1); + + /* + * If they compare successfully, clean up. + */ + if (i != 0) { + (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); + } + return (ret); +} + +/* + * Set up all the directories needed for the test. We have a full backup + * 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 +setup_directories(void) +{ + int i, ret; + char buf[1024]; + + for (i = 0; i < MAX_ITERATIONS; i++) { + /* + * For incremental backups we need 0-N. The 0 incremental + * directory will compare with the original at the end. + */ + 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); + } + if (i == 0) + continue; + /* + * For full backups we need 1-N. + */ + 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); + } + } + return (0); +} + +static int +add_work(WT_SESSION *session, int iter) +{ + WT_CURSOR *cursor; + int i, ret; + char k[32], v[32]; + + ret = session->open_cursor(session, uri, NULL, NULL, &cursor); + /* + * Perform some operations with individual auto-commit transactions. + */ + for (i = 0; i < MAX_KEYS; i++) { + snprintf(k, sizeof(k), "key.%d.%d", iter, i); + snprintf(v, sizeof(v), "value.%d.%d", iter, i); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = cursor->insert(cursor); + } + ret = cursor->close(cursor); + return (ret); +} + +static int +take_full_backup(WT_SESSION *session, int i) +{ + WT_CURSOR *cursor; + int j, ret; + char buf[1024], h[256]; + const char *filename, *hdir; + + /* + * First time through we take a full backup into the incremental + * directories. Otherwise only into the appropriate full directory. + */ + if (i != 0) { + snprintf(h, sizeof(h), "%s.%d", home_full, i); + hdir = h; + } else + hdir = home_incr; + ret = session->open_cursor(session, "backup:", NULL, NULL, &cursor); + + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &filename); + if (i == 0) + /* + * Take a full backup into each incremental directory. + */ + for (j = 0; j < MAX_ITERATIONS; j++) { + 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); + } + else { + 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); + } + } + if (ret != WT_NOTFOUND) + fprintf(stderr, + "WT_CURSOR.next: %s\n", session->strerror(session, ret)); + ret = cursor->close(cursor); + return (ret); +} + +static int +take_incr_backup(WT_SESSION *session, int i) +{ + WT_CURSOR *cursor; + int j, ret; + char buf[1024], h[256]; + const char *filename; + + ret = session->open_cursor(session, "backup:", + NULL, "target=(\"log:\")", &cursor); + + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &filename); + /* + * Copy into the 0 incremental directory and then each of the + * incremental directories for this iteration and later. + */ + 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); + for (j = i; j < MAX_ITERATIONS; j++) { + 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); + } + } + if (ret != WT_NOTFOUND) + fprintf(stderr, + "WT_CURSOR.next: %s\n", session->strerror(session, ret)); + ret = 0; + /* + * 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); +} + +int +main(void) +{ + WT_CONNECTION *wt_conn; + WT_SESSION *session; + int i, ret; + char cmd_buf[256]; + + 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 (ret); + } + if ((ret = wiredtiger_open(home, NULL, CONN_CONFIG, &wt_conn)) != 0) { + fprintf(stderr, "Error connecting to %s: %s\n", + home, wiredtiger_strerror(ret)); + return (ret); + } + + ret = setup_directories(); + ret = wt_conn->open_session(wt_conn, NULL, NULL, &session); + ret = session->create(session, uri, "key_format=S,value_format=S"); + printf("Adding initial data\n"); + ret = add_work(session, 0); + + printf("Taking initial backup\n"); + ret = take_full_backup(session, 0); + + ret = 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); + /* + * 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); + /* + * 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); + + printf("Iteration %d: dumping and comparing data\n", i); + ret = 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); + printf("Final comparison: dumping and comparing data\n"); + ret = compare_backups(0); + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_call_center.c b/src/third_party/wiredtiger/examples/c/ex_call_center.c new file mode 100644 index 00000000000..d401507d165 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_call_center.c @@ -0,0 +1,249 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_call_center.c + * 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> + +static const char *home; + +/*! [call-center decl] */ +/* + * In SQL, the tables are described as follows: + * + * CREATE TABLE Customers(id INTEGER PRIMARY KEY, + * name VARCHAR(30), address VARCHAR(50), phone VARCHAR(15)) + * CREATE INDEX CustomersPhone ON Customers(phone) + * + * CREATE TABLE Calls(id INTEGER PRIMARY KEY, call_date DATE, + * cust_id INTEGER, emp_id INTEGER, call_type VARCHAR(12), + * notes VARCHAR(25)) + * CREATE INDEX CallsCustDate ON Calls(cust_id, call_date) + * + * In this example, both tables will use record numbers for their IDs, which + * will be the key. The C structs for the records are as follows. + */ + +/* Customer records. */ +typedef struct { + uint64_t id; + const char *name; + const char *address; + const char *phone; +} CUSTOMER; + +/* Call records. */ +typedef struct { + uint64_t id; + uint64_t call_date; + uint64_t cust_id; + uint64_t emp_id; + const char *call_type; + const char *notes; +} CALL; +/*! [call-center decl] */ + +int +main(void) +{ + int count, exact, ret; + WT_CONNECTION *conn; + WT_SESSION *session; + WT_CURSOR *cursor; + CUSTOMER cust, *custp, cust_sample[] = { + { 0, "Professor Oak", "LeafGreen Avenue", "123-456-7890" }, + { 0, "Lorelei", "Sevii Islands", "098-765-4321" }, + { 0, NULL, NULL, NULL } + }; + CALL call, *callp, call_sample[] = { + { 0, 32, 1, 2, "billing", "unavailable" }, + { 0, 33, 1, 2, "billing", "available" }, + { 0, 34, 1, 2, "reminder", "unavailable" }, + { 0, 35, 1, 2, "reminder", "available" }, + { 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, wiredtiger_strerror(ret)); + return (1); + } + /* Note: further error checking omitted for clarity. */ + + /*! [call-center work] */ + ret = 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", + "key_format=r," + "value_format=SSS," + "columns=(id,name,address,phone)," + "colgroups=(main,address)"); + + /* Create the main column group with value columns except address. */ + ret = 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)"); + + /* Create an index on the customer table by phone number. */ + ret = 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); + for (custp = cust_sample; custp->name != NULL; custp++) { + cursor->set_value(cursor, + custp->name, custp->address, custp->phone); + ret = cursor->insert(cursor); + } + ret = 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", + "key_format=r," + "value_format=qrrSS," + "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)"); + + /* Populate the calls table with some data. */ + ret = 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); + } + ret = cursor->close(cursor); + + /* + * First query: a call arrives. In SQL: + * + * SELECT id, name FROM Customers WHERE phone=? + * + * Use the cust_phone index, lookup by phone number to fill the + * customer record. The cursor will have a key format of "S" for a + * string because the cust_phone index has a single column ("phone"), + * which is of type "S". + * + * 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); + 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); + + /* + * Next query: get the recent order history. In SQL: + * + * SELECT * FROM Calls WHERE cust_id=? ORDER BY call_date DESC LIMIT 3 + * + * Use the call_cust_date index to find the matching calls. Since it is + * is in increasing order by date for a given customer, we want to start + * with the last record for the customer and work backwards. + * + * Specify a subset of columns to be returned. (Note that if these were + * all covered by the index, the primary would not have to be accessed.) + * Stop after getting 3 records. + */ + ret = session->open_cursor(session, + "index:calls:cust_date(cust_id,call_type,notes)", + NULL, NULL, &cursor); + + /* + * The keys in the index are (cust_id,call_date) -- we want the largest + * call date for a given cust_id. Search for (cust_id+1,0), then work + * backwards. + */ + cust.id = 1; + cursor->set_key(cursor, cust.id + 1, 0); + ret = cursor->search_near(cursor, &exact); + + /* + * If the table is empty, search_near will return WT_NOTFOUND, else the + * cursor will be positioned on a matching key if one exists, or an + * 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 (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); + } + /*! [call-center work] */ + + ret = conn->close(conn, NULL); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_config.c b/src/third_party/wiredtiger/examples/c/ex_config.c new file mode 100644 index 00000000000..2ac8198176c --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_config.c @@ -0,0 +1,91 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_config.c + * This is an example demonstrating how to configure various database and + * table properties. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <wiredtiger.h> + +static const char *home; + +int +main(void) +{ + int ret; + WT_CONNECTION *conn; + WT_SESSION *session; + WT_CURSOR *cursor; + const char *key, *value; + + /* + * 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; + + /*! [configure cache size] */ + if ((ret = wiredtiger_open(home, NULL, + "create,cache_size=500M", &conn)) != 0) + fprintf(stderr, "Error connecting to %s: %s\n", + home, wiredtiger_strerror(ret)); + /*! [configure cache size] */ + + /*! [create a table] */ + ret = conn->open_session(conn, NULL, NULL, &session); + + ret = session->create(session, + "table:access", "key_format=S,value_format=S"); + /*! [create a table] */ + + /*! [transaction] */ + ret = session->begin_transaction(session, "priority=100,name=mytxn"); + + ret = session->open_cursor(session, "config:", NULL, NULL, &cursor); + + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &key); + ret = cursor->get_value(cursor, &value); + printf("configuration value: %s = %s\n", key, value); + } + + ret = session->commit_transaction(session, NULL); + /*! [transaction] */ + + ret = conn->close(conn, NULL); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_config_parse.c b/src/third_party/wiredtiger/examples/c/ex_config_parse.c new file mode 100644 index 00000000000..124eff21130 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_config_parse.c @@ -0,0 +1,166 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_config_parse.c + * This is an example demonstrating how to parse WiredTiger compatible + * configuration strings. + */ + +#include <stdio.h> +#include <string.h> + +#include <wiredtiger.h> + +int +main(void) +{ + int ret; + + /*! [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 (ret); + } + if ((ret = parser->close(parser)) != 0) { + fprintf(stderr, "Error closing configuration parser: %s\n", + wiredtiger_strerror(ret)); + return (ret); + } + /*! [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 (ret); + } + + { + /*! [get] */ + int64_t my_page_size; + /* + * 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 (ret); + } + my_page_size = v.val; + /*! [get] */ + + ret = parser->close(parser); + + (void)my_page_size; + } + + { + 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 (ret); + } + /*! [next] */ + /* + * Retrieve and print the values of the configuration strings. + */ + while ((ret = parser->next(parser, &k, &v)) == 0) { + printf("%.*s:", (int)k.len, k.str); + if (v.type == WT_CONFIG_ITEM_NUM) + printf("%d\n", (int)v.val); + else + printf("%.*s\n", (int)v.len, v.str); + } + /*! [next] */ + ret = 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 (ret); + } + + /*! [nested get] */ + /* + * Retrieve the value of the nested log file_max configuration string + * using dot shorthand. Utilize the configuration parsing automatic + * 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 (ret); + } + printf("log file max: %d\n", (int)v.val); + /*! [nested get] */ + ret = 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 (ret); + } + /*! [nested traverse] */ + { + WT_CONFIG_PARSER *sub_parser; + while ((ret = parser->next(parser, &k, &v)) == 0) { + 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)); + ret = parser->close(parser); + return (ret); + } + 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); + } + } + /*! [nested traverse] */ + ret = parser->close(parser); + } + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_cursor.c b/src/third_party/wiredtiger/examples/c/ex_cursor.c new file mode 100644 index 00000000000..67c945ebc0b --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_cursor.c @@ -0,0 +1,228 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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> + +int cursor_reset(WT_CURSOR *cursor); +int cursor_forward_scan(WT_CURSOR *cursor); +int cursor_reverse_scan(WT_CURSOR *cursor); +int cursor_search(WT_CURSOR *cursor); +int cursor_search_near(WT_CURSOR *cursor); +int cursor_insert(WT_CURSOR *cursor); +int cursor_update(WT_CURSOR *cursor); +int cursor_remove(WT_CURSOR *cursor); + +static const char *home; + +/*! [cursor next] */ +int +cursor_forward_scan(WT_CURSOR *cursor) +{ + const char *key, *value; + int ret; + + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &key); + ret = cursor->get_value(cursor, &value); + } + return (ret); +} +/*! [cursor next] */ + +/*! [cursor prev] */ +int +cursor_reverse_scan(WT_CURSOR *cursor) +{ + const char *key, *value; + int ret; + + while ((ret = cursor->prev(cursor)) == 0) { + ret = cursor->get_key(cursor, &key); + ret = cursor->get_value(cursor, &value); + } + return (ret); +} +/*! [cursor prev] */ + +/*! [cursor reset] */ +int +cursor_reset(WT_CURSOR *cursor) +{ + return (cursor->reset(cursor)); +} +/*! [cursor reset] */ + +/*! [cursor search] */ +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); + + return (ret); +} +/*! [cursor search] */ + +/*! [cursor search near] */ +int +cursor_search_near(WT_CURSOR *cursor) +{ + const char *key, *value; + int exact, ret; + + 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); + } + + return (ret); +} +/*! [cursor search near] */ + +/*! [cursor insert] */ +int +cursor_insert(WT_CURSOR *cursor) +{ + cursor->set_key(cursor, "foo"); + cursor->set_value(cursor, "bar"); + + return (cursor->insert(cursor)); +} +/*! [cursor insert] */ + +/*! [cursor update] */ +int +cursor_update(WT_CURSOR *cursor) +{ + cursor->set_key(cursor, "foo"); + cursor->set_value(cursor, "newbar"); + + return (cursor->update(cursor)); +} +/*! [cursor update] */ + +/*! [cursor remove] */ +int +cursor_remove(WT_CURSOR *cursor) +{ + cursor->set_key(cursor, "foo"); + return (cursor->remove(cursor)); +} +/*! [cursor remove] */ + +int +main(void) +{ + 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; + + /* 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, wiredtiger_strerror(ret)); + + /* 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, wiredtiger_strerror(ret)); + + ret = session->create(session, "table:world", + "key_format=r,value_format=5sii," + "columns=(id,country,population,area)"); + + /*! [open cursor #1] */ + ret = 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); + /*! [open cursor #2] */ + + /*! [open cursor #3] */ + ret = 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); + + /* Note: closing the connection implicitly closes open session(s). */ + if ((ret = conn->close(conn, NULL)) != 0) + fprintf(stderr, "Error closing %s: %s\n", + home, wiredtiger_strerror(ret)); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_data_source.c b/src/third_party/wiredtiger/examples/c/ex_data_source.c new file mode 100644 index 00000000000..dd2b835e6ae --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_data_source.c @@ -0,0 +1,673 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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> + +/*! [WT_EXTENSION_API declaration] */ +#include <wiredtiger_ext.h> + +static WT_EXTENSION_API *wt_api; + +static void +my_data_source_init(WT_CONNECTION *connection) +{ + wt_api = connection->get_extension_api(connection); +} +/*! [WT_EXTENSION_API declaration] */ + +/*! [WT_DATA_SOURCE create] */ +static int +my_create(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE create] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)uri; + (void)config; + + { + const char *msg = "string"; + /*! [WT_EXTENSION_API err_printf] */ + (void)wt_api->err_printf( + wt_api, session, "extension error message: %s", msg); + /*! [WT_EXTENSION_API err_printf] */ + } + + { + const char *msg = "string"; + /*! [WT_EXTENSION_API msg_printf] */ + (void)wt_api->msg_printf(wt_api, session, "extension message: %s", msg); + /*! [WT_EXTENSION_API msg_printf] */ + } + + { + int ret = 0; + /*! [WT_EXTENSION_API strerror] */ + (void)wt_api->err_printf(wt_api, session, + "WiredTiger error return: %s", + wt_api->strerror(wt_api, session, ret)); + /*! [WT_EXTENSION_API strerror] */ + } + + { + /*! [WT_EXTENSION_API scr_alloc] */ + void *buffer; + if ((buffer = wt_api->scr_alloc(wt_api, session, 512)) == NULL) { + (void)wt_api->err_printf(wt_api, session, + "buffer allocation: %s", + session->strerror(session, ENOMEM)); + return (ENOMEM); + } + /*! [WT_EXTENSION_API scr_alloc] */ + + /*! [WT_EXTENSION_API scr_free] */ + wt_api->scr_free(wt_api, session, buffer); + /*! [WT_EXTENSION_API scr_free] */ + } + + return (0); +} + +/*! [WT_DATA_SOURCE compact] */ +static int +my_compact(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE compact] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)config; + + return (0); +} + +/*! [WT_DATA_SOURCE drop] */ +static int +my_drop(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE drop] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)config; + + return (0); +} + +static int +data_source_cursor(void) +{ + return (0); +} + +static const char * +data_source_error(int v) +{ + return (v == 0 ? "one" : "two"); +} + +static int +data_source_notify( + WT_TXN_NOTIFY *handler, WT_SESSION *session, uint64_t txnid, int committed) +{ + /* Unused parameters */ + (void)handler; + (void)session; + (void)txnid; + (void)committed; + + return (0); +} + +static int my_cursor_next(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } +static int my_cursor_prev(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } +static int my_cursor_reset(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } +static int my_cursor_search(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } +static int my_cursor_search_near(WT_CURSOR *wtcursor, int *exactp) + { (void)wtcursor; (void)exactp; return (0); } +static int my_cursor_insert(WT_CURSOR *wtcursor) +{ + WT_SESSION *session = NULL; + int ret; + + /* Unused parameters */ + (void)wtcursor; + + { + int is_snapshot_isolation, isolation_level; + /*! [WT_EXTENSION transaction isolation level] */ + isolation_level = wt_api->transaction_isolation_level(wt_api, session); + if (isolation_level == WT_TXN_ISO_SNAPSHOT) + is_snapshot_isolation = 1; + else + is_snapshot_isolation = 0; + /*! [WT_EXTENSION transaction isolation level] */ + (void)is_snapshot_isolation; + } + + { + /*! [WT_EXTENSION transaction ID] */ + uint64_t transaction_id; + + transaction_id = wt_api->transaction_id(wt_api, session); + /*! [WT_EXTENSION transaction ID] */ + (void)transaction_id; + } + + { + /*! [WT_EXTENSION transaction oldest] */ + uint64_t transaction_oldest; + + transaction_oldest = wt_api->transaction_oldest(wt_api); + /*! [WT_EXTENSION transaction oldest] */ + (void)transaction_oldest; + } + + { + /*! [WT_EXTENSION transaction notify] */ + WT_TXN_NOTIFY handler; + handler.notify = data_source_notify; + ret = wt_api->transaction_notify(wt_api, session, &handler); + /*! [WT_EXTENSION transaction notify] */ + } + + { + uint64_t transaction_id = 1; + int is_visible; + /*! [WT_EXTENSION transaction visible] */ + is_visible = + wt_api->transaction_visible(wt_api, session, transaction_id); + /*! [WT_EXTENSION transaction visible] */ + (void)is_visible; + } + + { + const char *key1 = NULL, *key2 = NULL; + uint32_t key1_len = 0, key2_len = 0; + WT_COLLATOR *collator = NULL; + /*! [WT_EXTENSION collate] */ + WT_ITEM first, second; + int cmp; + + first.data = key1; + first.size = key1_len; + second.data = key2; + second.size = key2_len; + + ret = wt_api->collate(wt_api, session, collator, &first, &second, &cmp); + if (cmp == 0) + printf("key1 collates identically to key2\n"); + else if (cmp < 0) + printf("key1 collates less than key2\n"); + else + printf("key1 collates greater than key2\n"); + /*! [WT_EXTENSION collate] */ + } + + return (ret); +} + +static int my_cursor_update(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } +static int my_cursor_remove(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } +static int my_cursor_close(WT_CURSOR *wtcursor) + { (void)wtcursor; return (0); } + +/*! [WT_DATA_SOURCE open_cursor] */ +typedef struct __my_cursor { + WT_CURSOR wtcursor; /* WiredTiger cursor, must come first */ + + /* + * Local cursor information: for example, we might want to have a + * reference to the extension functions. + */ + WT_EXTENSION_API *wtext; /* Extension functions */ +} MY_CURSOR; + +static int +my_open_cursor(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config, WT_CURSOR **new_cursor) +{ + MY_CURSOR *cursor; + + /* Allocate and initialize a WiredTiger cursor. */ + if ((cursor = calloc(1, sizeof(*cursor))) == NULL) + return (errno); + + cursor->wtcursor.next = my_cursor_next; + cursor->wtcursor.prev = my_cursor_prev; + cursor->wtcursor.reset = my_cursor_reset; + cursor->wtcursor.search = my_cursor_search; + cursor->wtcursor.search_near = my_cursor_search_near; + cursor->wtcursor.insert = my_cursor_insert; + cursor->wtcursor.update = my_cursor_update; + cursor->wtcursor.remove = my_cursor_remove; + cursor->wtcursor.close = my_cursor_close; + + /* + * Configure local cursor information. + */ + + /* Return combined cursor to WiredTiger. */ + *new_cursor = (WT_CURSOR *)cursor; + +/*! [WT_DATA_SOURCE open_cursor] */ + { + int ret = 0; + (void)dsrc; /* Unused parameters */ + (void)session; + (void)uri; + (void)new_cursor; + + { + /*! [WT_EXTENSION_CONFIG boolean] */ + WT_CONFIG_ITEM v; + int my_data_source_overwrite; + + /* + * 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); + } + my_data_source_overwrite = v.val != 0; + /*! [WT_EXTENSION_CONFIG boolean] */ + + (void)my_data_source_overwrite; + } + + { + /*! [WT_EXTENSION_CONFIG integer] */ + WT_CONFIG_ITEM v; + int64_t my_data_source_page_size; + + /* + * 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); + } + my_data_source_page_size = v.val; + /*! [WT_EXTENSION_CONFIG integer] */ + + (void)my_data_source_page_size; + } + + { + /*! [WT_EXTENSION config_get] */ + WT_CONFIG_ITEM v; + const char *my_data_source_key; + + /* + * 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); + } + + /* + * Values returned from WT_EXTENSION_API::config in the str field are + * not nul-terminated; the associated length must be used instead. + */ + if (v.len == 1 && v.str[0] == 'r') + my_data_source_key = "recno"; + else + my_data_source_key = "bytestring"; + /*! [WT_EXTENSION config_get] */ + + (void)my_data_source_key; + } + + { + /*! [WT_EXTENSION collator config] */ + WT_COLLATOR *collator; + int collator_owned; + /* + * 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); + } + /*! [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 ((ret = data_source_cursor()) != 0) { + (void)wt_api->err_printf(wt_api, + session, "my_open_cursor: %s", data_source_error(ret)); + return (WT_ERROR); + } + /*! [WT_DATA_SOURCE error message] */ + + { + /*! [WT_EXTENSION metadata insert] */ + /* + * Insert a new WiredTiger metadata record. + */ + 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); + } + /*! [WT_EXTENSION metadata insert] */ + } + + { + /*! [WT_EXTENSION metadata remove] */ + /* + * Remove a WiredTiger metadata record. + */ + 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); + } + /*! [WT_EXTENSION metadata remove] */ + } + + { + /*! [WT_EXTENSION metadata search] */ + /* + * Search for a WiredTiger metadata record. + */ + 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); + } + printf("metadata: %s has a value of %s\n", key, value); + /*! [WT_EXTENSION metadata search] */ + } + + { + /*! [WT_EXTENSION metadata update] */ + /* + * Update a WiredTiger metadata record (insert it if it does not yet + * exist, update it if it does). + */ + 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); + } + /*! [WT_EXTENSION metadata update] */ + } + + } + return (0); +} + +/*! [WT_DATA_SOURCE rename] */ +static int +my_rename(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, const char *newname, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE rename] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)newname; + (void)config; + + return (0); +} + +/*! [WT_DATA_SOURCE salvage] */ +static int +my_salvage(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE salvage] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)config; + + return (0); +} + +/*! [WT_DATA_SOURCE truncate] */ +static int +my_truncate(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE truncate] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)config; + + return (0); +} + +/*! [WT_DATA_SOURCE range truncate] */ +static int +my_range_truncate(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + WT_CURSOR *start, WT_CURSOR *stop) +/*! [WT_DATA_SOURCE range truncate] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)start; + (void)stop; + + return (0); +} + +/*! [WT_DATA_SOURCE verify] */ +static int +my_verify(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE verify] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)config; + + return (0); +} + +/*! [WT_DATA_SOURCE checkpoint] */ +static int +my_checkpoint(WT_DATA_SOURCE *dsrc, WT_SESSION *session, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE checkpoint] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)config; + + return (0); +} + +/*! [WT_DATA_SOURCE terminate] */ +static int +my_terminate(WT_DATA_SOURCE *dsrc, WT_SESSION *session) +/*! [WT_DATA_SOURCE terminate] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + + return (0); +} + +int +main(void) +{ + WT_CONNECTION *conn; + WT_SESSION *session; + int ret; + + ret = wiredtiger_open(NULL, NULL, "create", &conn); + ret = conn->open_session(conn, NULL, NULL, &session); + + my_data_source_init(conn); + + { + /*! [WT_DATA_SOURCE register] */ + static WT_DATA_SOURCE my_dsrc = { + my_create, + my_compact, + my_drop, + my_open_cursor, + my_rename, + my_salvage, + my_truncate, + my_range_truncate, + my_verify, + my_checkpoint, + my_terminate + }; + ret = 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); + /*! [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); + /*! [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); + /*! [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); + /*! [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, + "WT_SESSION.open_cursor", + NULL, "devices=5", "int", "min=1, max=30"); + /*! [WT_DATA_SOURCE configure integer with checking] */ + + /*! [WT_DATA_SOURCE configure string with checking] */ + /* + * Limit the target string to one of /device, /home or /target; default + * to /home. + */ + ret = conn->configure_method(conn, + "WT_SESSION.open_cursor", NULL, "target=/home", "string", + "choices=[/device, /home, /target]"); + /*! [WT_DATA_SOURCE configure string with checking] */ + + /*! [WT_DATA_SOURCE configure list with checking] */ + /* + * Limit the paths list to one or more of /device, /home, /mnt or + * /target; default to /mnt. + */ + ret = conn->configure_method(conn, + "WT_SESSION.open_cursor", NULL, "paths=[/mnt]", "list", + "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] */ + + (void)conn->close(conn, NULL); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_encrypt.c b/src/third_party/wiredtiger/examples/c/ex_encrypt.c new file mode 100644 index 00000000000..425ee6b7287 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_encrypt.c @@ -0,0 +1,593 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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> + +#ifdef _WIN32 +/* + * Explicitly export this function so it is visible when loading extensions. + */ +__declspec(dllexport) +#endif +int add_my_encryptors(WT_CONNECTION *connection); + +static const char *home = NULL; + +#define SYS_KEYID "system" +#define SYS_PW "system_password" +#define USER1_KEYID "user1" +#define USER2_KEYID "user2" +#define USERBAD_KEYID "userbad" + +#define ITEM_MATCHES(config_item, s) \ + (strlen(s) == (config_item).len && \ + strncmp((config_item).str, s, (config_item).len) == 0) + +/*! [encryption example callback implementation] */ +typedef struct { + WT_ENCRYPTOR encryptor; /* Must come first */ + int rot_N; /* rotN value */ + uint32_t num_calls; /* Count of calls */ + char *keyid; /* Saved keyid */ + char *password; /* Saved password */ +} MY_CRYPTO; + +#define CHKSUM_LEN 4 +#define IV_LEN 16 + +/* + * make_cksum -- + * This is where one would call a checksum function on the encrypted + * buffer. Here we just put a constant value in it. + */ +static void +make_cksum(uint8_t *dst) +{ + int i; + /* + * Assume array is big enough for the checksum. + */ + for (i = 0; i < CHKSUM_LEN; i++) + dst[i] = 'C'; +} + +/* + * make_iv -- + * This is where one would generate the initialization vector. + * Here we just put a constant value in it. + */ +static void +make_iv(uint8_t *dst) +{ + int i; + /* + * Assume array is big enough for the initialization vector. + */ + for (i = 0; i < IV_LEN; i++) + dst[i] = 'I'; +} + +/* + * Rotate encryption functions. + */ +/* + * do_rotate -- + * Perform rot-N on the buffer given. + */ +static void +do_rotate(char *buf, size_t len, int rotn) +{ + uint32_t i; + /* + * Now rotate + */ + for (i = 0; i < len; i++) + if (isalpha(buf[i])) { + if (islower(buf[i])) + buf[i] = ((buf[i] - 'a') + rotn) % 26 + 'a'; + else + buf[i] = ((buf[i] - 'A') + rotn) % 26 + 'A'; + } +} + +/* + * rotate_decrypt -- + * A simple rotate decryption. + */ +static int +rotate_decrypt(WT_ENCRYPTOR *encryptor, WT_SESSION *session, + uint8_t *src, size_t src_len, + uint8_t *dst, size_t dst_len, + size_t *result_lenp) +{ + MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor; + size_t mylen; + uint32_t i; + + (void)session; /* Unused */ + ++my_crypto->num_calls; + + if (src == NULL) + return (0); + /* + * Make sure it is big enough. + */ + mylen = src_len - (CHKSUM_LEN + IV_LEN); + if (dst_len < mylen) { + fprintf(stderr, + "Rotate: ENOMEM ERROR: dst_len %zu src_len %zu\n", + dst_len, src_len); + return (ENOMEM); + } + + /* + * !!! Most implementations would verify any needed + * checksum and initialize the IV here. + */ + /* + * Copy the encrypted data to the destination buffer and then + * decrypt the destination buffer in place. + */ + i = CHKSUM_LEN + IV_LEN; + memcpy(&dst[0], &src[i], mylen); + /* + * Call common rotate function on the text portion of the + * buffer. Send in dst_len as the length of the text. + */ + /* + * !!! Most implementations would need the IV too. + */ + do_rotate((char *)dst, mylen, 26 - my_crypto->rot_N); + *result_lenp = mylen; + return (0); +} + +/* + * rotate_encrypt -- + * A simple rotate encryption. + */ +static int +rotate_encrypt(WT_ENCRYPTOR *encryptor, WT_SESSION *session, + uint8_t *src, size_t src_len, + uint8_t *dst, size_t dst_len, + size_t *result_lenp) +{ + MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor; + uint32_t i; + + (void)session; /* Unused */ + ++my_crypto->num_calls; + + if (src == NULL) + return (0); + if (dst_len < src_len + CHKSUM_LEN + IV_LEN) + return (ENOMEM); + + i = CHKSUM_LEN + IV_LEN; + /* + * Skip over space reserved for checksum and initialization + * vector. Copy text into destination buffer then encrypt + * in place. + */ + memcpy(&dst[i], &src[0], src_len); + /* + * Call common rotate function on the text portion of the + * destination buffer. Send in src_len as the length of + * the text. + */ + do_rotate((char *)dst + i, src_len, my_crypto->rot_N); + /* + * Checksum the encrypted buffer and add the IV. + */ + i = 0; + make_cksum(&dst[i]); + i += CHKSUM_LEN; + make_iv(&dst[i]); + *result_lenp = dst_len; + return (0); +} + +/* + * rotate_sizing -- + * A sizing example that returns the header size needed. + */ +static int +rotate_sizing(WT_ENCRYPTOR *encryptor, WT_SESSION *session, + size_t *expansion_constantp) +{ + MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor; + + (void)session; /* Unused parameters */ + + ++my_crypto->num_calls; /* Call count */ + + *expansion_constantp = CHKSUM_LEN + IV_LEN; + return (0); +} + +/* + * rotate_customize -- + * The customize function creates a customized encryptor + */ +static int +rotate_customize(WT_ENCRYPTOR *encryptor, WT_SESSION *session, + WT_CONFIG_ARG *encrypt_config, WT_ENCRYPTOR **customp) +{ + MY_CRYPTO *my_crypto; + WT_CONFIG_ITEM keyid, secret; + WT_EXTENSION_API *extapi; + int ret; + const MY_CRYPTO *orig_crypto; + + extapi = session->connection->get_extension_api(session->connection); + + orig_crypto = (const MY_CRYPTO *)encryptor; + if ((my_crypto = calloc(1, sizeof(MY_CRYPTO))) == NULL) { + ret = errno; + goto err; + } + *my_crypto = *orig_crypto; + my_crypto->keyid = my_crypto->password = NULL; + + /* + * 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) { + if ((my_crypto->keyid = malloc(keyid.len + 1)) == NULL) { + ret = errno; + goto err; + } + strncpy(my_crypto->keyid, keyid.str, keyid.len + 1); + my_crypto->keyid[keyid.len] = '\0'; + } + + if ((ret = extapi->config_get(extapi, session, encrypt_config, + "secretkey", &secret)) == 0 && secret.len != 0) { + if ((my_crypto->password = malloc(secret.len + 1)) == NULL) { + ret = errno; + goto err; + } + strncpy(my_crypto->password, secret.str, secret.len + 1); + my_crypto->password[secret.len] = '\0'; + } + /* + * Presumably we'd have some sophisticated key management + * here that maps the id onto a secret key. + */ + if (ITEM_MATCHES(keyid, "system")) { + if (my_crypto->password == NULL || + strcmp(my_crypto->password, SYS_PW) != 0) { + ret = EPERM; + goto err; + } + my_crypto->rot_N = 13; + } else if (ITEM_MATCHES(keyid, USER1_KEYID)) + my_crypto->rot_N = 4; + else if (ITEM_MATCHES(keyid, USER2_KEYID)) + my_crypto->rot_N = 19; + else { + ret = EINVAL; + goto err; + } + + ++my_crypto->num_calls; /* Call count */ + + *customp = (WT_ENCRYPTOR *)my_crypto; + return (0); + +err: free(my_crypto->keyid); + free(my_crypto->password); + free(my_crypto); + return (ret); +} + +/* + * rotate_terminate -- + * WiredTiger rotate encryption termination. + */ +static int +rotate_terminate(WT_ENCRYPTOR *encryptor, WT_SESSION *session) +{ + MY_CRYPTO *my_crypto = (MY_CRYPTO *)encryptor; + + (void)session; /* Unused parameters */ + + ++my_crypto->num_calls; /* Call count */ + + /* Free the allocated memory. */ + free(my_crypto->password); + my_crypto->password = NULL; + + free(my_crypto->keyid); + my_crypto->keyid = NULL; + + free(encryptor); + + return (0); +} + +/* + * add_my_encryptors -- + * A simple example of adding encryption callbacks. + */ +int +add_my_encryptors(WT_CONNECTION *connection) +{ + MY_CRYPTO *m; + WT_ENCRYPTOR *wt; + int ret; + + /* + * Initialize our top level encryptor. + */ + if ((m = calloc(1, sizeof(MY_CRYPTO))) == NULL) + return (errno); + wt = (WT_ENCRYPTOR *)&m->encryptor; + wt->encrypt = rotate_encrypt; + wt->decrypt = rotate_decrypt; + wt->sizing = rotate_sizing; + 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); + + return (0); +} + +/* + * simple_walk_log -- + * A simple walk of the write-ahead log. + * We wrote text messages into the log. Print them. + * This verifies we're decrypting properly. + */ +static int +simple_walk_log(WT_SESSION *session) +{ + WT_CURSOR *cursor; + WT_ITEM logrec_key, logrec_value; + WT_LSN lsn; + uint64_t txnid; + uint32_t fileid, opcount, optype, rectype; + int found, ret; + + ret = session->open_cursor(session, "log:", NULL, NULL, &cursor); + + found = 0; + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &lsn.file, &lsn.offset, &opcount); + ret = cursor->get_value(cursor, &txnid, + &rectype, &optype, &fileid, &logrec_key, &logrec_value); + + if (rectype == WT_LOGREC_MESSAGE) { + found = 1; + printf("Application Log Record: %s\n", + (char *)logrec_value.data); + } + } + if (ret == WT_NOTFOUND) + ret = 0; + ret = cursor->close(cursor); + if (found == 0) { + fprintf(stderr, "Did not find log messages.\n"); + exit(EXIT_FAILURE); + } + return (ret); +} + +#define MAX_KEYS 20 + +#define EXTENSION_NAME "local=(entry=add_my_encryptors)" + +#define WT_OPEN_CONFIG_COMMON \ + "create,cache_size=100MB,extensions=[" EXTENSION_NAME "],"\ + "log=(archive=false,enabled=true)," \ + +#define WT_OPEN_CONFIG_GOOD \ + WT_OPEN_CONFIG_COMMON \ + "encryption=(name=rotn,keyid=" SYS_KEYID ",secretkey=" SYS_PW ")" + +#define COMP_A "AAAAAAAAAAAAAAAAAA" +#define COMP_B "BBBBBBBBBBBBBBBBBB" +#define COMP_C "CCCCCCCCCCCCCCCCCC" + +int +main(void) +{ + WT_CONNECTION *conn; + WT_CURSOR *c1, *c2, *nc; + WT_SESSION *session; + int i, ret; + 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); + + ret = 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, + 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); + + /* + * Create and open some encrypted and not encrypted tables. + * Also use column store and compression for some tables. + */ + ret = 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", + "encryption=(name=rotn,keyid=" USER1_KEYID")," + "columns=(value0,key0)"); + ret = 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"); + + /* + * Send in an unknown keyid. WiredTiger will try to add in the + * new keyid, but the customize function above will return an + * error since it is unrecognized. + */ + ret = session->create(session, "table:cryptobad", + "encryption=(name=rotn,keyid=" USERBAD_KEYID")," + "key_format=S,value_format=S"); + if (ret == 0) { + fprintf(stderr, "Did not detect bad/unknown keyid error\n"); + 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); + + /* + * Insert a set of keys and values. Insert the same data into + * all tables so that we can verify they're all the same after + * we decrypt on read. + */ + for (i = 0; i < MAX_KEYS; i++) { + snprintf(keybuf, sizeof(keybuf), "key%d", i); + c1->set_key(c1, keybuf); + c2->set_key(c2, keybuf); + nc->set_key(nc, keybuf); + + snprintf(valbuf, sizeof(valbuf), "value%d", i); + c1->set_value(c1, valbuf); + c2->set_value(c2, valbuf); + nc->set_value(nc, valbuf); + + ret = c1->insert(c1); + ret = c2->insert(c2); + ret = nc->insert(nc); + if (i % 5 == 0) + ret = session->log_printf(session, + "Wrote %d records", i); + } + ret = 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); + + printf("Read key %s; value %s\n", key1, val1); + } + ret = simple_walk_log(session); + printf("CLOSE\n"); + ret = conn->close(conn, NULL); + + /* + * We want to close and reopen so that we recreate the cache + * by reading the data from disk, forcing decryption. + */ + printf("REOPEN and VERIFY encrypted data\n"); + + ret = wiredtiger_open(home, NULL, WT_OPEN_CONFIG_GOOD, &conn); + + ret = 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); + + /* + * 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); + + if (strcmp(key1, key2) != 0) + fprintf(stderr, "Key1 %s and Key2 %s do not match\n", + key1, key2); + if (strcmp(key1, key3) != 0) + fprintf(stderr, "Key1 %s and Key3 %s do not match\n", + key1, key3); + if (strcmp(key2, key3) != 0) + fprintf(stderr, "Key2 %s and Key3 %s do not match\n", + key2, key3); + if (strcmp(val1, val2) != 0) + fprintf(stderr, "Val1 %s and Val2 %s do not match\n", + val1, val2); + if (strcmp(val1, val3) != 0) + fprintf(stderr, "Val1 %s and Val3 %s do not match\n", + val1, val3); + if (strcmp(val2, val3) != 0) + fprintf(stderr, "Val2 %s and Val3 %s do not match\n", + val2, val3); + + printf("Verified key %s; value %s\n", key1, val1); + } + ret = conn->close(conn, NULL); + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_extending.c b/src/third_party/wiredtiger/examples/c/ex_extending.c new file mode 100644 index 00000000000..4d265ae1d2b --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_extending.c @@ -0,0 +1,133 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_extending.c + * 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 + +static const char *home; + +/*! [case insensitive comparator] */ +/* A simple case insensitive comparator. */ +static int +__compare_nocase(WT_COLLATOR *collator, WT_SESSION *session, + const WT_ITEM *v1, const WT_ITEM *v2, int *cmp) +{ + const char *s1 = (const char *)v1->data; + const char *s2 = (const char *)v2->data; + + (void)session; /* unused */ + (void)collator; /* unused */ + + *cmp = strcasecmp(s1, s2); + return (0); +} + +static WT_COLLATOR nocasecoll = { __compare_nocase, NULL, NULL }; +/*! [case insensitive comparator] */ + +/*! [n character comparator] */ +/* + * Comparator that only compares the first N prefix characters of the string. + * This has associated data, so we need to extend WT_COLLATOR. + */ +typedef struct { + WT_COLLATOR iface; + uint32_t maxlen; +} PREFIX_COLLATOR; + +static int +__compare_prefixes(WT_COLLATOR *collator, WT_SESSION *session, + const WT_ITEM *v1, const WT_ITEM *v2, int *cmp) +{ + PREFIX_COLLATOR *pcoll = (PREFIX_COLLATOR *)collator; + const char *s1 = (const char *)v1->data; + const char *s2 = (const char *)v2->data; + + (void)session; /* unused */ + + *cmp = strncmp(s1, s2, pcoll->maxlen); + return (0); +} + +static PREFIX_COLLATOR pcoll10 = { {__compare_prefixes, NULL, NULL}, 10 }; +/*! [n character comparator] */ + +int +main(void) +{ + 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; + + /* 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, wiredtiger_strerror(ret)); + + /*! [add collator nocase] */ + ret = conn->add_collator(conn, "nocase", &nocasecoll, NULL); + /*! [add collator nocase] */ + /*! [add collator prefix10] */ + ret = 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, wiredtiger_strerror(ret)); + + /* XXX Do some work... */ + + /* Note: closing the connection implicitly closes open session(s). */ + if ((ret = conn->close(conn, NULL)) != 0) + /*! [add collator prefix10] */ + fprintf(stderr, "Error closing %s: %s\n", + home, wiredtiger_strerror(ret)); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_extractor.c b/src/third_party/wiredtiger/examples/c/ex_extractor.c new file mode 100644 index 00000000000..fff9c79f8e0 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_extractor.c @@ -0,0 +1,284 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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); + +static const char *home; + +struct president_data { + int id; + const char *last_name; + const char *first_name; + uint16_t term_start; + uint16_t term_end; +}; + +static const struct president_data example_data[] = { + { 0, "Obama", "Barack", 2009, 2014 }, + { 1, "Bush", "George W", 2001, 2009 }, + { 2, "Clinton", "Bill", 1993, 2001 }, + { 3, "Bush", "George H", 1989, 1993 }, + { 4, "Reagan", "Ronald", 1981, 1989 }, + { 0, NULL, NULL, 0, 0 } +}; +/* + * Number of years this data spans + */ +#define YEAR_BASE 1981 +#define YEAR_SPAN (2014-1981) + +/* + * A custom index extractor function that adds an index entry for each year of + * the given president's term. + */ +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; + + /* Unused parameters */ + (void)extractor; + (void)key; + + /* Unpack the value. */ + if ((ret = wiredtiger_struct_unpack( + session, value->data, value->size, "SSHH", + &last_name, &first_name, &term_start, &term_end)) != 0) + return (ret); + + /* + * We have overlapping years, so multiple records may share the same + * index key. + */ + for (year = term_start; year <= term_end; ++year) { + /* + * Note that the extract callback is called for all operations + * that update the table, not just inserts. The user sets the + * key and uses the cursor->insert() method to return the index + * key(s). WiredTiger will perform the required operation + * (such as a remove()). + */ + fprintf(stderr, "EXTRACTOR: index op for year %d: %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 %d: error %d\n", + year, ret); + return (ret); + } + } + return (0); +} + +/* + * The terminate method is called to release any allocated resources when the + * table is closed. In this example, no cleanup is required. + */ +static int +my_extract_terminate(WT_EXTRACTOR *extractor, WT_SESSION *session) +{ + (void)extractor; + (void)session; + + return (0); +} + +int +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); +} + +/* + * Read the index by year and print out who was in office that year. + */ +static int +read_index(WT_SESSION *session) +{ + WT_CURSOR *cursor; + int i, ret; + char *first_name, *last_name; + uint16_t rec_year, term_end, term_start, year; + + year = 0; + srand((unsigned int)getpid()); + ret = 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++) { + year = (uint16_t)((rand() % YEAR_SPAN) + YEAR_BASE); + printf("Year %d:\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; + + /* Report all presidents that served during the chosen year */ + 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; + } + } + if (!RET_OK(ret)) + fprintf(stderr, "Error %d for year %d\n", ret, year); + + ret = cursor->close(cursor); + return (ret); +} + +/* + * Remove some items from the primary table. + */ +static int +remove_items(WT_SESSION *session) +{ + WT_CURSOR *cursor; + struct president_data p; + int i, ret; + + /* + * 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); + /* + * 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); + } + return (ret); +} + +/* + * Set up the table and index of the data. + */ +static int +setup_table(WT_SESSION *session) +{ + WT_CURSOR *cursor; + struct president_data p; + int i, ret; + + /* Create the primary table. It has a key of the unique ID. */ + ret = session->create(session, "table:presidents", + "key_format=I,value_format=SSHH," + "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"); + + ret = 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); + cursor->set_value(cursor, + p.last_name, p.first_name, p.term_start, p.term_end); + fprintf(stderr, "SETUP: table insert %d-%d: %s %s\n", + p.term_start, p.term_end, + p.first_name, p.last_name); + ret = cursor->insert(cursor); + } + return (ret); +} + +int +main(void) +{ + 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; + + ret = wiredtiger_open(home, NULL, "create,cache_size=500M", &conn); + ret = add_extractor(conn); + ret = conn->open_session(conn, NULL, NULL, &session); + + ret = setup_table(session); + ret = read_index(session); + ret = remove_items(session); + + ret = conn->close(conn, NULL); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_hello.c b/src/third_party/wiredtiger/examples/c/ex_hello.c new file mode 100644 index 00000000000..345e434741f --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_hello.c @@ -0,0 +1,76 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_hello.c + * 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> + +static const char *home; + +int +main(void) +{ + 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; + + /* 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, wiredtiger_strerror(ret)); + + /* 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, wiredtiger_strerror(ret)); + + /* 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, wiredtiger_strerror(ret)); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_log.c b/src/third_party/wiredtiger/examples/c/ex_log.c new file mode 100644 index 00000000000..cc6a3c46b93 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_log.c @@ -0,0 +1,358 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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> + +static const char *home1 = "WT_HOME_LOG_1"; +static const char *home2 = "WT_HOME_LOG_2"; + +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 +setup_copy(WT_CONNECTION **wt_connp, WT_SESSION **sessionp) +{ + int ret; + + 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); +} + +static int +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); + + 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); + 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); + } + } + if (ret != WT_NOTFOUND) + fprintf(stderr, + "WT_CURSOR.next: %s\n", session->strerror(session, ret)); + ret = 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); + + return (ret); +} + +/*! [log cursor walk] */ +static void +print_record(WT_LSN *lsn, uint32_t opcount, + uint32_t rectype, uint32_t optype, uint64_t txnid, uint32_t fileid, + WT_ITEM *key, WT_ITEM *value) +{ + printf( + "LSN [%" PRIu32 "][%" PRIu64 "].%" PRIu32 + ": record type %" PRIu32 " optype %" PRIu32 + " txnid %" PRIu64 " fileid %" PRIu32, + lsn->file, (uint64_t)lsn->offset, opcount, + rectype, optype, txnid, fileid); + printf(" key size %zu value size %zu\n", key->size, value->size); + if (rectype == WT_LOGREC_MESSAGE) + printf("Application Record: %s\n", (char *)value->data); +} + +/* + * simple_walk_log -- + * A simple walk of the log. + */ +static int +simple_walk_log(WT_SESSION *session, int count_min) +{ + WT_CURSOR *cursor; + WT_LSN lsn; + WT_ITEM logrec_key, logrec_value; + uint64_t txnid; + uint32_t fileid, opcount, optype, rectype; + int count, ret; + + /*! [log cursor open] */ + ret = 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, &lsn.file, &lsn.offset, &opcount); + /*! [log cursor get_key] */ + /*! [log cursor get_value] */ + ret = cursor->get_value(cursor, &txnid, + &rectype, &optype, &fileid, &logrec_key, &logrec_value); + /*! [log cursor get_value] */ + + print_record(&lsn, opcount, + rectype, optype, txnid, fileid, &logrec_key, &logrec_value); + } + if (ret == WT_NOTFOUND) + ret = 0; + ret = cursor->close(cursor); + if (count < count_min) { + fprintf(stderr, + "Expected minimum %d records, found %d\n", + count_min, count); + abort(); + } + return (ret); +} +/*! [log cursor walk] */ + +static int +walk_log(WT_SESSION *session) +{ + WT_CONNECTION *wt_conn2; + WT_CURSOR *cursor, *cursor2; + WT_LSN lsn, lsnsave; + WT_ITEM logrec_key, logrec_value; + WT_SESSION *session2; + uint64_t txnid; + uint32_t fileid, opcount, optype, rectype; + 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); + i = 0; + in_txn = 0; + txnid = 0; + memset(&lsnsave, 0, sizeof(lsnsave)); + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &lsn.file, &lsn.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 + * that LSN to the end (where the multi-step transaction + * was performed). Just choose the record that is MAX_KEYS. + */ + if (++i == MAX_KEYS) + lsnsave = lsn; + ret = cursor->get_value(cursor, &txnid, &rectype, + &optype, &fileid, &logrec_key, &logrec_value); + + print_record(&lsn, opcount, + rectype, optype, txnid, fileid, &logrec_key, &logrec_value); + + /* + * If we are in a transaction and this is a new one, end + * the previous one. + */ + if (in_txn && opcount == 0) { + ret = session2->commit_transaction(session2, NULL); + in_txn = 0; + } + + /* + * If the operation is a put, replay it here on the backup + * connection. + * + * !!! + * Minor cheat: the metadata is fileid 0, skip its records. + */ + if (fileid != 0 && + rectype == WT_LOGREC_COMMIT && optype == WT_LOGOP_ROW_PUT) { + if (!in_txn) { + ret = session2->begin_transaction(session2, + NULL); + in_txn = 1; + } + cursor2->set_key(cursor2, &logrec_key); + cursor2->set_value(cursor2, &logrec_value); + ret = cursor2->insert(cursor2); + } + } + if (in_txn) + ret = session2->commit_transaction(session2, NULL); + + ret = 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); + + ret = cursor->reset(cursor); + /*! [log cursor set_key] */ + cursor->set_key(cursor, lsnsave.file, lsnsave.offset, 0); + /*! [log cursor set_key] */ + /*! [log cursor search] */ + ret = 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, + &lsn.file, &lsn.offset, &opcount)) == 0) { + if (first) { + first = 0; + if (lsnsave.file != lsn.file || + lsnsave.offset != lsn.offset) { + fprintf(stderr, + "search returned the wrong LSN\n"); + exit (1); + } + } + ret = cursor->get_value(cursor, &txnid, &rectype, + &optype, &fileid, &logrec_key, &logrec_value); + + print_record(&lsn, opcount, + rectype, optype, txnid, fileid, &logrec_key, &logrec_value); + + ret = cursor->next(cursor); + if (ret != 0) + break; + } + ret = cursor->close(cursor); + return (ret); +} + +int +main(void) +{ + WT_CONNECTION *wt_conn; + WT_CURSOR *cursor; + WT_SESSION *session; + int count_min, i, record_count, ret; + char cmd_buf[256], k[16], v[16]; + + count_min = 0; + 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 (ret); + } + if ((ret = wiredtiger_open(home1, NULL, CONN_CONFIG, &wt_conn)) != 0) { + fprintf(stderr, "Error connecting to %s: %s\n", + home1, wiredtiger_strerror(ret)); + return (ret); + } + + ret = wt_conn->open_session(wt_conn, NULL, NULL, &session); + ret = session->create(session, uri, "key_format=S,value_format=S"); + count_min++; + + ret = session->open_cursor(session, uri, NULL, NULL, &cursor); + /* + * Perform some operations with individual auto-commit transactions. + */ + for (record_count = 0, i = 0; i < MAX_KEYS; i++, record_count++) { + snprintf(k, sizeof(k), "key%d", i); + snprintf(v, sizeof(v), "value%d", i); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = cursor->insert(cursor); + count_min++; + } + ret = session->begin_transaction(session, NULL); + /* + * Perform some operations within a single transaction. + */ + for (i = MAX_KEYS; i < MAX_KEYS+5; i++, record_count++) { + snprintf(k, sizeof(k), "key%d", i); + snprintf(v, sizeof(v), "value%d", i); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = cursor->insert(cursor); + } + ret = session->commit_transaction(session, NULL); + count_min++; + ret = cursor->close(cursor); + + /*! [log cursor printf] */ + ret = session->log_printf(session, "Wrote %d records", record_count); + count_min++; + /*! [log cursor printf] */ + + /* + * 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 (ret); + } + + 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); + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_pack.c b/src/third_party/wiredtiger/examples/c/ex_pack.c new file mode 100644 index 00000000000..43b57880674 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_pack.c @@ -0,0 +1,89 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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> + +static const char *home; + +int +main(void) +{ + WT_CONNECTION *conn; + WT_SESSION *session; + int i, j, k, 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) + fprintf(stderr, "Error connecting to %s: %s\n", + home, wiredtiger_strerror(ret)); + + /* 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, wiredtiger_strerror(ret)); + + { + /*! [packing] */ + size_t size; + char buf[50]; + + ret = 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); + + ret = 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, wiredtiger_strerror(ret)); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_process.c b/src/third_party/wiredtiger/examples/c/ex_process.c new file mode 100644 index 00000000000..19f395dddaf --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_process.c @@ -0,0 +1,79 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_process.c + * 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> + +static const char *home; + +int +main(void) +{ + 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; + + /*! [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, wiredtiger_strerror(ret)); + + /* 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, wiredtiger_strerror(ret)); + + /* 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, wiredtiger_strerror(ret)); + /*! [processes] */ + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_schema.c b/src/third_party/wiredtiger/examples/c/ex_schema.c new file mode 100644 index 00000000000..fdf02d12302 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_schema.c @@ -0,0 +1,364 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_schema.c + * 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> + +static const char *home; + +/*! [schema declaration] */ +/* The C struct for the data we are storing in a WiredTiger table. */ +typedef struct { + char country[5]; + uint16_t year; + uint64_t population; +} POP_RECORD; + +static POP_RECORD pop_data[] = { + { "AU", 1900, 4000000 }, + { "AU", 1950, 8267337 }, + { "AU", 2000, 19053186 }, + { "CAN", 1900, 5500000 }, + { "CAN", 1950, 14011422 }, + { "CAN", 2000, 31099561 }, + { "UK", 1900, 369000000 }, + { "UK", 1950, 50127000 }, + { "UK", 2000, 59522468 }, + { "USA", 1900, 76212168 }, + { "USA", 1950, 150697361 }, + { "USA", 2000, 301279593 }, + { "", 0, 0 } +}; +/*! [schema declaration] */ + +int +main(void) +{ + POP_RECORD *p; + WT_CONNECTION *conn; + WT_CURSOR *cursor, *cursor2, *join_cursor; + WT_SESSION *session; + const char *country; + uint64_t recno, population; + 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", &conn)) != 0) { + fprintf(stderr, "Error connecting to %s: %s\n", + home, wiredtiger_strerror(ret)); + return (ret); + } + /* Note: error checking omitted for clarity. */ + + ret = conn->open_session(conn, NULL, NULL, &session); + + /*! [Create a table with column groups] */ + /* + * Create the population table. + * Keys are record numbers, the format for values is (5-byte string, + * uint16_t, uint64_t). + * See ::wiredtiger_struct_pack for details of the format strings. + */ + ret = session->create(session, "table:poptable", + "key_format=r," + "value_format=5sHQ," + "columns=(id,country,year,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)"); + /*! [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)"); + /*! [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)"); + /*! [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"); + /*! [Create an immutable index] */ + + /* Insert the records into the table. */ + ret = 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); + } + ret = cursor->close(cursor); + + /* Update records in the table. */ + ret = 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); + cursor->set_value(cursor, country, year, population + 1); + ret = cursor->update(cursor); + } + ret = cursor->close(cursor); + + /* List the records in the table. */ + ret = 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); + printf("ID %" PRIu64, recno); + printf(": country %s, year %u, population %" PRIu64 "\n", + country, year, population); + } + ret = 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); + 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); + printf("ID %" PRIu64, recno); + + ret = cursor->get_value(cursor, &value); + ret = wiredtiger_struct_unpack(session, + value.data, value.size, + "5sHQ", &country, &year, &population); + printf(": country %s, year %u, population %" PRIu64 "\n", + country, year, population); + } + /*! [List the records in the table using raw mode.] */ + ret = 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); + 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 %u, population %" PRIu64 "\n", + country, year, population); + } + /*! [Read population from the primary column group] */ + ret = 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); + cursor->set_key(cursor, 2); + if ((ret = cursor->search(cursor)) == 0) { + ret = cursor->get_value(cursor, &population); + printf("ID 2: population %" PRIu64 "\n", population); + } + /*! [Read population from the standalone column group] */ + ret = cursor->close(cursor); + + /*! [Search in a simple index] */ + /* Search in a simple index. */ + ret = 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); + printf("AU: country %s, year %u, population %" PRIu64 "\n", + country, (unsigned int)year, population); + /*! [Search in a simple index] */ + ret = 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); + cursor->set_key(cursor, "USA\0\0", (uint16_t)1900); + ret = cursor->search(cursor); + ret = cursor->get_value(cursor, &country, &year, &population); + printf("US 1900: country %s, year %u, population %" PRIu64 "\n", + country, (unsigned int)year, population); + /*! [Search in a composite index] */ + ret = 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); + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_value(cursor, &country, &year); + printf("country %s, year %u\n", country, year); + } + /*! [Return a subset of values from the table] */ + ret = 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); + 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); + printf("country %s, year %u\n", country, year); + } + /*! [Return a subset of values from the table using raw mode] */ + ret = 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); + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &country, &year); + ret = cursor->get_value(cursor, &recno); + printf("row ID %" PRIu64 ": country %s, year %u\n", + recno, country, year); + } + /*! [Return the table's record number key using an index] */ + ret = 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, + "index:poptable:country_plus_year(population)", + NULL, NULL, &cursor); + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &country, &year); + ret = cursor->get_value(cursor, &population); + printf("population %" PRIu64 ": country %s, year %u\n", + population, country, year); + } + /*! [Return a subset of the value columns from an index] */ + ret = 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); + while ((ret = cursor->next(cursor)) == 0) { + ret = cursor->get_key(cursor, &country, &year); + printf("country %s, year %u\n", country, year); + } + /*! [Access only the index] */ + ret = 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, &cursor); + ret = session->open_cursor(session, + "index:poptable:immutable_year", NULL, NULL, &cursor2); + + /* select values WHERE country == "AU" AND year > 1900 */ + cursor->set_key(cursor, "AU\0\0\0"); + ret = cursor->search(cursor); + ret = session->join(session, join_cursor, cursor, + "compare=eq,count=10"); + cursor2->set_key(cursor2, (uint16_t)1900); + ret = cursor2->search(cursor2); + ret = session->join(session, join_cursor, cursor2, + "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); + printf("ID %" PRIu64, recno); + printf(": country %s, year %u, population %" PRIu64 "\n", + country, year, population); + } + /*! [Join cursors] */ + ret = join_cursor->close(join_cursor); + ret = cursor2->close(cursor2); + ret = cursor->close(cursor); + + ret = conn->close(conn, NULL); + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_scope.c b/src/third_party/wiredtiger/examples/c/ex_scope.c new file mode 100644 index 00000000000..93878ec7e3d --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_scope.c @@ -0,0 +1,214 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_scope.c + * demonstrates the scope of buffers holding cursor keys and values. + */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <wiredtiger.h> + +#ifdef _WIN32 +/* snprintf is not supported on <= VS2013 */ +#define snprintf _snprintf +#endif + +static const char *home; + +static int +cursor_scope_ops(WT_CURSOR *cursor) +{ + struct { + const char *op; + const char *key; + const char *value; + int (*apply)(WT_CURSOR *); + } *op, ops[] = { + { "insert", "key1", "value1", cursor->insert, }, + { "update", "key1", "value2", cursor->update, }, + { "search", "key1", "value2", cursor->search, }, + { "remove", "key1", "value2", cursor->remove, }, + { NULL, NULL, NULL, NULL } + }; + WT_SESSION *session; + const char *key, *value; + char keybuf[10], valuebuf[10]; + int ret; + + session = cursor->session; + + for (op = ops; op->key != NULL; op++) { + key = value = NULL; + + /*! [cursor scope operation] */ + (void)snprintf(keybuf, sizeof(keybuf), "%s", op->key); + cursor->set_key(cursor, keybuf); + (void)snprintf(valuebuf, sizeof(valuebuf), "%s", op->value); + cursor->set_value(cursor, valuebuf); + + /* + * The application must keep key and value memory valid until + * the next operation that positions the cursor, modifies the + * data, or resets or closes the cursor. + * + * Modifying either the key or value buffers is not permitted. + */ + + /* Apply the operation (insert, update, search or remove). */ + if ((ret = op->apply(cursor)) != 0) { + fprintf(stderr, + "%s: error performing the operation: %s\n", + op->op, session->strerror(session, ret)); + return (ret); + } + + /* + * The cursor no longer references application memory, so + * application buffers can be safely overwritten. + */ + strcpy(keybuf, "no key"); + strcpy(valuebuf, "no value"); + + /* + * Check that get_key/value behave as expected after the + * operation. + */ + if (op->apply == cursor->insert) { + /* + * WT_CURSOR::insert no longer references application + * memory, but as it does not position the cursor, it + * doesn't reference memory owned by the cursor, either. + */ + if ((ret = cursor->get_key(cursor, &key)) == 0 || + (ret = cursor->get_value(cursor, &value)) == 0) { + fprintf(stderr, + "%s: error in s get_key/value: %s\n", + op->op, session->strerror(session, ret)); + return (ret); + } + continue; + } + if (op->apply == cursor->remove) { + /* + * WT_CURSOR::remove no longer references application + * memory; as it does not position the cursor, it will + * reference key memory owned by the cursor, but has no + * value. + */ + if ((ret = cursor->get_key(cursor, &key)) != 0 || + (ret = cursor->get_value(cursor, &value)) == 0) { + fprintf(stderr, + "%s: error in get_key/value: %s\n", + op->op, session->strerror(session, ret)); + return (ret); + } + } else /* search, update */{ + /* + * WT_CURSOR::search and WT_CURSOR::update no longer + * reference application memory; as they position the + * cursor, they will reference key/value memory owned + * by the cursor. + */ + if ((ret = cursor->get_key(cursor, &key)) != 0 || + (ret = cursor->get_value(cursor, &value)) != 0) { + fprintf(stderr, + "%s: error in get_key/value: %s\n", + op->op, session->strerror(session, ret)); + return (ret); + } + } + + /* + * Modifying the memory referenced by either key or value is + * not permitted. + * + * Check that the cursor's key and value are what we expect. + */ + if (key == keybuf || + (op->apply != cursor->remove && value == valuebuf)) { + fprintf(stderr, + "%s: cursor points at application memory!\n", + op->op); + return (EINVAL); + } + + if (strcmp(key, op->key) != 0 || + (op->apply != cursor->remove && + strcmp(value, op->value) != 0)) { + fprintf(stderr, + "%s: unexpected key / value!\n", op->op); + return (EINVAL); + } + /*! [cursor scope operation] */ + } + + return (0); +} + +int +main(void) +{ + WT_CONNECTION *conn; + WT_CURSOR *cursor; + WT_SESSION *session; + int ret, tret; + + /* + * 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, create a simple table, open a cursor. */ + 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, wiredtiger_strerror(ret)); + return (ret); + } + + ret = session->create(session, + "table:scope", "key_format=S,value_format=S,columns=(k,v)"); + + ret = session->open_cursor(session, + "table:scope", NULL, NULL, &cursor); + + ret = cursor_scope_ops(cursor); + + /* Close the connection and clean up. */ + if ((tret = conn->close(conn, NULL)) != 0 && ret == 0) + ret = tret; + + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_stat.c b/src/third_party/wiredtiger/examples/c/ex_stat.c new file mode 100644 index 00000000000..65402230eb8 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_stat.c @@ -0,0 +1,227 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_stat.c + * This is an example demonstrating how to query database statistics. + */ + +#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_overflow_pages(WT_SESSION *); +int get_stat(WT_CURSOR *cursor, int stat_field, uint64_t *valuep); +int print_derived_stats(WT_SESSION *); + +static const char *home; + +/*! [statistics display function] */ +int +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) + if (value != 0) + printf("%s=%s\n", desc, pvalue); + + return (ret == WT_NOTFOUND ? 0 : ret); +} +/*! [statistics display function] */ + +int +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); + + ret = print_cursor(cursor); + ret = cursor->close(cursor); + /*! [statistics database function] */ + + return (ret); +} + +int +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); + + ret = print_cursor(cursor); + ret = cursor->close(cursor); + /*! [statistics table function] */ + + return (ret); +} + +int +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); + + cursor->set_key(cursor, WT_STAT_DSRC_BTREE_OVERFLOW); + ret = cursor->search(cursor); + ret = cursor->get_value(cursor, &desc, &pvalue, &value); + printf("%s=%s\n", desc, pvalue); + + ret = cursor->close(cursor); + /*! [statistics retrieve by key] */ + + return (ret); +} + +/*! [statistics calculation helper function] */ +int +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)); +} +/*! [statistics calculation helper function] */ + +int +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); + /*! [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); + + percent = 0; + if (file_size != 0) + percent = 100 * ((file_size - ckpt_size) / file_size); + printf("Table is %" PRIu64 "%% fragmented\n", percent); + /*! [statistics calculate table fragmentation] */ + } + + { + /*! [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); + + ret = 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", + (double)fs_writes / (app_insert + app_remove + app_update)); + /*! [statistics calculate write amplification] */ + } + + ret = cursor->close(cursor); + + return (ret); +} + +int +main(void) +{ + 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"); + + ret = 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); + + ret = session->checkpoint(session, NULL); + + ret = print_database_stats(session); + + ret = print_file_stats(session); + + ret = print_overflow_pages(session); + + ret = print_derived_stats(session); + + return (conn->close(conn, NULL) == 0 ? ret : EXIT_FAILURE); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_sync.c b/src/third_party/wiredtiger/examples/c/ex_sync.c new file mode 100644 index 00000000000..8c3a6463a82 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_sync.c @@ -0,0 +1,153 @@ +/* + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * 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 <wiredtiger.h> + +static const char *home = "WT_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) +{ + WT_CONNECTION *wt_conn; + WT_CURSOR *cursor; + WT_SESSION *session; + int i, record_count, ret; + char cmd_buf[256], k[16], v[16]; + const char *conf; + + 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 (ret); + } + if ((ret = wiredtiger_open(home, NULL, CONN_CONFIG, &wt_conn)) != 0) { + fprintf(stderr, "Error connecting to %s: %s\n", + home, wiredtiger_strerror(ret)); + return (ret); + } + + ret = wt_conn->open_session(wt_conn, NULL, NULL, &session); + ret = session->create(session, uri, "key_format=S,value_format=S"); + + ret = session->open_cursor(session, uri, NULL, NULL, &cursor); + /* + * Perform some operations with individual auto-commit transactions. + */ + ret = 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"); + 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 ((record_count % 3) == 0) + conf = "sync=background"; + else + conf = "sync=off"; + ret = session->commit_transaction(session, conf); + ret = session->begin_transaction(session, NULL); + } + snprintf(k, sizeof(k), "key%d", i); + snprintf(v, sizeof(v), "value%d", i); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = cursor->insert(cursor); + } + ret = session->commit_transaction(session, "sync=background"); + printf("Wait forever until stable\n"); + ret = session->transaction_sync(session, NULL); + printf("Transactions now stable\n"); + ret = session->begin_transaction(session, NULL); + /* + * Perform some operations within a single transaction. + */ + for (i = MAX_KEYS; i < MAX_KEYS+5; i++, record_count++) { + snprintf(k, sizeof(k), "key%d", i); + snprintf(v, sizeof(v), "value%d", i); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = 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); + /* + * Demonstrate using log_flush to force the log to disk. + */ + for (i = 0; i < MAX_KEYS; i++, record_count++) { + snprintf(k, sizeof(k), "key%d", record_count); + snprintf(v, sizeof(v), "value%d", record_count); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = cursor->insert(cursor); + } + ret = session->log_flush(session, "sync=on"); + + for (i = 0; i < MAX_KEYS; i++, record_count++) { + snprintf(k, sizeof(k), "key%d", record_count); + snprintf(v, sizeof(v), "value%d", record_count); + cursor->set_key(cursor, k); + cursor->set_value(cursor, v); + ret = cursor->insert(cursor); + } + ret = cursor->close(cursor); + ret = session->log_flush(session, "sync=off"); + ret = session->log_flush(session, "sync=on"); + + ret = wt_conn->close(wt_conn, NULL); + return (ret); +} diff --git a/src/third_party/wiredtiger/examples/c/ex_thread.c b/src/third_party/wiredtiger/examples/c/ex_thread.c new file mode 100644 index 00000000000..a72211b6243 --- /dev/null +++ b/src/third_party/wiredtiger/examples/c/ex_thread.c @@ -0,0 +1,127 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_thread.c + * This is an example demonstrating how to create and access a simple + * table from multiple threads. + */ + +#ifndef _WIN32 +#include <pthread.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef _WIN32 +#include "windows_shim.h" +#endif + +#include <wiredtiger.h> + +static const char *home; + +void *scan_thread(void *arg); + +#define NUM_THREADS 10 + +/*! [thread scan] */ +void * +scan_thread(void *conn_arg) +{ + WT_CONNECTION *conn; + WT_CURSOR *cursor; + WT_SESSION *session; + const char *key, *value; + int ret; + + conn = conn_arg; + ret = conn->open_session(conn, NULL, NULL, &session); + ret = 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); + + printf("Got record: %s : %s\n", key, value); + } + if (ret != WT_NOTFOUND) + fprintf(stderr, + "WT_CURSOR.next: %s\n", session->strerror(session, ret)); + + return (NULL); +} +/*! [thread scan] */ + +/*! [thread main] */ +int +main(void) +{ + WT_CONNECTION *conn; + WT_SESSION *session; + WT_CURSOR *cursor; + pthread_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, 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); + cursor->set_key(cursor, "key1"); + cursor->set_value(cursor, "value1"); + ret = cursor->insert(cursor); + ret = session->close(session, NULL); + + for (i = 0; i < NUM_THREADS; i++) + ret = pthread_create(&threads[i], NULL, scan_thread, conn); + + for (i = 0; i < NUM_THREADS; i++) + ret = pthread_join(threads[i], NULL); + + ret = conn->close(conn, NULL); + + return (ret); +} +/*! [thread main] */ diff --git a/src/third_party/wiredtiger/examples/java/Makefile.am b/src/third_party/wiredtiger/examples/java/Makefile.am new file mode 100644 index 00000000000..c7fbfffa48c --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/Makefile.am @@ -0,0 +1,21 @@ +AM_CPPFLAGS = -I$(abs_top_builddir) + +JAVAEXAMPLES = $(top_srcdir)/examples/java/com/wiredtiger/examples + +# TODO: How to add to existing Javadoc from main API? +# JDOCDIR = $(top_srcdir)/docs/java +# java_DATA = $(JDOCDIR)/index.html + +javadir = $(datadir)/java +dist_java_JAVA = \ + $(JAVAEXAMPLES)/ex_access.java + +all-local: wiredtiger.jar + +$(JDOCDIR)/index.html: $(dist_java_JAVA) + mkdir -p $(JDOCDIR) + javadoc -public -d $(JDOCDIR) -link http://docs.oracle.com/javase/6/docs/api $(JAVAEXAMPLES)/[A-Z]*.java + +wiredtiger.jar: $(dist_java_JAVA) + (cd $(top_builddir) && \ + $(JAR) -cf wiredtiger.jar com/) diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_access.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_access.java new file mode 100644 index 00000000000..104f86d5545 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_access.java @@ -0,0 +1,94 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_access.java + * demonstrates how to create and access a simple table. + */ +package com.wiredtiger.examples; +import com.wiredtiger.db.*; + +public class ex_access { + public static void main(String[] args) { + /*! [access example connection] */ + Connection conn; + Session s; + Cursor c; + + try { + conn = wiredtiger.open("WT_HOME", "create"); + s = conn.open_session(null); + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + return; + } + /*! [access example connection] */ + try { + /*! [access example table create] */ + s.create("table:t", "key_format=S,value_format=u"); + /*! [access example table create] */ + /*! [access example cursor open] */ + c = s.open_cursor("table:t", null, null); + /*! [access example cursor open] */ + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + return; + } + System.out.println("Key format: " + c.getKeyFormat()); + System.out.println("Value format: " + c.getValueFormat()); + /*! [access example cursor insert] */ + try { + c.putKeyString("foo"); + c.putValueByteArray("bar".getBytes()); + c.insert(); + } catch (WiredTigerPackingException wtpe) { + System.err.println("WiredTigerPackingException: " + wtpe); + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + } + /*! [access example cursor insert] */ + /*! [access example cursor list] */ + try { + c.reset(); + while (c.next() == 0) { + System.out.println("Got: " + c.getKeyString()); + } + } catch (WiredTigerPackingException wtpe) { + System.err.println("WiredTigerPackingException: " + wtpe); + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + } + /*! [access example cursor list] */ + + /*! [access example close] */ + try { + conn.close(null); + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + } + /*! [access example close] */ + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_all.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_all.java new file mode 100644 index 00000000000..153f12d3e27 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_all.java @@ -0,0 +1,1036 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_all.java + * Containing a call to every method in the WiredTiger API. + * + * It doesn't do anything very useful, just demonstrates how to call each + * method. This file is used to populate the API reference with code + * fragments. + */ +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.nio.*; + +/* Note: indentation in non-standard so it will display nicely in doc. */ +public class ex_all { + +public static String progname = "ex_all"; + +public static int cursor_ops(Session session) + throws WiredTigerException +{ + Cursor cursor; + int ret; + + /*! [Open a cursor] */ + cursor = session.open_cursor("table:mytable", null, null); + /*! [Open a cursor] */ + + /*! [Open a cursor on the metadata] */ + cursor = session.open_cursor("metadata:", null, null); + /*! [Open a cursor on the metadata] */ + + { + Cursor duplicate; + String key = "some key"; + /*! [Duplicate a cursor] */ + cursor = session.open_cursor("table:mytable", null, null); + cursor.putKeyString(key); + ret = cursor.search(); + + /* Duplicate the cursor. */ + duplicate = session.open_cursor(null, cursor, null); + /*! [Duplicate a cursor] */ + } + + { + Cursor overwrite_cursor; + String key = "some key", value = "some value"; + /*! [Reconfigure a cursor] */ + cursor = session.open_cursor("table:mytable", null, null); + cursor.putKeyString(key); + + /* Reconfigure the cursor to overwrite the record. */ + overwrite_cursor = session.open_cursor(null, cursor, "overwrite"); + ret = cursor.close(); + + overwrite_cursor.putValueString(value); + ret = overwrite_cursor.insert(); + /*! [Reconfigure a cursor] */ + } + + { + /*! [boolean configuration string example] */ + cursor = session.open_cursor("table:mytable", null, "overwrite"); + cursor = session.open_cursor("table:mytable", null, "overwrite=true"); + cursor = session.open_cursor("table:mytable", null, "overwrite=1"); + /*! [boolean configuration string example] */ + } + + { + /*! [open a named checkpoint] */ + cursor = session.open_cursor("table:mytable", null, "checkpoint=midnight"); + /*! [open a named checkpoint] */ + } + + { + /*! [open the default checkpoint] */ + cursor = session.open_cursor("table:mytable", null, + "checkpoint=WiredTigerCheckpoint"); + /*! [open the default checkpoint] */ + } + + { + /*! [Get the cursor's string key] */ + String key; /* Get the cursor's string key. */ + key = cursor.getKeyString(); + /*! [Get the cursor's string key] */ + } + + { + /*! [Set the cursor's string key] */ + /* Set the cursor's string key. */ + String key = "another key"; + cursor.putKeyString(key); + /*! [Set the cursor's string key] */ + } + + { + /*! [Get the cursor's record number key] */ + long recno; /* Get the cursor's record number key. */ + recno = cursor.getKeyLong(); + /*! [Get the cursor's record number key] */ + } + + { + /*! [Set the cursor's record number key] */ + long recno = 37; /* Set the cursor's record number key. */ + cursor.putKeyLong(recno); + /*! [Set the cursor's record number key] */ + } + + { + /*! [Get the cursor's composite key] */ + /* Get the cursor's "SiH" format composite key. */ + String first; + int second; + short third; + + first = cursor.getKeyString(); + second = cursor.getKeyInt(); + third = cursor.getKeyShort(); + /*! [Get the cursor's composite key] */ + } + + { + /*! [Set the cursor's composite key] */ + /* Set the cursor's "SiH" format composite key. */ + cursor.putKeyString("first"); + cursor.putKeyInt(5); + cursor.putKeyShort((short)7); + /*! [Set the cursor's composite key] */ + } + + { + /*! [Get the cursor's string value] */ + String value; /* Get the cursor's string value. */ + value = cursor.getValueString(); + /*! [Get the cursor's string value] */ + } + + { + /*! [Set the cursor's string value] */ + /* Set the cursor's string value. */ + String value = "another value"; + cursor.putValueString(value); + /*! [Set the cursor's string value] */ + } + + { + /*! [Get the cursor's raw value] */ + byte[] value; /* Get the cursor's raw value. */ + value = cursor.getValueByteArray(); + /*! [Get the cursor's raw value] */ + } + + { + /*! [Set the cursor's raw value] */ + byte[] value; /* Set the cursor's raw value. */ + value = "another value".getBytes(); + cursor.putValueByteArray(value); + /*! [Set the cursor's raw value] */ + } + + /*! [Return the next record] */ + ret = cursor.next(); + /*! [Return the next record] */ + + /*! [Return the previous record] */ + ret = cursor.prev(); + /*! [Return the previous record] */ + + /*! [Reset the cursor] */ + ret = cursor.reset(); + /*! [Reset the cursor] */ + + { + Cursor other = null; + /*! [Cursor comparison] */ + int compare; + compare = cursor.compare(other); + if (compare == 0) { + /* Cursors reference the same key */ + } else if (compare < 0) { + /* Cursor key less than other key */ + } else if (compare > 0) { + /* Cursor key greater than other key */ + } + /*! [Cursor comparison] */ + } + + { + Cursor other = null; + /*! [Cursor equality] */ + int compare; + compare = cursor.equals(other); + if (compare == 0) { + /* redtiger.iCursors reference the same key */ + } else { + /* Cursors don't reference the same key */ + } + /*! [Cursor equality] */ + } + + { + /*! [Search for an exact match] */ + String key = "some key"; + cursor.putKeyString(key); + ret = cursor.search(); + /*! [Search for an exact match] */ + } + + cursor_search_near(cursor); + + { + /*! [Insert a new record or overwrite an existing record] */ + /* Insert a new record or overwrite an existing record. */ + String key = "some key", value = "some value"; + cursor = session.open_cursor("table:mytable", null, null); + cursor.putKeyString(key); + cursor.putValueString(value); + ret = cursor.insert(); + /*! [Insert a new record or overwrite an existing record] */ + } + + { + /*! [Insert a new record and fail if the record exists] */ + /* Insert a new record and fail if the record exists. */ + String key = "some key", value = "some value"; + cursor = session.open_cursor("table:mytable", null, "overwrite=false"); + cursor.putKeyString(key); + cursor.putValueString(value); + ret = cursor.insert(); + /*! [Insert a new record and fail if the record exists] */ + } + + { + /*! [Insert a new record and assign a record number] */ + /* Insert a new record and assign a record number. */ + long recno; + String value = "some value"; + cursor = session.open_cursor("table:mytable", null, "append"); + cursor.putValueString(value); + ret = cursor.insert(); + if (ret == 0) + recno = cursor.getKeyLong(); + /*! [Insert a new record and assign a record number] */ + } + + { + /*! [Update an existing record or insert a new record] */ + String key = "some key", value = "some value"; + cursor = session.open_cursor("table:mytable", null, null); + cursor.putKeyString(key); + cursor.putValueString(value); + ret = cursor.update(); + /*! [Update an existing record or insert a new record] */ + } + + { + /*! [Update an existing record and fail if DNE] */ + String key = "some key", value = "some value"; + cursor = session.open_cursor("table:mytable", null, "overwrite=false"); + cursor.putKeyString(key); + cursor.putValueString(value); + ret = cursor.update(); + /*! [Update an existing record and fail if DNE] */ + } + + { + /*! [Remove a record] */ + String key = "some key"; + cursor = session.open_cursor("table:mytable", null, null); + cursor.putKeyString(key); + ret = cursor.remove(); + /*! [Remove a record] */ + } + + { + /*! [Remove a record and fail if DNE] */ + String key = "some key"; + cursor = session.open_cursor("table:mytable", null, "overwrite=false"); + cursor.putKeyString(key); + ret = cursor.remove(); + /*! [Remove a record and fail if DNE] */ + } + + { + /*! [Display an error] */ + try { + String key = "non-existent key"; + cursor.putKeyString(key); + if ((ret = cursor.remove()) != 0) { + System.err.println( + "cursor.remove: " + wiredtiger.wiredtiger_strerror(ret)); + return (ret); + } + } catch (WiredTigerException wte) { /* Catch severe errors. */ + System.err.println("cursor.remove exception: " + wte); + } + /*! [Display an error] */ + } + + /*! [Close the cursor] */ + ret = cursor.close(); + /*! [Close the cursor] */ + + return (ret); +} + +static int +cursor_search_near(Cursor cursor) + throws WiredTigerException +{ + int ret; + String key = "some key"; + SearchStatus status; + + /*! [Search for an exact or adjacent match] */ + cursor.putKeyString(key); + status = cursor.search_near(); + if (status == SearchStatus.FOUND) { + /* an exact match */ + } else if (status == SearchStatus.SMALLER) { + /* returned smaller key */ + } else if (status == SearchStatus.LARGER) { + /* returned larger key */ + } else if (status == SearchStatus.NOTFOUND) { + /* no match found */ + } + /*! [Search for an exact or adjacent match] */ + + /*! [Forward scan greater than or equal] */ + cursor.putKeyString(key); + status = cursor.search_near(); + if (status == SearchStatus.FOUND || status == SearchStatus.LARGER) { + /* include first key returned in the scan */ + } + + while ((ret = cursor.next()) == 0) { + /* the rest of the scan */ + } + /*! [Forward scan greater than or equal] */ + + /*! [Backward scan less than] */ + cursor.putKeyString(key); + status = cursor.search_near(); + if (status == SearchStatus.SMALLER) { + /* include first key returned in the scan */ + } + + while ((ret = cursor.prev()) == 0) { + /* the rest of the scan */ + } + /*! [Backward scan less than] */ + + return (ret); +} + +static int +checkpoint_ops(Session session) + throws WiredTigerException +{ + int ret; + + /*! [Checkpoint examples] */ + /* Checkpoint the database. */ + ret = session.checkpoint(null); + + /* Checkpoint of the database, creating a named snapshot. */ + ret = session.checkpoint("name=June01"); + + /* + * Checkpoint a list of objects. + * JSON parsing requires quoting the list of target URIs. + */ + ret = session. + checkpoint("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("target=(\"table:mytable\"),name=midnight"); + + /* Checkpoint the database, discarding all previous snapshots. */ + ret = session.checkpoint("drop=(from=all)"); + + /* Checkpoint the database, discarding the "midnight" snapshot. */ + ret = session.checkpoint("drop=(midnight)"); + + /* + * Checkpoint the database, discarding all snapshots after and + * including "noon". + */ + ret = session.checkpoint("drop=(from=noon)"); + + /* + * Checkpoint the database, discarding all snapshots before and + * including "midnight". + */ + ret = session.checkpoint("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("target=(\"table:mytable\"),name=July01,drop=(May01,June01)"); + /*! [Checkpoint examples] */ + + /*! [JSON quoting example] */ + /* + * Checkpoint a list of objects. + * JSON parsing requires quoting the list of target URIs. + */ + ret = session. + checkpoint("target=(\"table:table1\",\"table:table2\")"); + /*! [JSON quoting example] */ + + return (ret); +} + +static boolean +cursor_statistics(Session session) + throws WiredTigerException +{ + Cursor cursor; + + /*! [Statistics cursor database] */ + cursor = session.open_cursor( + "statistics:", null, null); + /*! [Statistics cursor database] */ + + /*! [Statistics cursor table] */ + cursor = session.open_cursor( + "statistics:table:mytable", null, null); + /*! [Statistics cursor table] */ + + /*! [Statistics cursor table fast] */ + cursor = session.open_cursor("statistics:table:mytable", null, "statistics=(fast)"); + /*! [Statistics cursor table fast] */ + + /*! [Statistics clear configuration] */ + cursor = session.open_cursor("statistics:", null, "statistics=(fast,clear)"); + /*! [Statistics clear configuration] */ + + /*! [Statistics cursor clear configuration] */ + cursor = session.open_cursor("statistics:table:mytable", + null, "statistics=(all,clear)"); + /*! [Statistics cursor clear configuration] */ + + return (true); +} + +static int +session_ops(Session session) + throws WiredTigerException +{ + int ret; + + /*! [Reconfigure a session] */ + ret = session.reconfigure("isolation=snapshot"); + /*! [Reconfigure a session] */ + + /*! [Create a table] */ + ret = session.create("table:mytable", "key_format=S,value_format=S"); + /*! [Create a table] */ + ret = session.drop("table:mytable", null); + + /*! [Create a column-store table] */ + ret = session.create("table:mytable", "key_format=r,value_format=S"); + /*! [Create a column-store table] */ + ret = session.drop("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("table:mytable", + "key_format=r,value_format=SiH," + + "columns=(id,department,salary,year-started)"); + /*! [Create a table with columns] */ + ret = session.drop("table:mytable", null); + + /* + * This example code gets run, and the compression libraries might not + * be loaded, causing the create to fail. The documentation requires + * the code snippets, use if (false) to avoid running it. + */ + if (false) { // MIGHT_NOT_RUN + /*! [Create a bzip2 compressed table] */ + ret = session.create("table:mytable", + "block_compressor=bzip2,key_format=S,value_format=S"); + /*! [Create a bzip2 compressed table] */ + ret = session.drop("table:mytable", null); + + /*! [Create a lz4 compressed table] */ + ret = session.create("table:mytable", + "block_compressor=lz4,key_format=S,value_format=S"); + /*! [Create a lz4 compressed table] */ + ret = session.drop("table:mytable", null); + + /*! [Create a snappy compressed table] */ + ret = session.create("table:mytable", + "block_compressor=snappy,key_format=S,value_format=S"); + /*! [Create a snappy compressed table] */ + ret = session.drop("table:mytable", null); + + /*! [Create a zlib compressed table] */ + ret = session.create("table:mytable", + "block_compressor=zlib,key_format=S,value_format=S"); + /*! [Create a zlib compressed table] */ + ret = session.drop("table:mytable", null); + } // if (false) + + /*! [Configure checksums to uncompressed] */ + ret = session.create("table:mytable", + "key_format=S,value_format=S,checksum=uncompressed"); + /*! [Configure checksums to uncompressed] */ + ret = session.drop("table:mytable", null); + + /*! [Configure dictionary compression on] */ + ret = session.create("table:mytable", + "key_format=S,value_format=S,dictionary=1000"); + /*! [Configure dictionary compression on] */ + ret = session.drop("table:mytable", null); + + /*! [Configure key prefix compression on] */ + ret = session.create("table:mytable", + "key_format=S,value_format=S,prefix_compression=true"); + /*! [Configure key prefix compression on] */ + ret = session.drop("table:mytable", null); + + if (false) { // MIGHT_NOT_RUN + /* Requires sync_file_range */ + /*! [os_cache_dirty_max configuration] */ + ret = session.create( + "table:mytable", "os_cache_dirty_max=500MB"); + /*! [os_cache_dirty_max configuration] */ + ret = session.drop("table:mytable", null); + + /* Requires posix_fadvise */ + /*! [os_cache_max configuration] */ + ret = session.create("table:mytable", "os_cache_max=1GB"); + /*! [os_cache_max configuration] */ + ret = session.drop("table:mytable", null); + } // if (false) + + /*! [Configure block_allocation] */ + ret = session.create("table:mytable", + "key_format=S,value_format=S,block_allocation=first"); + /*! [Configure block_allocation] */ + ret = session.drop("table:mytable", null); + + /*! [Create a cache-resident object] */ + ret = session.create("table:mytable", "key_format=r,value_format=S,cache_resident=true"); + /*! [Create a cache-resident object] */ + ret = session.drop("table:mytable", null); + + { + /* Create a table for the session operations. */ + ret = session.create( + "table:mytable", "key_format=S,value_format=S"); + + /*! [Compact a table] */ + ret = session.compact("table:mytable", null); + /*! [Compact a table] */ + + /*! [Rename a table] */ + ret = session.rename("table:old", "table:new", null); + /*! [Rename a table] */ + + /*! [Salvage a table] */ + ret = session.salvage("table:mytable", null); + /*! [Salvage a table] */ + + /*! [Truncate a table] */ + ret = session.truncate("table:mytable", null, null, null); + /*! [Truncate a table] */ + + { + /* + * Insert a pair of keys so we can truncate a range. + */ + Cursor cursor; + cursor = session.open_cursor( + "table:mytable", null, null); + cursor.putKeyString("June01"); + cursor.putValueString("value"); + ret = cursor.update(); + cursor.putKeyString("June30"); + cursor.putValueString("value"); + ret = cursor.update(); + cursor.close(); + + { + /*! [Truncate a range] */ + Cursor start, stop; + + start = session.open_cursor( + "table:mytable", null, null); + start.putKeyString("June01"); + ret = start.search(); + + stop = session.open_cursor( + "table:mytable", null, null); + stop.putKeyString("June30"); + ret = stop.search(); + + ret = session.truncate(null, start, stop, null); + /*! [Truncate a range] */ + } + } + + /*! [Upgrade a table] */ + ret = session.upgrade("table:mytable", null); + /*! [Upgrade a table] */ + + /*! [Verify a table] */ + ret = session.verify("table:mytable", null); + /*! [Verify a table] */ + + /*! [Drop a table] */ + ret = session.drop("table:mytable", null); + /*! [Drop a table] */ + } + + /*! [Close a session] */ + ret = session.close(null); + /*! [Close a session] */ + + return (ret); +} + +static int +transaction_ops(Connection conn, Session session) + throws WiredTigerException +{ + Cursor cursor; + int ret; + + /*! [transaction commit/rollback] */ + cursor = session.open_cursor("table:mytable", null, null); + ret = session.begin_transaction(null); + /* + * Cursors may be opened before or after the transaction begins, and in + * either case, subsequent operations are included in the transaction. + * The begin_transaction call resets all open cursors. + */ + + cursor.putKeyString("key"); + cursor.putValueString("value"); + switch (ret = cursor.update()) { + case 0: /* Update success */ + ret = session.commit_transaction(null); + /* + * The commit_transaction call resets all open cursors. + * If commit_transaction fails, the transaction was rolled-back. + */ + break; + case wiredtiger.WT_ROLLBACK: /* Update conflict */ + default: /* Other error */ + ret = session.rollback_transaction(null); + /* The rollback_transaction call resets all open cursors. */ + break; + } + + /* Cursors remain open and may be used for multiple transactions. */ + /*! [transaction commit/rollback] */ + ret = cursor.close(); + + /*! [transaction isolation] */ + /* A single transaction configured for snapshot isolation. */ + cursor = session.open_cursor("table:mytable", null, null); + ret = session.begin_transaction("isolation=snapshot"); + cursor.putKeyString("some-key"); + cursor.putValueString("some-value"); + ret = cursor.update(); + ret = session.commit_transaction(null); + /*! [transaction isolation] */ + + /*! [session isolation configuration] */ + /* Open a session configured for read-uncommitted isolation. */ + session = conn.open_session( + "isolation=read_uncommitted"); + /*! [session isolation configuration] */ + + /*! [session isolation re-configuration] */ + /* Re-configure a session for snapshot isolation. */ + ret = session.reconfigure("isolation=snapshot"); + /*! [session isolation re-configuration] */ + + return (ret); +} + +/*! [Implement WT_COLLATOR] */ +/* Not available for java */ +/*! [Implement WT_COLLATOR] */ + +/*! [WT_EXTRACTOR] */ +/* Not available for java */ +/*! [WT_EXTRACTOR] */ + +static int +connection_ops(Connection conn) + throws WiredTigerException +{ + int ret; + + if (false) { // Might not run. + /*! [Load an extension] */ + ret = conn.load_extension("my_extension.dll", null); + + ret = conn.load_extension( + "datasource/libdatasource.so", + "config=[device=/dev/sd1,alignment=64]"); + /*! [Load an extension] */ + } // if (false) + + /*! [Reconfigure a connection] */ + ret = conn.reconfigure("eviction_target=75"); + /*! [Reconfigure a connection] */ + + /*! [Get the database home directory] */ + System.out.println("The database home is " + conn.get_home()); + /*! [Get the database home directory] */ + + /*! [Check if the database is newly created] */ + if (conn.is_new() != 0) { + /* First time initialization. */ + } + /*! [Check if the database is newly created] */ + + { + /*! [Open a session] */ + Session session; + session = conn.open_session(null); + /*! [Open a session] */ + + session_ops(session); + } + + /*! [Configure method configuration] */ + /* + * Applications opening a cursor for the data-source object "my_data" + * have an additional configuration option "entries", which is an + * integer type, defaults to 5, and must be an integer between 1 and 10. + */ + ret = conn.configure_method( + "session.open_cursor", + "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( + "session.open_cursor", "my_data:", "devices", "list", null); + /*! [Configure method configuration] */ + + /*! [Close a connection] */ + ret = conn.close(null); + /*! [Close a connection] */ + + return (ret); +} + +static int +pack_ops(Session session) +{ + { + /*! [Get the packed size] */ + /* Not available for java */ + /*! [Get the packed size] */ + } + + { + /*! [Pack fields into a buffer] */ + /* Not available for java */ + /*! [Pack fields into a buffer] */ + } + + { + /*! [Unpack fields from a buffer] */ + /* Not available for java */ + /*! [Unpack fields from a buffer] */ + } + + return (0); +} + +static boolean +backup(Session session) + throws WiredTigerException +{ + char buf[] = new char[1024]; + + /*! [backup]*/ + Cursor cursor; + String filename; + int ret = 0; + String databasedir = "/path/database"; + String backdir = "/path/database.backup"; + final String sep = File.separator; + + try { + /* Create the backup directory. */ + if (!(new File(backdir)).mkdir()) { + System.err.println(progname + ": cannot create backup dir: " + + backdir); + return false; + } + + /* Open the backup data source. */ + cursor = session.open_cursor("backup:", null, null); + + /* Copy the list of files. */ + while ((ret = cursor.next()) == 0 && + (filename = cursor.getKeyString()) != null) { + String src = databasedir + sep + filename; + String dest = backdir + sep + filename; + java.nio.file.Files.copy( + new java.io.File(src).toPath(), + new java.io.File(dest).toPath(), + java.nio.file.StandardCopyOption.REPLACE_EXISTING, + java.nio.file.StandardCopyOption.COPY_ATTRIBUTES); + } + if (ret == wiredtiger.WT_NOTFOUND) + ret = 0; + if (ret != 0) + System.err.println(progname + + ": cursor next(backup:) failed: " + + wiredtiger.wiredtiger_strerror(ret)); + + ret = cursor.close(); + } + catch (Exception ex) { + System.err.println(progname + + ": backup failed: " + ex.toString()); + } + /*! [backup]*/ + + /*! [backup of a checkpoint]*/ + ret = session.checkpoint("drop=(from=June01),name=June01"); + /*! [backup of a checkpoint]*/ + + return (ret == 0); +} + +public static int +allExample() + throws WiredTigerException +{ + Connection conn; + int ret = 0; + String home = "/home/example/WT_TEST"; + + /*! [Open a connection] */ + conn = wiredtiger.open(home, "create,cache_size=500M"); + /*! [Open a connection] */ + + connection_ops(conn); + /* + * The connection has been closed. + */ + + if (false) { // MIGHT_NOT_RUN + /* + * This example code gets run, and the compression libraries might not + * be installed, causing the open to fail. The documentation requires + * the code snippets, use if (false) to avoid running it. + */ + /*! [Configure bzip2 extension] */ + conn = wiredtiger.open(home, + "create," + + "extensions=[/usr/local/lib/libwiredtiger_bzip2.so]"); + /*! [Configure bzip2 extension] */ + conn.close(null); + + /*! [Configure lz4 extension] */ + conn = wiredtiger.open(home, + "create," + + "extensions=[/usr/local/lib/libwiredtiger_lz4.so]"); + /*! [Configure lz4 extension] */ + conn.close(null); + + /*! [Configure snappy extension] */ + conn = wiredtiger.open(home, + "create," + + "extensions=[/usr/local/lib/libwiredtiger_snappy.so]"); + /*! [Configure snappy extension] */ + conn.close(null); + + /*! [Configure zlib extension] */ + conn = wiredtiger.open(home, + "create," + + "extensions=[/usr/local/lib/libwiredtiger_zlib.so]"); + /*! [Configure zlib extension] */ + conn.close(null); + + /* + * This example code gets run, and direct I/O might not be available, + * causing the open to fail. The documentation requires code snippets, + * use if (false) to avoid running it. + */ + /* Might Not Run: direct I/O may not be available. */ + /*! [Configure direct_io for data files] */ + conn = wiredtiger.open(home, "create,direct_io=[data]"); + /*! [Configure direct_io for data files] */ + conn.close(null); + } // if (false) + + /*! [Configure file_extend] */ + conn = wiredtiger.open( + home, "create,file_extend=(data=16MB)"); + /*! [Configure file_extend] */ + conn.close(null); + + /*! [Eviction configuration] */ + /* + * Configure eviction to begin at 90% full, and run until the cache + * is only 75% dirty. + */ + conn = wiredtiger.open(home, + "create,eviction_trigger=90,eviction_dirty_target=75"); + /*! [Eviction configuration] */ + conn.close(null); + + /*! [Eviction worker configuration] */ + /* Configure up to four eviction threads */ + conn = wiredtiger.open(home, + "create,eviction_trigger=90,eviction=(threads_max=4)"); + /*! [Eviction worker configuration] */ + conn.close(null); + + /*! [Statistics configuration] */ + conn = wiredtiger.open(home, "create,statistics=(all)"); + /*! [Statistics configuration] */ + conn.close(null); + + /*! [Statistics logging] */ + conn = wiredtiger.open( + home, "create,statistics_log=(wait=30)"); + /*! [Statistics logging] */ + conn.close(null); + + /*! [Statistics logging with a table] */ + conn = wiredtiger.open(home, + "create," + + "statistics_log=(sources=(\"table:table1\",\"table:table2\"))"); + /*! [Statistics logging with a table] */ + conn.close(null); + + /*! [Statistics logging with all tables] */ + conn = wiredtiger.open(home, + "create,statistics_log=(sources=(\"table:\"))"); + /*! [Statistics logging with all tables] */ + conn.close(null); + + if (false) { // MIGHT_NOT_RUN + /* + * This example code gets run, and a non-existent log file path might + * cause the open to fail. The documentation requires code snippets, + * use if (false) to avoid running it. + */ + /*! [Statistics logging with path] */ + conn = wiredtiger.open(home, + "create," + + "statistics_log=(wait=120,path=/log/log.%m.%d.%y)"); + /*! [Statistics logging with path] */ + conn.close(null); + + /* + * Don't run this code, because memory checkers get very upset when we + * leak memory. + */ + conn = wiredtiger.open(home, "create"); + /*! [Connection close leaking memory] */ + ret = conn.close("leak_memory=true"); + /*! [Connection close leaking memory] */ + } // if (false) + + /*! [Get the WiredTiger library version #1] */ + /* Not available for java */ + /*! [Get the WiredTiger library version #1] */ + + { + /*! [Get the WiredTiger library version #2] */ + /* Not available for java */ + /*! [Get the WiredTiger library version #2] */ + } + + return (0); +} + +public static int +main(String[] argv) +{ + try { + return (allExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + return (-1); + } +} +} /* Non-standard indentation */ diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_async.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_async.java new file mode 100644 index 00000000000..2e890095b2d --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_async.java @@ -0,0 +1,221 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_async.java + * demonstrates how to use the asynchronous API. + */ +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +/*! [async example callback implementation] */ +class AsyncKeys implements AsyncCallback { + + public int numKeys = 0; + + public AsyncKeys() {} + + public void notifyError(String desc) { + System.err.println("ERROR: notify: " + desc); + } + + public int notify(AsyncOp op, int opReturn, int flags) { + /* + * Note: we are careful not to throw any errors here. Any + * exceptions would be swallowed by a native worker thread. + */ + int ret = 0; + try { + /*! [async get type] */ + /* Retrieve the operation's type. */ + AsyncOpType optype = op.getType(); + /*! [async get type] */ + /*! [async get identifier] */ + /* Retrieve the operation's 64-bit identifier. */ + long id = op.getId(); + /*! [async get identifier] */ + + /* If doing a search, retrieve the key/value pair. */ + if (optype == AsyncOpType.WT_AOP_SEARCH) { + /*! [async get the operation's string key] */ + String key = op.getKeyString(); + /*! [async get the operation's string key] */ + /*! [async get the operation's string value] */ + String value = op.getValueString(); + /*! [async get the operation's string value] */ + synchronized (this) { + numKeys += 1; + } + System.out.println("Id " + id + " got record: " + key + + " : " + value); + } + } + catch (Exception e) { + System.err.println("ERROR: exception in notify: " + e.toString() + + ", opreturn=" + opReturn); + ret = 1; + } + return (ret); + } +} +/*! [async example callback implementation] */ + +public class ex_async { + + public static String home; + + public static final int MAX_KEYS = 15; + + public static AsyncOp tryAsyncNewOp(Connection conn, String uri, + String config, AsyncCallback cb) throws WiredTigerException + { + WiredTigerException savedwte = null; + + for (int tries = 0; tries < 10; tries++) + try { + return conn.async_new_op(uri, config, cb); + } + catch (WiredTigerException wte) { + /* + * If we used up all the handles, pause and retry to + * give the workers a chance to catch up. + */ + System.err.println( + "asynchronous operation handle not available: " + wte); + savedwte = wte; + try { + Thread.sleep(1); + } catch (InterruptedException ie) { + /* not a big problem, continue to retry */ + } + } + + throw savedwte; + } + + public static int + asyncExample() + throws WiredTigerException + { + AsyncOp op; + Connection conn; + Session session; + int i, ret; + String k[] = new String[MAX_KEYS]; + String v[] = new String[MAX_KEYS]; + + /*! [async example callback implementation part 2] */ + AsyncKeys asynciface = new AsyncKeys(); + /*! [async example callback implementation part 2] */ + + /*! [async example connection] */ + conn = wiredtiger.open(home, "create,cache_size=100MB," + + "async=(enabled=true,ops_max=20,threads=2)"); + /*! [async example connection] */ + + /*! [async example table create] */ + session = conn.open_session(null); + ret = session.create("table:async", "key_format=S,value_format=S"); + /*! [async example table create] */ + + /* Insert a set of keys asynchronously. */ + for (i = 0; i < MAX_KEYS; i++) { + /*! [async handle allocation] */ + op = tryAsyncNewOp(conn, "table:async", null, asynciface); + /*! [async handle allocation] */ + + /*! [async insert] */ + /* + * Set the operation's string key and value, and then do + * an asynchronous insert. + */ + /*! [async set the operation's string key] */ + k[i] = "key" + i; + op.putKeyString(k[i]); + /*! [async set the operation's string key] */ + + /*! [async set the operation's string value] */ + v[i] = "value" + i; + op.putValueString(v[i]); + /*! [async set the operation's string value] */ + + ret = op.insert(); + /*! [async insert] */ + } + + /*! [async flush] */ + /* Wait for all outstanding operations to complete. */ + ret = conn.async_flush(); + /*! [async flush] */ + + /*! [async compaction] */ + /* + * Compact a table asynchronously, limiting the run-time to 5 minutes. + */ + op = tryAsyncNewOp(conn, "table:async", "timeout=300", asynciface); + ret = op.compact(); + /*! [async compaction] */ + + /* Search for the keys we just inserted, asynchronously. */ + for (i = 0; i < MAX_KEYS; i++) { + op = tryAsyncNewOp(conn, "table:async", null, asynciface); + /*! [async search] */ + /* + * Set the operation's string key and value, and then do + * an asynchronous search. + */ + k[i] = "key" + i; + op.putKeyString(k[i]); + ret = op.search(); + /*! [async search] */ + } + + /* + * Connection close automatically does an async_flush so it will wait + * for all queued search operations to complete. + */ + ret = conn.close(null); + + System.out.println("Searched for " + asynciface.numKeys + " keys"); + + return (ret); + } + + public static void + main(String[] argv) + { + try { + System.exit(asyncExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_call_center.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_call_center.java new file mode 100644 index 00000000000..a3f0f56ded8 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_call_center.java @@ -0,0 +1,302 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_call_center.java + * This is an example application that demonstrates how to map a + * moderately complex SQL application into WiredTiger. + */ + +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +/*! [call-center decl] */ +/* + * In SQL, the tables are described as follows: + * + * CREATE TABLE Customers(id INTEGER PRIMARY KEY, + * name VARCHAR(30), address VARCHAR(50), phone VARCHAR(15)) + * CREATE INDEX CustomersPhone ON Customers(phone) + * + * CREATE TABLE Calls(id INTEGER PRIMARY KEY, call_date DATE, + * cust_id INTEGER, emp_id INTEGER, call_type VARCHAR(12), + * notes VARCHAR(25)) + * CREATE INDEX CallsCustDate ON Calls(cust_id, call_date) + * + * In this example, both tables will use record numbers for their IDs, which + * will be the key. The C structs for the records are as follows. + */ + +/* Customer records. */ +class Customer { + public long id; + public String name; + public String address; + public String phone; + public Customer(long id, String name, String address, String phone) { + this.id = id; + this.name = name; + this.address = address; + this.phone = phone; + } + public Customer() {} +} + +/* Call records. */ +class Call { + public long id; + public long call_date; + public long cust_id; + public long emp_id; + public String call_type; + public String notes; + public Call(long id, long call_date, long cust_id, long emp_id, + String call_type, String notes) { + this.id = id; + this.call_date = call_date; + this.cust_id = cust_id; + this.emp_id = emp_id; + this.call_type = call_type; + this.notes = notes; + } + public Call() {} +} +/*! [call-center decl] */ + +public class ex_call_center { + + public static String home; + + public static int + callCenterExample() + throws WiredTigerException + { + Connection conn; + Cursor cursor; + Session session; + int count, ret; + SearchStatus nearstatus; + List<Customer> custSample = new ArrayList<Customer>(); + List<Call> callSample = new ArrayList<Call>(); + + custSample.add(new Customer(0, "Professor Oak", + "LeafGreen Avenue", "123-456-7890")); + custSample.add(new Customer(0, "Lorelei", + "Sevii Islands", "098-765-4321")); + callSample.add(new Call(0, 32, 1, 2, "billing", "unavailable")); + callSample.add(new Call(0, 33, 1, 2, "billing", "available")); + callSample.add(new Call(0, 34, 1, 2, "reminder", "unavailable")); + callSample.add(new Call(0, 35, 1, 2, "reminder", "available")); + + /* + * 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 (System.getenv("WIREDTIGER_HOME") == null) { + home = "WT_HOME"; + try { + Process proc = Runtime.getRuntime().exec("/bin/rm -rf WT_HOME"); + BufferedReader br = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + while(br.ready()) + System.out.println(br.readLine()); + br.close(); + proc.waitFor(); + new File("WT_HOME").mkdir(); + } catch (Exception ex) { + System.err.println("Exception: " + ex); + return (1); + } + } else + home = null; + + try { + conn = wiredtiger.open(home, "create"); + session = conn.open_session(null); + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + return(1); + } + /* Note: further error checking omitted for clarity. */ + + /*! [call-center work] */ + /* + * 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("table:customers", + "key_format=r," + + "value_format=SSS," + + "columns=(id,name,address,phone)," + + "colgroups=(main,address)"); + + /* Create the main column group with value columns except address. */ + ret = session.create( + "colgroup:customers:main", "columns=(name,phone)"); + + /* Create the address column group with just the address. */ + ret = session.create( + "colgroup:customers:address", "columns=(address)"); + + /* Create an index on the customer table by phone number. */ + ret = session.create( + "index:customers:phone", "columns=(phone)"); + + /* Populate the customers table with some data. */ + cursor = session.open_cursor("table:customers", null, "append"); + for (Customer cust : custSample) { + cursor.putValueString(cust.name); + cursor.putValueString(cust.address); + cursor.putValueString(cust.phone); + ret = cursor.insert(); + } + ret = cursor.close(); + + /* + * 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("table:calls", + "key_format=r," + + "value_format=qrrSS," + + "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("index:calls:cust_date", + "columns=(cust_id,call_date)"); + + /* Populate the calls table with some data. */ + cursor = session.open_cursor("table:calls", null, "append"); + for (Call call : callSample) { + cursor.putValueLong(call.call_date); + cursor.putValueRecord(call.cust_id); + cursor.putValueRecord(call.emp_id); + cursor.putValueString(call.call_type); + cursor.putValueString(call.notes); + ret = cursor.insert(); + } + ret = cursor.close(); + + /* + * First query: a call arrives. In SQL: + * + * SELECT id, name FROM Customers WHERE phone=? + * + * Use the cust_phone index, lookup by phone number to fill the + * customer record. The cursor will have a key format of "S" for a + * string because the cust_phone index has a single column ("phone"), + * which is of type "S". + * + * Specify the columns we want: the customer ID and the name. This + * means the cursor's value format will be "rS". + */ + cursor = session.open_cursor( + "index:customers:phone(id,name)", null, null); + cursor.putKeyString("123-456-7890"); + ret = cursor.search(); + if (ret == 0) { + Customer cust = new Customer(); + cust.id = cursor.getValueRecord(); + cust.name = cursor.getValueString(); + System.out.println("Read customer record for " + cust.name + + " (ID " + cust.id + ")"); + } + ret = cursor.close(); + + /* + * Next query: get the recent order history. In SQL: + * + * SELECT * FROM Calls WHERE cust_id=? ORDER BY call_date DESC LIMIT 3 + * + * Use the call_cust_date index to find the matching calls. Since it is + * is in increasing order by date for a given customer, we want to start + * with the last record for the customer and work backwards. + * + * Specify a subset of columns to be returned. (Note that if these were + * all covered by the index, the primary would not have to be accessed.) + * Stop after getting 3 records. + */ + cursor = session.open_cursor( + "index:calls:cust_date(cust_id,call_type,notes)", + null, null); + + /* + * The keys in the index are (cust_id,call_date) -- we want the largest + * call date for a given cust_id. Search for (cust_id+1,0), then work + * backwards. + */ + long custid = 1; + cursor.putKeyRecord(custid + 1); + cursor.putKeyLong(0); + nearstatus = cursor.search_near(); + + /* + * If the table is empty, search_near will return WT_NOTFOUND, else the + * cursor will be positioned on a matching key if one exists, or an + * 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 && (nearstatus == SearchStatus.LARGER || + nearstatus == SearchStatus.FOUND)) + ret = cursor.prev(); + for (count = 0; ret == 0 && count < 3; ++count) { + Call call = new Call(); + call.cust_id = cursor.getValueRecord(); + call.call_type = cursor.getValueString(); + call.notes = cursor.getValueString(); + if (call.cust_id != custid) + break; + System.out.println("Call record: customer " + call.cust_id + + " (" + call.call_type + + ": " + call.notes + ")"); + ret = cursor.prev(); + } + /*! [call-center work] */ + + ret = conn.close(null); + + return (ret); + } + + public static void + main(String[] argv) + { + try { + System.exit(callCenterExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_cursor.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_cursor.java new file mode 100644 index 00000000000..a0a6e48aa46 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_cursor.java @@ -0,0 +1,242 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_cursor.java + * This is an example demonstrating some cursor types and operations. + */ + +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +public class ex_cursor { + + public static String home; + + /*! [cursor next] */ + public static int + cursor_forward_scan(Cursor cursor) + throws WiredTigerException + { + String key, value; + int ret; + + while ((ret = cursor.next()) == 0) { + key = cursor.getKeyString(); + value = cursor.getValueString(); + } + return (ret); + } + /*! [cursor next] */ + + /*! [cursor prev] */ + public static int + cursor_reverse_scan(Cursor cursor) + throws WiredTigerException + { + String key, value; + int ret; + + while ((ret = cursor.prev()) == 0) { + key = cursor.getKeyString(); + value = cursor.getValueString(); + } + return (ret); + } + /*! [cursor prev] */ + + /*! [cursor reset] */ + public static int + cursor_reset(Cursor cursor) + throws WiredTigerException + { + return (cursor.reset()); + } + /*! [cursor reset] */ + + /*! [cursor search] */ + public static int + cursor_search(Cursor cursor) + throws WiredTigerException + { + String value; + int ret; + + cursor.putKeyString("foo"); + + if ((ret = cursor.search()) != 0) + value = cursor.getValueString(); + + return (ret); + } + /*! [cursor search] */ + + /*! [cursor search near] */ + public static int + cursor_search_near(Cursor cursor) + throws WiredTigerException + { + String key, value; + SearchStatus exact; + + key = "foo"; + cursor.putKeyString(key); + + exact = cursor.search_near(); + if (exact == SearchStatus.SMALLER) + /* Returned key smaller than search key */ + key = cursor.getKeyString(); + else if (exact == SearchStatus.LARGER) + /* Returned key larger than search key */ + key = cursor.getKeyString(); + /* Else exact match found, and key already set */ + + value = cursor.getValueString(); + + return (0); + } + /*! [cursor search near] */ + + /*! [cursor insert] */ + public static int + cursor_insert(Cursor cursor) + throws WiredTigerException + { + cursor.putKeyString("foo"); + cursor.putValueString("bar"); + + return (cursor.insert()); + } + /*! [cursor insert] */ + + /*! [cursor update] */ + public static int + cursor_update(Cursor cursor) + throws WiredTigerException + { + cursor.putKeyString("foo"); + cursor.putValueString("newbar"); + + return (cursor.update()); + } + /*! [cursor update] */ + + /*! [cursor remove] */ + public static int + cursor_remove(Cursor cursor) + throws WiredTigerException + { + cursor.putKeyString("foo"); + return (cursor.remove()); + } + /*! [cursor remove] */ + + public static int + cursorExample() + throws WiredTigerException + { + Connection conn; + Cursor cursor; + 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 (System.getenv("WIREDTIGER_HOME") == null) { + home = "WT_HOME"; + try { + Process proc = Runtime.getRuntime().exec("/bin/rm -rf WT_HOME"); + BufferedReader br = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + while(br.ready()) + System.out.println(br.readLine()); + br.close(); + proc.waitFor(); + new File("WT_HOME").mkdir(); + } catch (Exception ex) { + System.err.println("Exception: " + ex); + return (1); + } + } else + home = null; + + conn = wiredtiger.open(home, "create,statistics=(fast)"); + session = conn.open_session(null); + + ret = session.create("table:world", + "key_format=r,value_format=5sii," + + "columns=(id,country,population,area)"); + + /*! [open cursor #1] */ + cursor = session.open_cursor("table:world", null, null); + /*! [open cursor #1] */ + + /*! [open cursor #2] */ + cursor = session.open_cursor("table:world(country,population)", null, null); + /*! [open cursor #2] */ + + /*! [open cursor #3] */ + cursor = session.open_cursor("statistics:", null, null); + /*! [open cursor #3] */ + + /* Create a simple string table to illustrate basic operations. */ + ret = session.create("table:map", "key_format=S,value_format=S"); + cursor = session.open_cursor("table:map", null, null); + 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(); + + /* Note: closing the connection implicitly closes open session(s). */ + if ((ret = conn.close(null)) != 0) + System.err.println("Error connecting to " + home + ": " + + wiredtiger.wiredtiger_strerror(ret)); + + return (ret); + } + + public static void + main(String[] argv) + { + try { + System.exit(cursorExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_log.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_log.java new file mode 100644 index 00000000000..03eab6b38b1 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_log.java @@ -0,0 +1,382 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_log.java + * demonstrates how to logging and log cursors. + */ +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +class Lsn { + int file; + long offset; +} + +public class ex_log { + + public static String home1 = "WT_HOME_LOG_1"; + public static String home2 = "WT_HOME_LOG_2"; + public static String uri = "table:logtest"; + + public static final String CONN_CONFIG = + "create,cache_size=100MB,log=(archive=false,enabled=true)"; + public static final int MAX_KEYS = 10; + + static Session + setup_copy() + throws WiredTigerException + { + int ret = 0; + Connection conn; + + conn = wiredtiger.open(home2, CONN_CONFIG); + Session session = conn.open_session(null); + session.create(uri, "key_format=U,value_format=U"); + return (session); + } + + static int + compare_tables(Session session, Session sess_copy) + throws WiredTigerException + { + int ret; + + Cursor cursor = session.open_cursor(uri, null, null); + Cursor curs_copy = sess_copy.open_cursor(uri, null, null); + + while ((ret = cursor.next()) == 0) { + ret = curs_copy.next(); + byte[] key = cursor.getKeyByteArray(); + byte[] value = cursor.getValueByteArray(); + byte[] key_copy = curs_copy.getKeyByteArray(); + byte[] value_copy = curs_copy.getValueByteArray(); + if (!Arrays.equals(key, key_copy) || + !Arrays.equals(value, value_copy)) { + System.err.println( + "Mismatched: key " + new String(key) + + ", key_copy " + new String(key_copy) + + ", value " + new String(value) + + ", value_copy " + new String(value_copy)); + return (1); + } + } + if (ret != wiredtiger.WT_NOTFOUND) + System.err.println("WT_CURSOR.next: " + + wiredtiger.wiredtiger_strerror(ret)); + ret = cursor.close(); + + ret = curs_copy.next(); + if (ret != wiredtiger.WT_NOTFOUND) + System.err.println("WT_CURSOR.next: " + + wiredtiger.wiredtiger_strerror(ret)); + ret = curs_copy.close(); + + return (ret); + } + + /*! [log cursor walk] */ + static void + print_record(Lsn lsn, int opcount, + int rectype, int optype, long txnid, int fileid, + byte[] key, byte[] value) + { + System.out.print( + "LSN [" + lsn.file + "][" + lsn.offset + "]." + opcount + + ": record type " + rectype + " optype " + optype + + " txnid " + txnid + " fileid " + fileid); + System.out.println(" key size " + key.length + + " value size " + value.length); + if (rectype == wiredtiger.WT_LOGREC_MESSAGE) + System.out.println("Application Record: " + new String(value)); + } + + /* + * simple_walk_log -- + * A simple walk of the log. + */ + static int + simple_walk_log(Session session) + throws WiredTigerException + { + Cursor cursor; + Lsn lsn = new Lsn(); + byte[] logrec_key, logrec_value; + long txnid; + int fileid, opcount, optype, rectype; + int ret; + + /*! [log cursor open] */ + cursor = session.open_cursor("log:", null, null); + /*! [log cursor open] */ + + while ((ret = cursor.next()) == 0) { + /*! [log cursor get_key] */ + lsn.file = cursor.getKeyInt(); + lsn.offset = cursor.getKeyLong(); + opcount = cursor.getKeyInt(); + /*! [log cursor get_key] */ + /*! [log cursor get_value] */ + txnid = cursor.getValueLong(); + rectype = cursor.getValueInt(); + optype = cursor.getValueInt(); + fileid = cursor.getValueInt(); + logrec_key = cursor.getValueByteArray(); + logrec_value = cursor.getValueByteArray(); + /*! [log cursor get_value] */ + + print_record(lsn, opcount, + rectype, optype, txnid, fileid, logrec_key, logrec_value); + } + if (ret == wiredtiger.WT_NOTFOUND) + ret = 0; + ret = cursor.close(); + return (ret); + } + /*! [log cursor walk] */ + + static int + walk_log(Session session) + throws WiredTigerException + { + Connection wt_conn2; + Cursor cursor, cursor2; + Lsn lsn, lsnsave; + byte[] logrec_key, logrec_value; + Session session2; + long txnid; + int fileid, opcount, optype, rectype; + int i, ret; + boolean in_txn, first; + + session2 = setup_copy(); + wt_conn2 = session2.getConnection(); + cursor = session.open_cursor("log:", null, null); + cursor2 = session2.open_cursor(uri, null, "raw=true"); + i = 0; + in_txn = false; + txnid = 0; + lsn = new Lsn(); + lsnsave = new Lsn(); + while ((ret = cursor.next()) == 0) { + lsn.file = cursor.getKeyInt(); + lsn.offset = cursor.getKeyLong(); + opcount = cursor.getKeyInt(); + + /* + * Save one of the LSNs we get back to search for it + * later. Pick a later one because we want to walk from + * that LSN to the end (where the multi-step transaction + * was performed). Just choose the record that is MAX_KEYS. + */ + if (++i == MAX_KEYS) + lsnsave = lsn; + txnid = cursor.getValueLong(); + rectype = cursor.getValueInt(); + optype = cursor.getValueInt(); + fileid = cursor.getValueInt(); + logrec_key = cursor.getValueByteArray(); + logrec_value = cursor.getValueByteArray(); + + print_record(lsn, opcount, + rectype, optype, txnid, fileid, logrec_key, logrec_value); + + /* + * If we are in a transaction and this is a new one, end + * the previous one. + */ + if (in_txn && opcount == 0) { + ret = session2.commit_transaction(null); + in_txn = false; + } + + /* + * If the operation is a put, replay it here on the backup + * connection. Note, we cheat by looking only for fileid 1 + * in this example. The metadata is fileid 0. + */ + if (fileid == 1 && rectype == wiredtiger.WT_LOGREC_COMMIT && + optype == wiredtiger.WT_LOGOP_ROW_PUT) { + if (!in_txn) { + ret = session2.begin_transaction(null); + in_txn = true; + } + cursor2.putKeyByteArray(logrec_key); + cursor2.putValueByteArray(logrec_value); + ret = cursor2.insert(); + } + } + if (in_txn) + ret = session2.commit_transaction(null); + + ret = cursor2.close(); + /* + * Compare the tables after replay. They should be identical. + */ + if (compare_tables(session, session2) != 0) + System.out.println("compare failed"); + ret = session2.close(null); + ret = wt_conn2.close(null); + + ret = cursor.reset(); + /*! [log cursor set_key] */ + cursor.putKeyInt(lsnsave.file); + cursor.putKeyLong(lsnsave.offset); + /*! [log cursor set_key] */ + /*! [log cursor search] */ + ret = cursor.search(); + /*! [log cursor search] */ + System.out.println("Reset to saved..."); + /* + * Walk all records starting with this key. + */ + first = true; + while (ret == 0) { /*TODO: not quite right*/ + lsn.file = cursor.getKeyInt(); + lsn.offset = cursor.getKeyLong(); + opcount = cursor.getKeyInt(); + if (first) { + first = false; + if (lsnsave.file != lsn.file || + lsnsave.offset != lsn.offset) { + System.err.println("search returned the wrong LSN"); + System.exit(1); + } + } + txnid = cursor.getValueLong(); + rectype = cursor.getValueInt(); + optype = cursor.getValueInt(); + fileid = cursor.getValueInt(); + logrec_key = cursor.getValueByteArray(); + logrec_value = cursor.getValueByteArray(); + + print_record(lsn, opcount, rectype, optype, txnid, + fileid, logrec_key, logrec_value); + + ret = cursor.next(); + if (ret != 0) + break; + } + ret = cursor.close(); + return (ret); + } + + public static int + logExample() + throws WiredTigerException + { + Connection wt_conn; + Cursor cursor; + Session session; + int i, record_count, ret; + + try { + String command = "/bin/rm -rf " + home1 + " " + home2; + Process proc = Runtime.getRuntime().exec(command); + BufferedReader br = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + while(br.ready()) + System.out.println(br.readLine()); + br.close(); + proc.waitFor(); + new File(home1).mkdir(); + new File(home2).mkdir(); + } catch (Exception ex) { + System.err.println("Exception: " + ex); + return (1); + } + if ((wt_conn = wiredtiger.open(home1, CONN_CONFIG)) == null) { + System.err.println("Error connecting to " + home1); + return (1); + } + + session = wt_conn.open_session(null); + ret = session.create(uri, "key_format=S,value_format=S"); + + cursor = session.open_cursor(uri, null, null); + /* + * Perform some operations with individual auto-commit transactions. + */ + for (record_count = 0, i = 0; i < MAX_KEYS; i++, record_count++) { + String k = "key" + i; + String v = "value" + i; + cursor.putKeyString(k); + cursor.putValueString(v); + ret = cursor.insert(); + } + ret = session.begin_transaction(null); + /* + * Perform some operations within a single transaction. + */ + for (i = MAX_KEYS; i < MAX_KEYS+5; i++, record_count++) { + String k = "key" + i; + String v = "value" + i; + cursor.putKeyString(k); + cursor.putValueString(v); + ret = cursor.insert(); + } + ret = session.commit_transaction(null); + ret = cursor.close(); + + /*! [log cursor printf] */ + ret = session.log_printf("Wrote " + record_count + " records"); + /*! [log cursor printf] */ + + session.close(null); + /* + * 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(null); + if ((wt_conn = wiredtiger.open(home1, CONN_CONFIG)) == null) { + System.err.println("Error connecting to " + home1); + return (ret); + } + + session = wt_conn.open_session(null); + ret = simple_walk_log(session); + ret = walk_log(session); + ret = session.close(null); + ret = wt_conn.close(null); + return (ret); + } + + public static void + main(String[] args) + { + try { + System.exit(logExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_schema.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_schema.java new file mode 100644 index 00000000000..be1077ee2df --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_schema.java @@ -0,0 +1,392 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_schema.java + * This is an example application demonstrating how to create and access + * tables using a schema. + */ +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +public class ex_schema { + + public static String home; + + /*! [schema declaration] */ + /* The class for the data we are storing in a WiredTiger table. */ + static class PopRecord { + public String country; // Stored in database as fixed size char[5]; + public short year; + public long population; + public PopRecord(String country, short year, long population) { + this.country = country; + this.year = year; + this.population = population; + } + } + + static List<PopRecord> popData; + + static { + popData = new ArrayList<PopRecord>(); + + popData.add(new PopRecord("AU", (short)1900, 4000000 )); + popData.add(new PopRecord("AU", (short)1950, 8267337 )); + popData.add(new PopRecord("AU", (short)2000, 19053186 )); + popData.add(new PopRecord("CAN", (short)1900, 5500000 )); + popData.add(new PopRecord("CAN", (short)1950, 14011422 )); + popData.add(new PopRecord("CAN", (short)2000, 31099561 )); + popData.add(new PopRecord("UK", (short)1900, 369000000 )); + popData.add(new PopRecord("UK", (short)1950, 50127000 )); + popData.add(new PopRecord("UK", (short)2000, 59522468 )); + popData.add(new PopRecord("USA", (short)1900, 76212168 )); + popData.add(new PopRecord("USA", (short)1950, 150697361 )); + popData.add(new PopRecord("USA", (short)2000, 301279593 )); + }; + /*! [schema declaration] */ + + public static int + schemaExample() + throws WiredTigerException + { + Connection conn; + Cursor cursor, cursor2, join_cursor; + Session session; + String country; + long recno, population; + short 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 (System.getenv("WIREDTIGER_HOME") == null) { + home = "WT_HOME"; + try { + Process proc = Runtime.getRuntime().exec("/bin/rm -rf WT_HOME"); + BufferedReader br = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + while(br.ready()) + System.out.println(br.readLine()); + br.close(); + proc.waitFor(); + new File("WT_HOME").mkdir(); + } catch (Exception ex) { + System.err.println("Exception: " + ex); + return (1); + } + } else + home = null; + + try { + conn = wiredtiger.open(home, "create"); + session = conn.open_session(null); + } catch (WiredTigerException wte) { + System.err.println("WiredTigerException: " + wte); + return(1); + } + + /*! [Create a table with column groups] */ + /* + * Create the population table. + * Keys are record numbers, the format for values is (5-byte string, + * long, long). + * See ::wiredtiger_struct_pack for details of the format strings. + */ + ret = session.create("table:poptable", + "key_format=r,value_format=5sHQ," + + "columns=(id,country,year,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("colgroup:poptable:main", + "columns=(country,year,population)"); + ret = session.create("colgroup:poptable:population", + "columns=(population)"); + /*! [Create a table with column groups] */ + + /*! [Create an index] */ + /* Create an index with a simple key. */ + ret = session.create("index:poptable:country", + "columns=(country)"); + /*! [Create an index] */ + + /*! [Create an immutable index] */ + /* Create an index with a simple key. */ + ret = session.create("index:poptable:immutable_year", + "columns=(year),immutable"); + /*! [Create an immutable index] */ + + /*! [Create an index with a composite key] */ + /* Create an index with a composite key (country,year). */ + ret = session.create("index:poptable:country_plus_year", + "columns=(country,year)"); + /*! [Create an index with a composite key] */ + + /*! [Insert and list records] */ + /* Insert the records into the table. */ + cursor = session.open_cursor("table:poptable", null, "append"); + for (PopRecord p : popData) { + cursor.putValueString(p.country); + cursor.putValueShort(p.year); + cursor.putValueLong(p.population); + ret = cursor.insert(); + } + ret = cursor.close(); + + /* Update records in the table. */ + cursor = session.open_cursor("table:poptable", null, null); + while ((ret = cursor.next()) == 0) { + recno = cursor.getKeyRecord(); + country = cursor.getValueString(); + year = cursor.getValueShort(); + population = cursor.getValueLong(); + cursor.putValueString(country); + cursor.putValueShort(year); + cursor.putValueLong(population + 1); + } + ret = cursor.close(); + + /* List the records in the table. */ + cursor = session.open_cursor("table:poptable", null, null); + while ((ret = cursor.next()) == 0) { + recno = cursor.getKeyRecord(); + country = cursor.getValueString(); + year = cursor.getValueShort(); + population = cursor.getValueLong(); + System.out.print("ID " + recno); + System.out.println(": country " + country + ", year " + year + + ", population " + population); + } + ret = cursor.close(); + /*! [Insert and list records] */ + + /*! [List the records in the table using raw mode.] */ + cursor = session.open_cursor("table:poptable", null, "raw"); + while ((ret = cursor.next()) == 0) { + byte[] key, value; + + key = cursor.getKeyByteArray(); + System.out.println(Arrays.toString(key)); + value = cursor.getValueByteArray(); + System.out.println("raw key: " + Arrays.toString(key) + + ", raw value: " + Arrays.toString(value)); + } + /*! [List the records in the table using raw mode.] */ + + /*! [Read population from the primary column group] */ + /* + * Open a cursor on the main column group, and return the information + * for a particular country. + */ + cursor = session.open_cursor("colgroup:poptable:main", null, null); + cursor.putKeyRecord(2); + if ((ret = cursor.search()) == 0) { + country = cursor.getValueString(); + year = cursor.getValueShort(); + population = cursor.getValueLong(); + System.out.println("ID 2: country " + country + + ", year " + year + ", population " + population); + } + /*! [Read population from the primary column group] */ + ret = cursor.close(); + + /*! [Read population from the standalone column group] */ + /* + * Open a cursor on the population column group, and return the + * population of a particular country. + */ + cursor = session.open_cursor("colgroup:poptable:population", null, null); + cursor.putKeyRecord(2); + if ((ret = cursor.search()) == 0) { + population = cursor.getValueLong(); + System.out.println("ID 2: population " + population); + } + /*! [Read population from the standalone column group] */ + ret = cursor.close(); + + /*! [Search in a simple index] */ + /* Search in a simple index. */ + cursor = session.open_cursor("index:poptable:country", null, null); + cursor.putKeyString("AU"); + ret = cursor.search(); + country = cursor.getValueString(); + year = cursor.getValueShort(); + population = cursor.getValueLong(); + System.out.println("AU: country " + country + ", year " + year + + ", population " + population); + /*! [Search in a simple index] */ + ret = cursor.close(); + + /*! [Search in a composite index] */ + /* Search in a composite index. */ + cursor = session.open_cursor( + "index:poptable:country_plus_year", null, null); + cursor.putKeyString("USA"); + cursor.putKeyShort((short)1900); + ret = cursor.search(); + country = cursor.getValueString(); + year = cursor.getValueShort(); + population = cursor.getValueLong(); + System.out.println("US 1900: country " + country + + ", year " + year + ", population " + population); + /*! [Search in a composite index] */ + ret = cursor.close(); + + /*! [Return a subset of values from the table] */ + /* + * Use a projection to return just the table's country and year + * columns. + */ + cursor = session.open_cursor("table:poptable(country,year)", null, null); + while ((ret = cursor.next()) == 0) { + country = cursor.getValueString(); + year = cursor.getValueShort(); + System.out.println("country " + country + ", year " + year); + } + /*! [Return a subset of values from the table] */ + ret = cursor.close(); + + /*! [Return a subset of values from the table using raw mode] */ + /* + * Use a projection to return just the table's country and year + * columns. + */ + cursor = session.open_cursor("table:poptable(country,year)", null, null); + while ((ret = cursor.next()) == 0) { + country = cursor.getValueString(); + year = cursor.getValueShort(); + System.out.println("country " + country + ", year " + year); + } + /*! [Return a subset of values from the table using raw mode] */ + ret = cursor.close(); + + /*! [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. + */ + cursor = session.open_cursor("index:poptable:country_plus_year(id)", null, null); + while ((ret = cursor.next()) == 0) { + country = cursor.getKeyString(); + year = cursor.getKeyShort(); + recno = cursor.getValueRecord(); + System.out.println("row ID " + recno + ": country " + country + + ", year " + year); + } + /*! [Return the table's record number key using an index] */ + ret = cursor.close(); + + /*! [Return a subset of the value columns from an index] */ + /* + * Use a projection to return just the population column from an + * index. + */ + cursor = session.open_cursor( + "index:poptable:country_plus_year(population)", null, null); + while ((ret = cursor.next()) == 0) { + country = cursor.getKeyString(); + year = cursor.getKeyShort(); + population = cursor.getValueLong(); + System.out.println("population " + population + + ": country " + country + ", year " + year); + } + /*! [Return a subset of the value columns from an index] */ + ret = cursor.close(); + + /*! [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. + */ + cursor = session.open_cursor( + "index:poptable:country_plus_year()", null, null); + while ((ret = cursor.next()) == 0) { + country = cursor.getKeyString(); + year = cursor.getKeyShort(); + System.out.println("country " + country + ", year " + year); + } + /*! [Access only the index] */ + ret = cursor.close(); + + /*! [Join cursors] */ + /* Open cursors needed by the join. */ + join_cursor = session.open_cursor( + "join:table:poptable", null, null); + cursor = session.open_cursor( + "index:poptable:country", null, null); + cursor2 = session.open_cursor( + "index:poptable:immutable_year", null, null); + + /* select values WHERE country == "AU" AND year > 1900 */ + cursor.putKeyString("AU"); + ret = cursor.search(); + session.join(join_cursor, cursor, "compare=eq,count=10"); + cursor2.putKeyShort((short)1900); + ret = cursor2.search(); + session.join(join_cursor, cursor2, + "compare=gt,count=10,strategy=bloom"); + + /* List the values that are joined */ + while ((ret = join_cursor.next()) == 0) { + recno = join_cursor.getKeyRecord(); + country = join_cursor.getValueString(); + year = join_cursor.getValueShort(); + population = join_cursor.getValueLong(); + System.out.print("ID " + recno); + System.out.println( ": country " + country + ", year " + year + + ", population " + population); + } + /*! [Join cursors] */ + ret = join_cursor.close(); + ret = cursor2.close(); + ret = cursor.close(); + + ret = conn.close(null); + + return (ret); + } + + public static void + main(String[] argv) + { + try { + System.exit(schemaExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_stat.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_stat.java new file mode 100644 index 00000000000..b0b83a2d3b2 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_stat.java @@ -0,0 +1,256 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_stat.java + * This is an example demonstrating how to query database statistics. + */ +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +public class ex_stat { + + public static String home; + + /*! [statistics display function] */ + int + print_cursor(Cursor cursor) + throws WiredTigerException + { + String desc, pvalue; + long value; + int ret; + + while ((ret = cursor.next()) == 0) { + desc = cursor.getValueString(); + pvalue = cursor.getValueString(); + value = cursor.getValueLong(); + if (value != 0) + System.out.println(desc + "=" + pvalue); + } + + return (ret == wiredtiger.WT_NOTFOUND ? 0 : ret); + } + /*! [statistics display function] */ + + int + print_database_stats(Session session) + throws WiredTigerException + { + Cursor cursor; + int ret; + + /*! [statistics database function] */ + cursor = session.open_cursor("statistics:", null, null); + + ret = print_cursor(cursor); + ret = cursor.close(); + /*! [statistics database function] */ + + return (ret); + } + + int + print_file_stats(Session session) + throws WiredTigerException + { + Cursor cursor; + int ret; + + /*! [statistics table function] */ + cursor = session.open_cursor("statistics:table:access", null, null); + ret = print_cursor(cursor); + ret = cursor.close(); + /*! [statistics table function] */ + + return (ret); + } + + int + print_overflow_pages(Session session) + throws WiredTigerException + { + /*! [statistics retrieve by key] */ + Cursor cursor; + String desc, pvalue; + long value; + int ret; + + cursor = session.open_cursor("statistics:table:access", null, null); + + cursor.putKeyInt(wiredtiger.WT_STAT_DSRC_BTREE_OVERFLOW); + ret = cursor.search(); + desc = cursor.getValueString(); + pvalue = cursor.getValueString(); + value = cursor.getValueLong(); + System.out.println(desc + "=" + pvalue); + + ret = cursor.close(); + /*! [statistics retrieve by key] */ + + return (ret); + } + + /*! [statistics calculation helper function] */ + long + get_stat(Cursor cursor, int stat_field) + throws WiredTigerException + { + long value; + int ret; + + cursor.putKeyInt(stat_field); + if ((ret = cursor.search()) != 0) { + System.err.println("stat_field: " + stat_field + " not found"); + value = 0; + } + else { + String desc = cursor.getValueString(); + String pvalue = cursor.getValueString(); + value = cursor.getValueLong(); + } + return (value); + } + /*! [statistics calculation helper function] */ + + int + print_derived_stats(Session session) + throws WiredTigerException + { + Cursor cursor; + int ret; + + /*! [statistics calculate open table stats] */ + cursor = session.open_cursor("statistics:table:access", null, null); + /*! [statistics calculate open table stats] */ + + { + /*! [statistics calculate table fragmentation] */ + long ckpt_size = get_stat(cursor, + wiredtiger.WT_STAT_DSRC_BLOCK_CHECKPOINT_SIZE); + long file_size = get_stat(cursor, + wiredtiger.WT_STAT_DSRC_BLOCK_SIZE); + + System.out.println("File is " + + (int)(100 * (file_size - ckpt_size) / file_size) + + "% fragmented\n"); + /*! [statistics calculate table fragmentation] */ + } + + { + /*! [statistics calculate write amplification] */ + long app_insert = get_stat(cursor, + wiredtiger.WT_STAT_DSRC_CURSOR_INSERT_BYTES); + long app_remove = get_stat(cursor, + wiredtiger.WT_STAT_DSRC_CURSOR_REMOVE_BYTES); + long app_update = get_stat(cursor, + wiredtiger.WT_STAT_DSRC_CURSOR_UPDATE_BYTES); + + long fs_writes = get_stat(cursor, + wiredtiger.WT_STAT_DSRC_CACHE_BYTES_WRITE); + + if (app_insert + app_remove + app_update != 0) + System.out.println("Write amplification is " + + (double)fs_writes / (app_insert + app_remove + app_update)); + /*! [statistics calculate write amplification] */ + } + + ret = cursor.close(); + + return (ret); + } + + public int + statExample() + throws WiredTigerException + { + Connection conn; + Cursor cursor; + 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 (System.getenv("WIREDTIGER_HOME") == null) { + home = "WT_HOME"; + try { + Process proc = Runtime.getRuntime().exec("/bin/rm -rf " + home); + BufferedReader br = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + while(br.ready()) + System.out.println(br.readLine()); + br.close(); + proc.waitFor(); + if (!(new File(home)).mkdir()) + System.err.println("mkdir: failed"); + } catch (Exception ex) { + System.err.println("Exception: " + home + ": " + ex); + System.exit(1); + } + } else + home = null; + + conn = wiredtiger.open(home, "create,statistics=(all)"); + session = conn.open_session(null); + + ret = session.create("table:access", "key_format=S,value_format=S"); + + cursor = session.open_cursor("table:access", null, null); + cursor.putKeyString("key"); + cursor.putValueString("value"); + ret = cursor.insert(); + ret = cursor.close(); + + ret = session.checkpoint(null); + + ret = print_database_stats(session); + + ret = print_file_stats(session); + + ret = print_overflow_pages(session); + + ret = print_derived_stats(session); + + return (conn.close(null) == 0 ? ret : -1); + } + + public static void + main(String[] argv) + { + try { + System.exit((new ex_stat()).statExample()); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } +} diff --git a/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_thread.java b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_thread.java new file mode 100644 index 00000000000..402daebbd61 --- /dev/null +++ b/src/third_party/wiredtiger/examples/java/com/wiredtiger/examples/ex_thread.java @@ -0,0 +1,149 @@ +/*- + * Public Domain 2014-2016 MongoDB, Inc. + * Public Domain 2008-2014 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ex_thread.java + * This is an example demonstrating how to create and access a simple + * table from multiple threads. + */ + +package com.wiredtiger.examples; +import com.wiredtiger.db.*; +import java.io.*; +import java.util.*; + +/*! [thread scan] */ +class ScanThread extends Thread { + private Connection conn; + + public ScanThread(Connection conn) { + this.conn = conn; + } + + public void run() + { + try { + int ret; + + Session session = conn.open_session(null); + Cursor cursor = session.open_cursor("table:access", null, null); + + /* Show all records. */ + while ((ret = cursor.next()) == 0) { + String key = cursor.getKeyString(); + String value = cursor.getValueString(); + System.out.println("Got record: " + key + " : " + value); + } + if (ret != wiredtiger.WT_NOTFOUND) + System.err.println("Cursor.next: " + + wiredtiger.wiredtiger_strerror(ret)); + cursor.close(); + session.close(null); + } catch (WiredTigerException wte) { + System.err.println("Exception " + wte); + } + } +} +/*! [thread scan] */ + +public class ex_thread { + + public static String home; + + public static final int NUM_THREADS = 10; + + /*! [thread main] */ + public static void main(String[] argv) + { + try { + Thread[] threads = new Thread[NUM_THREADS]; + int i, ret; + Connection conn; + + /* + * 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 (System.getenv("WIREDTIGER_HOME") == null) { + home = "WT_HOME"; + try { + Process proc = Runtime.getRuntime().exec("/bin/rm -rf " + home); + BufferedReader br = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + while(br.ready()) + System.out.println(br.readLine()); + br.close(); + proc.waitFor(); + if (!(new File(home)).mkdir()) + System.err.println("mkdir: failed"); + } catch (Exception ex) { + System.err.println("Exception: " + home + ": " + ex); + System.exit(1); + } + } else + home = null; + + if ((conn = wiredtiger.open(home, "create")) == null) { + System.err.println("Error connecting to " + home); + System.exit(1); + } + + /* Note: further error checking omitted for clarity. */ + + Session session = conn.open_session(null); + ret = session.create("table:access", "key_format=S,value_format=S"); + Cursor cursor = session.open_cursor("table:access", null, "overwrite"); + cursor.putKeyString("key1"); + cursor.putValueString("value1"); + ret = cursor.insert(); + cursor.close(); + ret = session.close(null); + + for (i = 0; i < NUM_THREADS; i++) { + threads[i] = new ScanThread(conn); + threads[i].start(); + } + + for (i = 0; i < NUM_THREADS; i++) + try { + threads[i].join(); + ret = -1; + } + catch (InterruptedException ie) { + } + + ret = conn.close(null); + System.exit(ret); + } + catch (WiredTigerException wte) { + System.err.println("Exception: " + wte); + wte.printStackTrace(); + System.exit(1); + } + } + /*! [thread main] */ + +} diff --git a/src/third_party/wiredtiger/examples/python/ex_access.py b/src/third_party/wiredtiger/examples/python/ex_access.py new file mode 100755 index 00000000000..aa99c1f6547 --- /dev/null +++ b/src/third_party/wiredtiger/examples/python/ex_access.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# Public Domain 2014-2016 MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# + +import os +from wiredtiger import wiredtiger_open + +# Connect to the database and open a session +os.system('rm -rf WT_HOME') +os.makedirs('WT_HOME') + +conn = wiredtiger_open('WT_HOME', 'create') +session = conn.open_session() + +# Create a simple table +session.create('table:T', 'key_format=S,value_format=S') + +# Open a cursor and insert a record +cursor = session.open_cursor('table:T', None) + +cursor.set_key('key1') +cursor.set_value('value1') +cursor.insert() + +# Iterate through the records +cursor.reset() +for key, value in cursor: + print('Got record: %s : %s' % (key, value)) + +conn.close() diff --git a/src/third_party/wiredtiger/examples/python/ex_stat.py b/src/third_party/wiredtiger/examples/python/ex_stat.py new file mode 100755 index 00000000000..10f1d6d597c --- /dev/null +++ b/src/third_party/wiredtiger/examples/python/ex_stat.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# +# Public Domain 2014-2016 MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# ex_stat.py +# This is an example demonstrating how to query database statistics. + +import os +from wiredtiger import wiredtiger_open,WIREDTIGER_VERSION_STRING,stat + + +def main(): + # Create a clean test directory for this run of the test program + os.system('rm -rf WT_HOME') + os.makedirs('WT_HOME') + # Connect to the database and open a session + conn = wiredtiger_open('WT_HOME', 'create,statistics=(all)') + session = conn.open_session() + + # Create a simple table + session.create('table:access', 'key_format=S,value_format=S') + + # Open a cursor and insert a record + cursor = session.open_cursor('table:access', None) + + cursor['key'] = 'value' + cursor.close() + + session.checkpoint() + print WIREDTIGER_VERSION_STRING + print_database_stats(session) + print_file_stats(session) + print_overflow_pages(session) + print_derived_stats(session) + conn.close() + + +def print_database_stats(session): + statcursor = session.open_cursor("statistics:") + print_cursor(statcursor) + statcursor.close() + + +def print_file_stats(session): + fstatcursor = session.open_cursor("statistics:table:access") + print_cursor(fstatcursor) + fstatcursor.close() + + +def print_overflow_pages(session): + ostatcursor = session.open_cursor("statistics:table:access") + val = ostatcursor[stat.dsrc.btree_overflow] + if val != 0: + print '%s=%s' % (str(val[0]), str(val[1])) + ostatcursor.close() + + +def print_derived_stats(session): + dstatcursor = session.open_cursor("statistics:table:access") + ckpt_size = dstatcursor[stat.dsrc.block_checkpoint_size][1] + file_size = dstatcursor[stat.dsrc.block_size][1] + percent = 0 + if file_size != 0: + percent = 100 * ((float(file_size) - float(ckpt_size)) / float(file_size)) + print "Table is %%%s fragmented" % str(percent) + + app_insert = int(dstatcursor[stat.dsrc.cursor_insert_bytes][1]) + app_remove = int(dstatcursor[stat.dsrc.cursor_remove_bytes][1]) + app_update = int(dstatcursor[stat.dsrc.cursor_update_bytes][1]) + fs_writes = int(dstatcursor[stat.dsrc.cache_bytes_write][1]) + + if app_insert + app_remove + app_update != 0: + print "Write amplification is " + '{:.2f}'.format(fs_writes / (app_insert + app_remove + app_update)) + dstatcursor.close() + + +def print_cursor(mycursor): + while mycursor.next() == 0: + val = mycursor.get_value() + if val[1] != '0': + print '%s=%s' % (str(val[0]), str(val[1])) + +if __name__ == "__main__": + main() + |