summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/examples/c/ex_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/examples/c/ex_log.c')
-rw-r--r--src/third_party/wiredtiger/examples/c/ex_log.c358
1 files changed, 358 insertions, 0 deletions
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);
+}