void populate(TEST_OPTS *opts) { WT_CURSOR *maincur; WT_SESSION *session; uint32_t key; int balance, i, flag, post; WT_RAND_STATE rnd; testutil_check(__wt_random_init_seed(NULL, &rnd)); testutil_check(opts->conn->open_session( opts->conn, NULL, NULL, &session)); testutil_check(session->open_cursor(session, opts->uri, NULL, NULL, &maincur)); for (i = 0; i < N_INSERT; i++) { testutil_check(session->begin_transaction(session, NULL)); key = (__wt_random(&rnd) % (N_RECORDS)); maincur->set_key(maincur, key); if (__wt_random(&rnd) % 11 == 0) post = 54321; else post = i % 100000; if (__wt_random(&rnd) % 4 == 0) { balance = -100; flag = 1; } else { balance = 100 * (i + 1); flag = 0; } maincur->set_value(maincur, post, balance, flag, key); testutil_check(maincur->insert(maincur)); testutil_check(session->commit_transaction(session, NULL)); } maincur->close(maincur); session->close(session, NULL); }
int main(int argc, char *argv[]) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; home = example_setup(argc, argv); error_check( wiredtiger_open(home, NULL, "create,statistics=(all)", &conn)); error_check(conn->open_session(conn, NULL, NULL, &session)); error_check(session->create(session, "table:access", "key_format=S,value_format=S,columns=(k,v)")); error_check(session->open_cursor( session, "table:access", NULL, NULL, &cursor)); cursor->set_key(cursor, "key"); cursor->set_value(cursor, "value"); error_check(cursor->insert(cursor)); error_check(cursor->close(cursor)); error_check(session->checkpoint(session, NULL)); print_database_stats(session); print_file_stats(session); print_join_cursor_stats(session); print_overflow_pages(session); print_derived_stats(session); error_check(conn->close(conn, NULL)); return (EXIT_SUCCESS); }
TEST_F(WiredTigerRecoveryUnitTestFixture, LocalReadOnADocumentBeingPreparedDoesntTriggerPrepareConflict) { // Prepare but don't commit a transaction ru1->beginUnitOfWork(clientAndCtx1.second.get()); WT_CURSOR* cursor; getCursor(ru1, &cursor); cursor->set_key(cursor, "key"); cursor->set_value(cursor, "value"); invariantWTOK(cursor->insert(cursor)); ru1->setPrepareTimestamp({1, 1}); ru1->prepareUnitOfWork(); // A transaction that chooses to ignore prepare conflicts does not see the record instead of // returning a prepare conflict. ru2->beginUnitOfWork(clientAndCtx2.second.get()); ru2->setIgnorePrepared(true); getCursor(ru2, &cursor); cursor->set_key(cursor, "key"); int ret = cursor->search(cursor); ASSERT_EQ(WT_NOTFOUND, ret); ru1->abortUnitOfWork(); ru2->abortUnitOfWork(); }
/* * json_data -- * Parse the data portion of the JSON input, and insert all * values. */ static int json_data(WT_SESSION *session, JSON_INPUT_STATE *ins, CONFIG_LIST *clp, uint32_t flags) { WT_CURSOR *cursor; WT_DECL_RET; char config[64], *endp, *uri; const char *keyformat; int isrec, nfield, nkeys, toktype, tret; size_t keystrlen; ssize_t gotnolen; uint64_t gotno, recno; cursor = NULL; uri = NULL; /* Reorder and check the list. */ if ((ret = config_reorder(clp->list)) != 0) goto err; /* Update config based on command-line configuration. */ if ((ret = config_update(session, clp->list)) != 0) goto err; /* Create the items collected. */ if ((ret = config_exec(session, clp->list)) != 0) goto err; uri = clp->list[0]; (void)snprintf(config, sizeof(config), "dump=json%s%s", LF_ISSET(LOAD_JSON_APPEND) ? ",append" : "", LF_ISSET(LOAD_JSON_NO_OVERWRITE) ? ",overwrite=false" : ""); if ((ret = session->open_cursor( session, uri, NULL, config, &cursor)) != 0) { ret = util_err(ret, "%s: session.open", uri); goto err; } keyformat = cursor->key_format; isrec = (strcmp(keyformat, "r") == 0); for (nkeys = 0; *keyformat; keyformat++) if (!isdigit(*keyformat)) nkeys++; recno = 0; while (json_peek(session, ins) == '{') { nfield = 0; JSON_EXPECT(session, ins, '{'); if (ins->kvraw == NULL) { if ((ins->kvraw = (char *)malloc(1)) == NULL) { ret = util_err(errno, NULL); goto err; } } ins->kvraw[0] = '\0'; ins->kvrawstart = JSON_INPUT_POS(ins); keystrlen = 0; while (json_peek(session, ins) == 's') { JSON_EXPECT(session, ins, 's'); JSON_EXPECT(session, ins, ':'); toktype = json_peek(session, ins); JSON_EXPECT(session, ins, toktype); if (isrec && nfield == 0) { /* Verify the dump has recnos in order. */ recno++; gotno = __wt_strtouq(ins->tokstart, &endp, 0); gotnolen = (endp - ins->tokstart); if (recno != gotno || ins->toklen != (size_t)gotnolen) { ret = util_err(0, "%s: recno out of order", uri); goto err; } } if (++nfield == nkeys) { size_t curpos = JSON_INPUT_POS(ins); if ((ret = json_kvraw_append(ins, (char *)ins->line.mem + ins->kvrawstart, curpos - ins->kvrawstart)) != 0) goto err; ins->kvrawstart = curpos; keystrlen = strlen(ins->kvraw); } if (json_peek(session, ins) != ',') break; JSON_EXPECT(session, ins, ','); if (json_peek(session, ins) != 's') goto err; } if (json_kvraw_append(ins, ins->line.mem, JSON_INPUT_POS(ins))) goto err; ins->kvraw[keystrlen] = '\0'; if (!LF_ISSET(LOAD_JSON_APPEND)) cursor->set_key(cursor, ins->kvraw); /* skip over inserted space and comma */ cursor->set_value(cursor, &ins->kvraw[keystrlen+2]); if ((ret = cursor->insert(cursor)) != 0) { ret = util_err(ret, "%s: cursor.insert", uri); goto err; } JSON_EXPECT(session, ins, '}'); if (json_peek(session, ins) != ',') break; JSON_EXPECT(session, ins, ','); if (json_peek(session, ins) != '{') goto err; } if (0) { err: if (ret == 0) ret = EINVAL; } /* * Technically, we don't have to close the cursor because the session * handle will do it for us, but I'd like to see the flush to disk and * the close succeed, it's better to fail early when loading files. */ if (cursor != NULL && (tret = cursor->close(cursor)) != 0) { tret = util_err(tret, "%s: cursor.close", uri); if (ret == 0) ret = tret; } if (ret == 0) ret = util_flush(session, uri); return (ret); }
int transaction_ops(WT_CONNECTION *conn, WT_SESSION *session) { WT_CURSOR *cursor; int ret; /*! [transaction commit/rollback] */ ret = session->open_cursor(session, "table:mytable", NULL, NULL, &cursor); ret = session->begin_transaction(session, 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->set_key(cursor, "key"); cursor->set_value(cursor, "value"); switch (ret = cursor->update(cursor)) { case 0: /* Update success */ ret = session->commit_transaction(session, NULL); /* * The commit_transaction call resets all open cursors. * If commit_transaction fails, the transaction was rolled-back. */ break; case WT_DEADLOCK: /* Update conflict */ default: /* Other error */ ret = session->rollback_transaction(session, 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(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] */ 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); /* * 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 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 off] */ ret = session->create(session, "table:mytable", "key_format=S,value_format=S,prefix_compression=false"); /*! [Configure key prefix compression off] */ 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] */ /*! [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] */ { /* * 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); 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); }
/* * Child process creates the database and table, and then writes data into * the table until it is killed by the parent. */ static void fill_db(void) { FILE *fp; WT_CONNECTION *conn; WT_CURSOR *cursor; WT_ITEM data; WT_RAND_STATE rnd; WT_SESSION *session; uint64_t i; int ret; uint8_t buf[MAX_VAL]; __wt_random_init(&rnd); memset(buf, 0, sizeof(buf)); /* * Initialize the first 25% to random values. Leave a bunch of data * space at the end to emphasize zero data. */ for (i = 0; i < MAX_VAL/4; i++) buf[i] = (uint8_t)__wt_random(&rnd); /* * Run in the home directory so that the records file is in there too. */ chdir(home); if ((ret = wiredtiger_open(NULL, NULL, ENV_CONFIG, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); if ((ret = session->create(session, uri, "key_format=Q,value_format=u")) != 0) testutil_die(ret, "WT_SESSION.create: %s", uri); if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri); /* * Keep a separate file with the records we wrote for checking. */ (void)unlink(RECORDS_FILE); if ((fp = fopen(RECORDS_FILE, "w")) == NULL) testutil_die(errno, "fopen"); /* * Set to no buffering. */ setvbuf(fp, NULL, _IONBF, 0); /* * Write data into the table until we are killed by the parent. * The data in the buffer is already set to random content. */ data.data = buf; for (i = 0;; ++i) { data.size = __wt_random(&rnd) % MAX_VAL; cursor->set_key(cursor, i); cursor->set_value(cursor, &data); if ((ret = cursor->insert(cursor)) != 0) testutil_die(ret, "WT_CURSOR.insert"); /* * Save the key separately for checking later. */ if (fprintf(fp, "%" PRIu64 "\n", i) == -1) testutil_die(errno, "fprintf"); if (i % 5000) __wt_yield(); } }
int main(int argc, char *argv[]) { WT_CONNECTION *conn, *conn2, *conn3, *conn4; WT_CURSOR *cursor; WT_ITEM data; WT_SESSION *session; uint64_t i; int ch, status, op, ret; bool child; const char *working_dir; char cmd[512]; uint8_t buf[MAX_VAL]; if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL) progname = argv[0]; else ++progname; /* * Needed unaltered for system command later. */ saved_argv0 = argv[0]; working_dir = "WT_RD"; child = false; op = OP_READ; while ((ch = __wt_getopt(progname, argc, argv, "Rh:W")) != EOF) switch (ch) { case 'R': child = true; op = OP_READ; break; case 'W': child = true; op = OP_WRITE; break; case 'h': working_dir = __wt_optarg; break; default: usage(); } argc -= __wt_optind; argv += __wt_optind; if (argc != 0) usage(); /* * Set up all the directory names. */ testutil_work_dir_from_path(home, sizeof(home), working_dir); (void)snprintf(home_wr, sizeof(home_wr), "%s%s", home, HOME_WR_SUFFIX); (void)snprintf(home_rd, sizeof(home_rd), "%s%s", home, HOME_RD_SUFFIX); (void)snprintf( home_rd2, sizeof(home_rd2), "%s%s", home, HOME_RD2_SUFFIX); if (!child) { testutil_make_work_dir(home); testutil_make_work_dir(home_wr); testutil_make_work_dir(home_rd); testutil_make_work_dir(home_rd2); } else /* * We are a child process, we just want to call * the open_dbs with the directories we have. * The child function will exit. */ open_dbs(op, home, home_wr, home_rd, home_rd2); /* * Parent creates a database and table. Then cleanly shuts down. * Then copy database to read-only directory and chmod. * Also copy database to read-only directory and remove the lock * file. One read-only database will have a lock file in the * file system and the other will not. * Parent opens all databases with read-only configuration flag. * Parent forks off child who tries to also open all databases * with the read-only flag. It should error on the writeable * directory, but allow it on the read-only directories. * The child then confirms it can read all the data. */ /* * Run in the home directory and create the table. */ if ((ret = wiredtiger_open(home, NULL, ENV_CONFIG, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); if ((ret = session->create(session, uri, "key_format=Q,value_format=u")) != 0) testutil_die(ret, "WT_SESSION.create: %s", uri); if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", uri); /* * Write data into the table and then cleanly shut down connection. */ memset(buf, 0, sizeof(buf)); data.data = buf; data.size = MAX_VAL; for (i = 0; i < MAX_KV; ++i) { cursor->set_key(cursor, i); cursor->set_value(cursor, &data); if ((ret = cursor->insert(cursor)) != 0) testutil_die(ret, "WT_CURSOR.insert"); } if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); /* * Copy the database. Remove any lock file from one copy * and chmod the copies to be read-only permissions. */ (void)snprintf(cmd, sizeof(cmd), "cp -rp %s/* %s; rm -f %s/WiredTiger.lock", home, home_wr, home_wr); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); (void)snprintf(cmd, sizeof(cmd), "cp -rp %s/* %s; chmod 0555 %s; chmod -R 0444 %s/*", home, home_rd, home_rd, home_rd); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); (void)snprintf(cmd, sizeof(cmd), "cp -rp %s/* %s; rm -f %s/WiredTiger.lock; " "chmod 0555 %s; chmod -R 0444 %s/*", home, home_rd2, home_rd2, home_rd2, home_rd2); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); /* * Run four scenarios. Sometimes expect errors, sometimes success. * The writable database directories should always fail to allow the * child to open due to the lock file. The read-only ones will only * succeed when the child attempts read-only. * * 1. Parent has read-only handle to all databases. Child opens * read-only also. * 2. Parent has read-only handle to all databases. Child opens * read-write. * 3. Parent has read-write handle to writable databases and * read-only to read-only databases. Child opens read-only. * 4. Parent has read-write handle to writable databases and * read-only to read-only databases. Child opens read-write. */ /* * Open a connection handle to all databases. */ fprintf(stderr, " *** Expect several error messages from WT ***\n"); /* * Scenario 1. */ if ((ret = wiredtiger_open(home, NULL, ENV_CONFIG_RD, &conn)) != 0) testutil_die(ret, "wiredtiger_open original home"); if ((ret = wiredtiger_open(home_wr, NULL, ENV_CONFIG_RD, &conn2)) != 0) testutil_die(ret, "wiredtiger_open write nolock"); if ((ret = wiredtiger_open(home_rd, NULL, ENV_CONFIG_RD, &conn3)) != 0) testutil_die(ret, "wiredtiger_open readonly"); if ((ret = wiredtiger_open(home_rd2, NULL, ENV_CONFIG_RD, &conn4)) != 0) testutil_die(ret, "wiredtiger_open readonly nolock"); /* * Create a child to also open a connection handle to the databases. * We cannot use fork here because using fork the child inherits the * same memory image. Therefore the WT process structure is set in * the child even though it should not be. So use 'system' to spawn * an entirely new process. * * The child will exit with success if its test passes. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -R", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Scenario 2. Run child with writable config. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -W", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Reopen the two writable directories and rerun the child. */ if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn2->close(conn2, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = wiredtiger_open(home, NULL, ENV_CONFIG_RD, &conn)) != 0) testutil_die(ret, "wiredtiger_open original home"); if ((ret = wiredtiger_open(home_wr, NULL, ENV_CONFIG_RD, &conn2)) != 0) testutil_die(ret, "wiredtiger_open write nolock"); /* * Scenario 3. Child read-only. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -R", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Scenario 4. Run child with writable config. */ (void)snprintf( cmd, sizeof(cmd), "%s -h %s -W", saved_argv0, working_dir); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); if (WEXITSTATUS(status) != 0) testutil_die(WEXITSTATUS(status), "system: %s", cmd); /* * Clean-up. */ if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn2->close(conn2, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn3->close(conn3, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); if ((ret = conn4->close(conn4, NULL)) != 0) testutil_die(ret, "WT_CONNECTION:close"); /* * We need to chmod the read-only databases back so that they can * be removed by scripts. */ (void)snprintf(cmd, sizeof(cmd), "chmod 0777 %s %s", home_rd, home_rd2); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); (void)snprintf(cmd, sizeof(cmd), "chmod -R 0666 %s/* %s/*", home_rd, home_rd2); if ((status = system(cmd)) < 0) testutil_die(status, "system: %s", cmd); printf(" *** Readonly test successful ***\n"); return (EXIT_SUCCESS); }
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]; 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"); 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); } 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); ret = cursor->close(cursor); /*! [log cursor printf] */ ret = session->log_printf(session, "Wrote %d records", record_count); /*! [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); ret = walk_log(session); ret = wt_conn->close(wt_conn, NULL); return (ret); }
static void run(CONFIG *cp, int bigkey, size_t bytes) { WT_CONNECTION *conn; WT_SESSION *session; WT_CURSOR *cursor; uint64_t keyno; int ret; void *p; big[bytes - 1] = '\0'; printf(SIZET_FMT "%s%s: %s %s big %s\n", bytes < MEGABYTE ? bytes : (bytes < GIGABYTE ? bytes / MEGABYTE : bytes / GIGABYTE), bytes < MEGABYTE ? "" : (bytes < GIGABYTE ? (bytes % MEGABYTE == 0 ? "" : "+") : (bytes % GIGABYTE == 0 ? "" : "+")), bytes < MEGABYTE ? "B" : (bytes < GIGABYTE ? "MB" : "GB"), cp->uri, cp->config, bigkey ? "key" : "value"); testutil_make_work_dir(home); /* * Open/create the database, connection, session and cursor; set the * cache size large, we don't want to try and evict anything. */ if ((ret = wiredtiger_open( home, NULL, "create,cache_size=10GB", &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION.open_session"); if ((ret = session->create(session, cp->uri, cp->config)) != 0) testutil_die(ret, "WT_SESSION.create: %s %s", cp->uri, cp->config); if ((ret = session->open_cursor(session, cp->uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", cp->uri); /* Set the key/value. */ if (bigkey) cursor->set_key(cursor, big); else if (cp->recno) { keyno = 1; cursor->set_key(cursor, keyno); } else cursor->set_key(cursor, "key001"); cursor->set_value(cursor, big); /* Insert the record (use update, insert discards the key). */ if ((ret = cursor->update(cursor)) != 0) testutil_die(ret, "WT_CURSOR.insert"); /* Retrieve the record and check it. */ if ((ret = cursor->search(cursor)) != 0) testutil_die(ret, "WT_CURSOR.search"); if (bigkey && (ret = cursor->get_key(cursor, &p)) != 0) testutil_die(ret, "WT_CURSOR.get_key"); if ((ret = cursor->get_value(cursor, &p)) != 0) testutil_die(ret, "WT_CURSOR.get_value"); if (memcmp(p, big, bytes) != 0) testutil_die(0, "retrieved big key/value item did not match original"); /* Remove the record. */ if ((ret = cursor->remove(cursor)) != 0) testutil_die(ret, "WT_CURSOR.remove"); if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION.close"); big[bytes - 1] = 'a'; }
void worker(CONFIG *cfg, uint32_t worker_type) { WT_CONNECTION *conn; WT_SESSION *session; WT_CURSOR *cursor; const char *op_name = "search"; char *data_buf, *key_buf, *value; int ret, op_ret; uint64_t next_val; session = NULL; data_buf = key_buf = NULL; op_ret = 0; conn = cfg->conn; key_buf = calloc(cfg->key_sz + 1, 1); if (key_buf == NULL) { lprintf(cfg, ret = ENOMEM, 0, "Populate key buffer"); goto err; } if (worker_type == WORKER_INSERT) { data_buf = calloc(cfg->data_sz, 1); if (data_buf == NULL) { lprintf(cfg, ret = ENOMEM, 0, "Populate data buffer"); goto err; } memset(data_buf, 'a', cfg->data_sz - 1); } if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { lprintf(cfg, ret, 0, "open_session failed in read thread"); goto err; } if ((ret = session->open_cursor(session, cfg->uri, NULL, NULL, &cursor)) != 0) { lprintf(cfg, ret, 0, "open_cursor failed in read thread"); goto err; } while (g_running) { /* Get a value in range, avoid zero. */ #define VALUE_RANGE (cfg->icount + g_nins_ops - (cfg->insert_threads + 1)) next_val = (worker_type == WORKER_INSERT ? (cfg->icount + ATOMIC_ADD(g_nins_ops, 1)) : ((uint64_t)rand() % VALUE_RANGE) + 1); /* * If the workload is started without a populate phase we * rely on at least one insert to get a valid item id. */ if (worker_type != WORKER_INSERT && VALUE_RANGE < next_val) continue; sprintf(key_buf, "%0*" PRIu64, cfg->key_sz, next_val); cursor->set_key(cursor, key_buf); switch(worker_type) { case WORKER_READ: op_name = "read"; op_ret = cursor->search(cursor); if (op_ret == 0) ++g_nread_ops; break; case WORKER_INSERT: op_name = "insert"; cursor->set_value(cursor, data_buf); op_ret = cursor->insert(cursor); if (op_ret != 0) ++g_nfailedins_ops; break; case WORKER_UPDATE: op_name = "update"; op_ret = cursor->search(cursor); if (op_ret == 0) { cursor->get_value(cursor, &value); if (value[0] == 'a') value[0] = 'b'; else value[0] = 'a'; op_ret = cursor->update(cursor); } if (op_ret == 0) ++g_nupdate_ops; break; default: lprintf(cfg, EINVAL, 0, "Invalid worker type"); goto err; } /* Report errors and continue. */ if (op_ret != 0) lprintf(cfg, op_ret, 0, "%s failed for: %s", op_name, key_buf); else ++g_nworker_ops; } err: if (ret != 0) ++g_threads_quit; if (session != NULL) session->close(session, NULL); if (data_buf != NULL) free(data_buf); if (key_buf != NULL) free(key_buf); }
static void transaction_ops(WT_SESSION *session_arg) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; session = session_arg; conn = session->connection; /*! [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. */ error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); error_check(session->begin_transaction(session, NULL)); cursor->set_key(cursor, "key"); cursor->set_value(cursor, "value"); switch (cursor->update(cursor)) { case 0: /* Update success */ error_check(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 */ error_check(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] */ error_check(cursor->close(cursor)); /*! [transaction isolation] */ /* A single transaction configured for snapshot isolation. */ error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); error_check(session->begin_transaction(session, "isolation=snapshot")); cursor->set_key(cursor, "some-key"); cursor->set_value(cursor, "some-value"); error_check(cursor->update(cursor)); error_check(session->commit_transaction(session, NULL)); /*! [transaction isolation] */ { /*! [transaction prepare] */ /* * Prepare a transaction which guarantees a subsequent commit will * succeed. Only commit and rollback are allowed on a transaction after * it has been prepared. */ error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); error_check(session->begin_transaction(session, NULL)); cursor->set_key(cursor, "key"); cursor->set_value(cursor, "value"); error_check(session->prepare_transaction( session, "prepare_timestamp=2a")); error_check(session->commit_transaction( session, "commit_timestamp=2b")); /*! [transaction prepare] */ } /*! [session isolation configuration] */ /* Open a session configured for read-uncommitted isolation. */ error_check(conn->open_session( conn, NULL, "isolation=read-uncommitted", &session)); /*! [session isolation configuration] */ /*! [session isolation re-configuration] */ /* Re-configure a session for snapshot isolation. */ error_check(session->reconfigure(session, "isolation=snapshot")); /*! [session isolation re-configuration] */ error_check(session->close(session, NULL)); session = session_arg; { /*! [transaction pinned range] */ /* Check the transaction ID range pinned by the session handle. */ uint64_t range; error_check(session->transaction_pinned_range(session, &range)); /*! [transaction pinned range] */ } error_check(session->begin_transaction(session, NULL)); { /*! [query timestamp] */ char timestamp_buf[2 * sizeof(uint64_t) + 1]; /*! [transaction timestamp] */ error_check( session->timestamp_transaction(session, "commit_timestamp=2a")); /*! [transaction timestamp] */ error_check(session->commit_transaction(session, NULL)); error_check(conn->query_timestamp( conn, timestamp_buf, "get=all_committed")); /*! [query timestamp] */ } /*! [set commit timestamp] */ error_check(conn->set_timestamp(conn, "commit_timestamp=2a")); /*! [set commit timestamp] */ /*! [set oldest timestamp] */ error_check(conn->set_timestamp(conn, "oldest_timestamp=2a")); /*! [set oldest timestamp] */ /*! [set stable timestamp] */ error_check(conn->set_timestamp(conn, "stable_timestamp=2a")); /*! [set stable timestamp] */ /*! [rollback to stable] */ error_check(conn->rollback_to_stable(conn, NULL)); /*! [rollback to stable] */ }
static void session_ops(WT_SESSION *session) { WT_CONNECTION *conn; conn = session->connection; /*! [Reconfigure a session] */ error_check(session->reconfigure(session, "isolation=snapshot")); /*! [Reconfigure a session] */ /*! [Create a table] */ error_check(session->create(session, "table:mytable", "key_format=S,value_format=S")); /*! [Create a table] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a column-store table] */ error_check(session->create(session, "table:mytable", "key_format=r,value_format=S")); /*! [Alter a table] */ error_check(session->alter(session, "table:mytable", "access_pattern_hint=random")); /*! [Alter a table] */ /*! [Create a column-store table] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a table with columns] */ /* * Create a table with columns: keys are record numbers, values are * (string, signed 32-bit integer, unsigned 16-bit integer). */ error_check(session->create(session, "table:mytable", "key_format=r,value_format=SiH," "columns=(id,department,salary,year-started)")); /*! [Create a table with columns] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a table and configure the page size] */ error_check(session->create(session, "table:mytable", "key_format=S,value_format=S," "internal_page_max=16KB,leaf_page_max=1MB,leaf_value_max=64KB")); /*! [Create a table and configure the page size] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a table and configure a large leaf value max] */ error_check(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] */ error_check(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 lz4 compressed table] */ error_check(session->create(session, "table:mytable", "block_compressor=lz4,key_format=S,value_format=S")); /*! [Create a lz4 compressed table] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a snappy compressed table] */ error_check(session->create(session, "table:mytable", "block_compressor=snappy,key_format=S,value_format=S")); /*! [Create a snappy compressed table] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a zlib compressed table] */ error_check(session->create(session, "table:mytable", "block_compressor=zlib,key_format=S,value_format=S")); /*! [Create a zlib compressed table] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a zstd compressed table] */ error_check(session->create(session, "table:mytable", "block_compressor=zstd,key_format=S,value_format=S")); /*! [Create a zstd compressed table] */ error_check(session->drop(session, "table:mytable", NULL)); #endif /*! [Configure checksums to uncompressed] */ error_check(session->create(session, "table:mytable", "key_format=S,value_format=S,checksum=uncompressed")); /*! [Configure checksums to uncompressed] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Configure dictionary compression on] */ error_check(session->create(session, "table:mytable", "key_format=S,value_format=S,dictionary=1000")); /*! [Configure dictionary compression on] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Configure key prefix compression on] */ error_check(session->create(session, "table:mytable", "key_format=S,value_format=S,prefix_compression=true")); /*! [Configure key prefix compression on] */ error_check(session->drop(session, "table:mytable", NULL)); #ifdef MIGHT_NOT_RUN /* Requires sync_file_range */ /*! [os_cache_dirty_max configuration] */ error_check(session->create( session, "table:mytable", "os_cache_dirty_max=500MB")); /*! [os_cache_dirty_max configuration] */ error_check(session->drop(session, "table:mytable", NULL)); /* Requires posix_fadvise */ /*! [os_cache_max configuration] */ error_check(session->create( session, "table:mytable", "os_cache_max=1GB")); /*! [os_cache_max configuration] */ error_check(session->drop(session, "table:mytable", NULL)); #endif /*! [Configure block_allocation] */ error_check(session->create(session, "table:mytable", "key_format=S,value_format=S,block_allocation=first")); /*! [Configure block_allocation] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Create a cache-resident object] */ error_check(session->create( session, "table:mytable", "key_format=r,value_format=S,cache_resident=true")); /*! [Create a cache-resident object] */ error_check(session->drop(session, "table:mytable", NULL)); { /* Create a table for the session operations. */ error_check(session->create( session, "table:mytable", "key_format=S,value_format=S")); /*! [Compact a table] */ error_check(session->compact(session, "table:mytable", NULL)); /*! [Compact a table] */ /*! [Rebalance a table] */ error_check(session->rebalance(session, "table:mytable", NULL)); /*! [Rebalance a table] */ error_check(session->create( session, "table:old", "key_format=r,value_format=S,cache_resident=true")); /*! [Rename a table] */ error_check(session->rename(session, "table:old", "table:new", NULL)); /*! [Rename a table] */ /*! [Salvage a table] */ error_check(session->salvage(session, "table:mytable", NULL)); /*! [Salvage a table] */ /*! [Truncate a table] */ error_check(session->truncate( session, "table:mytable", NULL, NULL, NULL)); /*! [Truncate a table] */ /*! [Transaction sync] */ error_check(session->transaction_sync(session, NULL)); /*! [Transaction sync] */ /*! [Reset the session] */ error_check(session->reset(session)); /*! [Reset the session] */ { /* * Insert a pair of keys so we can truncate a range. */ WT_CURSOR *cursor; error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); cursor->set_key(cursor, "June01"); cursor->set_value(cursor, "value"); error_check(cursor->update(cursor)); cursor->set_key(cursor, "June30"); cursor->set_value(cursor, "value"); error_check(cursor->update(cursor)); error_check(cursor->close(cursor)); { /*! [Truncate a range] */ WT_CURSOR *start, *stop; error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &start)); start->set_key(start, "June01"); error_check(start->search(start)); error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &stop)); stop->set_key(stop, "June30"); error_check(stop->search(stop)); error_check(session->truncate(session, NULL, start, stop, NULL)); /*! [Truncate a range] */ error_check(stop->close(stop)); error_check(start->close(start)); } } /*! [Upgrade a table] */ error_check(session->upgrade(session, "table:mytable", NULL)); /*! [Upgrade a table] */ /*! [Verify a table] */ error_check(session->verify(session, "table:mytable", NULL)); /*! [Verify a table] */ /* * We can't call the backup function because it includes absolute paths * for documentation purposes that don't exist on test systems. That * said, we have to reference the function to avoid build warnings * about unused static code. */ (void)backup; /* Call other functions, where possible. */ checkpoint_ops(session); error_check(cursor_ops(session)); cursor_statistics(session); named_snapshot_ops(session); pack_ops(session); transaction_ops(session); /*! [Close a session] */ error_check(session->close(session, NULL)); /*! [Close a session] */ /* * We close the old session first to close all cursors, open a new one * for the drop. */ error_check(conn->open_session(conn, NULL, NULL, &session)); /*! [Drop a table] */ error_check(session->drop(session, "table:mytable", NULL)); /*! [Drop a table] */ } }
static int cursor_ops(WT_SESSION *session) { WT_CURSOR *cursor; int ret; /*! [Open a cursor] */ error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); /*! [Open a cursor] */ /*! [Open a cursor on the metadata] */ error_check(session->open_cursor( session, "metadata:", NULL, NULL, &cursor)); /*! [Open a cursor on the metadata] */ { const char *key = "some key", *value = "some value"; /*! [Reconfigure a cursor] */ error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite=false", &cursor)); /* Reconfigure the cursor to overwrite the record. */ error_check(cursor->reconfigure(cursor, "overwrite=true")); cursor->set_key(cursor, key); cursor->set_value(cursor, value); error_check(cursor->insert(cursor)); /*! [Reconfigure a cursor] */ } { WT_CURSOR *duplicate; const char *key = "some key"; /*! [Duplicate a cursor] */ error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); cursor->set_key(cursor, key); error_check(cursor->search(cursor)); /* Duplicate the cursor. */ error_check( session->open_cursor(session, NULL, cursor, NULL, &duplicate)); /*! [Duplicate a cursor] */ } { /*! [boolean configuration string example] */ error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite", &cursor)); error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite=true", &cursor)); error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite=1", &cursor)); /*! [boolean configuration string example] */ } error_check(session->checkpoint(session, "name=midnight")); { /*! [open a named checkpoint] */ error_check(session->open_cursor(session, "table:mytable", NULL, "checkpoint=midnight", &cursor)); /*! [open a named checkpoint] */ } { /*! [open the default checkpoint] */ error_check(session->open_cursor(session, "table:mytable", NULL, "checkpoint=WiredTigerCheckpoint", &cursor)); /*! [open the default checkpoint] */ } { /*! [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 string key] */ const char *key; /* Get the cursor's string key. */ error_check(cursor->get_key(cursor, &key)); /*! [Get the cursor's string key] */ } /* Switch to a recno table. */ error_check(session->create( session, "table:recno", "key_format=r,value_format=S")); error_check(session->open_cursor( session, "table:recno", NULL, NULL, &cursor)); { /*! [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 record number key] */ uint64_t recno; /* Get the cursor's record number key. */ error_check(cursor->get_key(cursor, &recno)); /*! [Get the cursor's record number key] */ } /* Switch to a composite table. */ error_check(session->create( session, "table:composite", "key_format=SiH,value_format=S")); error_check(session->open_cursor( session, "table:recno", NULL, NULL, &cursor)); { /*! [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 composite key] */ /* Get the cursor's "SiH" format composite key. */ const char *first; int32_t second; uint16_t third; error_check(cursor->get_key(cursor, &first, &second, &third)); /*! [Get the cursor's composite key] */ } { /*! [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 string value] */ const char *value; /* Get the cursor's string value. */ error_check(cursor->get_value(cursor, &value)); /*! [Get the cursor's string value] */ } { /*! [Get the cursor's raw value] */ WT_ITEM value; /* Get the cursor's raw value. */ error_check(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] */ error_check(cursor->insert(cursor)); } /*! [Return the next record] */ error_check(cursor->next(cursor)); /*! [Return the next record] */ /*! [Reset the cursor] */ error_check(cursor->reset(cursor)); /*! [Reset the cursor] */ /*! [Return the previous record] */ error_check(cursor->prev(cursor)); /*! [Return the previous record] */ { WT_CURSOR *other = NULL; error_check( session->open_cursor(session, NULL, cursor, NULL, &other)); { /*! [Cursor comparison] */ int compare; error_check(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] */ } { /*! [Cursor equality] */ int equal; error_check(cursor->equals(cursor, other, &equal)); if (equal) { /* Cursors reference the same key */ } /*! [Cursor equality] */ } } { /*! [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"; error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); cursor->set_key(cursor, key); cursor->set_value(cursor, value); error_check(cursor->insert(cursor)); /*! [Insert a new record or overwrite an existing record] */ } { /*! [Search for an exact match] */ const char *key = "some key"; cursor->set_key(cursor, key); error_check(cursor->search(cursor)); /*! [Search for an exact match] */ } cursor_search_near(cursor); { /*! [Insert a new record and fail if the record exists] */ /* Insert a new record and fail if the record exists. */ const char *key = "new key", *value = "some value"; error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite=false", &cursor)); cursor->set_key(cursor, key); cursor->set_value(cursor, value); error_check(cursor->insert(cursor)); /*! [Insert a new record and fail if the record exists] */ } error_check(session->open_cursor( session, "table:recno", NULL, "append", &cursor)); { /*! [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"; cursor->set_value(cursor, value); error_check(cursor->insert(cursor)); error_check(cursor->get_key(cursor, &recno)); /*! [Insert a new record and assign a record number] */ } error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); { /*! [Reserve a record] */ const char *key = "some key"; error_check(session->begin_transaction(session, NULL)); cursor->set_key(cursor, key); error_check(cursor->reserve(cursor)); error_check(session->commit_transaction(session, NULL)); /*! [Reserve a record] */ } error_check(session->create( session, "table:blob", "key_format=S,value_format=u")); error_check(session->open_cursor( session, "table:blob", NULL, NULL, &cursor)); { WT_ITEM value; value.data = "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"; value.size = strlen(value.data); cursor->set_key(cursor, "some key"); cursor->set_value(cursor, &value); error_check(cursor->insert(cursor)); } /* Modify requires an explicit transaction. */ error_check(session->begin_transaction(session, NULL)); { /*! [Modify an existing record] */ WT_MODIFY entries[3]; const char *key = "some key"; /* Position the cursor. */ cursor->set_key(cursor, key); error_check(cursor->search(cursor)); /* Replace 20 bytes starting at byte offset 5. */ entries[0].data.data = "some data"; entries[0].data.size = strlen(entries[0].data.data); entries[0].offset = 5; entries[0].size = 20; /* Insert data at byte offset 40. */ entries[1].data.data = "and more data"; entries[1].data.size = strlen(entries[1].data.data); entries[1].offset = 40; entries[1].size = 0; /* Replace 2 bytes starting at byte offset 10. */ entries[2].data.data = "and more data"; entries[2].data.size = strlen(entries[2].data.data); entries[2].offset = 10; entries[2].size = 2; error_check(cursor->modify(cursor, entries, 3)); /*! [Modify an existing record] */ } error_check(session->commit_transaction(session, NULL)); { /*! [Update an existing record or insert a new record] */ const char *key = "some key", *value = "some value"; error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); cursor->set_key(cursor, key); cursor->set_value(cursor, value); error_check(cursor->update(cursor)); /*! [Update an existing record or insert a new record] */ } { /*! [Update an existing record and fail if DNE] */ const char *key = "some key", *value = "some value"; error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite=false", &cursor)); cursor->set_key(cursor, key); cursor->set_value(cursor, value); error_check(cursor->update(cursor)); /*! [Update an existing record and fail if DNE] */ } { /*! [Remove a record and fail if DNE] */ const char *key = "some key"; error_check(session->open_cursor( session, "table:mytable", NULL, "overwrite=false", &cursor)); cursor->set_key(cursor, key); error_check(cursor->remove(cursor)); /*! [Remove a record and fail if DNE] */ } { /*! [Remove a record] */ const char *key = "some key"; error_check(session->open_cursor( session, "table:mytable", NULL, NULL, &cursor)); cursor->set_key(cursor, key); error_check(cursor->remove(cursor)); /*! [Remove a record] */ } { /*! [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", wiredtiger_strerror(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", cursor->session->strerror(cursor->session, ret)); return (ret); } /*! [Display an error thread safe] */ } /*! [Close the cursor] */ error_check(cursor->close(cursor)); /*! [Close the cursor] */ return (0); }
void wts_load(void) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_ITEM key, value; WT_SESSION *session; uint8_t *keybuf, *valbuf; int is_bulk, ret; conn = g.wts_conn; if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); if (g.logging != 0) (void)g.wt_api->msg_printf(g.wt_api, session, "=============== bulk load start ==============="); /* * Avoid bulk load with KVS (there's no bulk load support for a * data-source); avoid bulk load with a custom collator, because * the order of insertion will not match the collation order. */ is_bulk = !g.c_reverse && !DATASOURCE("kvsbdb") && !DATASOURCE("helium"); if ((ret = session->open_cursor(session, g.uri, NULL, is_bulk ? "bulk" : NULL, &cursor)) != 0) die(ret, "session.open_cursor"); /* Set up the default key buffer. */ key_gen_setup(&keybuf); val_gen_setup(&valbuf); for (;;) { if (++g.key_cnt > g.c_rows) { g.key_cnt = g.rows = g.c_rows; break; } /* Report on progress every 100 inserts. */ if (g.key_cnt % 100 == 0) track("bulk load", g.key_cnt, NULL); key_gen(keybuf, &key.size, (uint64_t)g.key_cnt, 0); key.data = keybuf; value_gen(valbuf, &value.size, (uint64_t)g.key_cnt); value.data = valbuf; switch (g.type) { case FIX: if (!is_bulk) cursor->set_key(cursor, g.key_cnt); cursor->set_value(cursor, *(uint8_t *)value.data); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu32 " {0x%02" PRIx8 "}", "bulk V", g.key_cnt, ((uint8_t *)value.data)[0]); break; case VAR: if (!is_bulk) cursor->set_key(cursor, g.key_cnt); cursor->set_value(cursor, &value); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu32 " {%.*s}", "bulk V", g.key_cnt, (int)value.size, (char *)value.data); break; case ROW: cursor->set_key(cursor, &key); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu32 " {%.*s}", "bulk K", g.key_cnt, (int)key.size, (char *)key.data); cursor->set_value(cursor, &value); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu32 " {%.*s}", "bulk V", g.key_cnt, (int)value.size, (char *)value.data); break; } if ((ret = cursor->insert(cursor)) != 0) die(ret, "cursor.insert"); if (!SINGLETHREADED) continue; /* Insert the item into BDB. */ bdb_insert(key.data, key.size, value.data, value.size); } if ((ret = cursor->close(cursor)) != 0) die(ret, "cursor.close"); if (g.logging != 0) (void)g.wt_api->msg_printf(g.wt_api, session, "=============== bulk load stop ==============="); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); free(keybuf); free(valbuf); }
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 } }; ret = wiredtiger_open(home, NULL, "create", &conn); if (ret != 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); }
int populate(CONFIG *cfg) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; char *data_buf, *key_buf; double secs; int ret; struct timeval e; conn = cfg->conn; cfg->phase = LSM_TEST_PERF_POP; if (cfg->verbose > 0) fprintf(cfg->logf, "Starting bulk load\n"); data_buf = calloc(cfg->data_sz, 1); if (data_buf == NULL) return (ENOMEM); key_buf = calloc(cfg->key_sz, 1); if (key_buf == NULL) return (ENOMEM); /* 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", cfg->home, wiredtiger_strerror(ret)); return (ret); } if ((ret = session->create( session, cfg->uri, cfg->table_config)) != 0) { fprintf(stderr, "Error creating table %s: %s\n", cfg->uri, wiredtiger_strerror(ret)); return (ret); } if ((ret = session->open_cursor( session, cfg->uri, NULL, "bulk", &cursor)) != 0) { fprintf(stderr, "Error opening cursor %s: %s\n", cfg->uri, wiredtiger_strerror(ret)); return (ret); } memset(data_buf, 'a', cfg->data_sz - 1); cursor->set_value(cursor, data_buf); /* Populate the database. */ gettimeofday(&cfg->phase_start_time, NULL); for (nops = 0; nops < cfg->icount; nops++) { if (cfg->verbose > 0) { if (nops % 1000000 == 0) printf("."); if (nops % 50000000 == 0) printf("\n"); } sprintf(key_buf, "%"PRIu64, nops); cursor->set_key(cursor, key_buf); if ((ret = cursor->insert(cursor)) != 0) { fprintf(stderr, "Failed inserting with: %d\n", ret); return (ret); } } gettimeofday(&e, NULL); cursor->close(cursor); session->close(session, NULL); if (cfg->verbose > 0) { fprintf(cfg->logf, "Finished bulk load of %d items\n", cfg->icount); secs = e.tv_sec + e.tv_usec / 1000000.0; secs -= (cfg->phase_start_time.tv_sec + cfg->phase_start_time.tv_usec / 1000000.0); if (secs == 0) ++secs; fprintf(cfg->logf, "Load time: %.2f\n" "load ops/sec: %.2f\n", secs, cfg->icount / secs); } free(data_buf); free(key_buf); return (ret); }
/* * build -- * Build a row- or column-store page in a file. */ void build(int ikey, int ivalue, int cnt) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_ITEM key, value; WT_SESSION *session; char config[256], kbuf[64], vbuf[64]; int new_slvg; assert(wiredtiger_open(NULL, NULL, "create", &conn) == 0); assert(conn->open_session(conn, NULL, NULL, &session) == 0); assert(session->drop(session, "file:" LOAD, "force") == 0); switch (page_type) { case WT_PAGE_COL_FIX: (void)snprintf(config, sizeof(config), "key_format=r,value_format=7t," "allocation_size=%d," "internal_page_max=%d,internal_item_max=%d," "leaf_page_max=%d,leaf_item_max=%d", PSIZE, PSIZE, OSIZE, PSIZE, OSIZE); break; case WT_PAGE_COL_VAR: (void)snprintf(config, sizeof(config), "key_format=r," "allocation_size=%d," "internal_page_max=%d,internal_item_max=%d," "leaf_page_max=%d,leaf_item_max=%d", PSIZE, PSIZE, OSIZE, PSIZE, OSIZE); break; case WT_PAGE_ROW_LEAF: (void)snprintf(config, sizeof(config), "key_format=u," "allocation_size=%d," "internal_page_max=%d,internal_item_max=%d," "leaf_page_max=%d,leaf_item_max=%d", PSIZE, PSIZE, OSIZE, PSIZE, OSIZE); break; default: assert(0); } assert(session->create(session, "file:" LOAD, config) == 0); assert(session->open_cursor( session, "file:" LOAD, NULL, "bulk", &cursor) == 0); for (; cnt > 0; --cnt, ++ikey, ++ivalue) { switch (page_type) { /* Build the key. */ case WT_PAGE_COL_FIX: case WT_PAGE_COL_VAR: break; case WT_PAGE_ROW_LEAF: snprintf(kbuf, sizeof(kbuf), "%010d KEY------", ikey); key.data = kbuf; key.size = 20; cursor->set_key(cursor, &key); break; } switch (page_type) { /* Build the value. */ case WT_PAGE_COL_FIX: cursor->set_value(cursor, ivalue & 0x7f); break; case WT_PAGE_COL_VAR: case WT_PAGE_ROW_LEAF: snprintf(vbuf, sizeof(vbuf), "%010d VALUE----", value_unique ? ivalue : 37); value.data = vbuf; value.size = 20; cursor->set_value(cursor, &value); } assert(cursor->insert(cursor) == 0); } /* * The first time through this routine we put a matching configuration * in for the salvage file. */ new_slvg = (access(SLVG, F_OK) != 0); if (new_slvg) { assert(session->drop(session, "file:" SLVG, "force") == 0); assert(session->create(session, "file:" SLVG, config) == 0); } assert(conn->close(conn, 0) == 0); /* * We created the salvage file above, but all we want is the schema, * we're creating the salvage file by hand. */ if (new_slvg) (void)remove(SLVG); }
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); }
int main(int argc, char *argv[]) { TEST_OPTS *opts, _opts; WT_CURSOR *c; WT_SESSION *session; clock_t ce, cs; pthread_t id[100]; uint64_t current_value; int i; opts = &_opts; if (testutil_disable_long_tests()) return (0); memset(opts, 0, sizeof(*opts)); opts->nthreads = 10; opts->nrecords = 1000; opts->table_type = TABLE_ROW; testutil_check(testutil_parse_opts(argc, argv, opts)); testutil_make_work_dir(opts->home); testutil_check(wiredtiger_open(opts->home, NULL, "create," "cache_size=2G," "eviction=(threads_max=5)," "statistics=(fast)", &opts->conn)); testutil_check( opts->conn->open_session(opts->conn, NULL, NULL, &session)); testutil_check(session->create(session, opts->uri, "key_format=Q,value_format=Q," "leaf_page_max=32k,")); /* Create the single record. */ testutil_check( session->open_cursor(session, opts->uri, NULL, NULL, &c)); c->set_key(c, 1); c->set_value(c, 0); testutil_check(c->insert(c)); testutil_check(c->close(c)); cs = clock(); for (i = 0; i < (int)opts->nthreads; ++i) { testutil_check(pthread_create( &id[i], NULL, thread_insert_race, (void *)opts)); } while (--i >= 0) testutil_check(pthread_join(id[i], NULL)); testutil_check( session->open_cursor(session, opts->uri, NULL, NULL, &c)); c->set_key(c, 1); testutil_check(c->search(c)); testutil_check(c->get_value(c, ¤t_value)); if (current_value != opts->nthreads * opts->nrecords) { fprintf(stderr, "ERROR: didn't get expected number of changes\n"); fprintf(stderr, "got: %" PRIu64 ", expected: %" PRIu64 "\n", current_value, opts->nthreads * opts->nrecords); return (EXIT_FAILURE); } testutil_check(session->close(session, NULL)); ce = clock(); printf("%" PRIu64 ": %.2lf\n", opts->nrecords, (ce - cs) / (double)CLOCKS_PER_SEC); testutil_cleanup(opts); return (EXIT_SUCCESS); }
int main(void) { int ret; WT_CONNECTION *conn; WT_SESSION *session; WT_CURSOR *cursor; POP_RECORD *p, *endp; const char *country; uint64_t recno; uint16_t year; ret = wiredtiger_open(home, NULL, "create", &conn); if (ret != 0) fprintf(stderr, "Error connecting to %s: %s\n", home, wiredtiger_strerror(ret)); /* Note: error checking omitted for clarity. */ /*! [schema work] */ ret = conn->open_session(conn, NULL, NULL, &session); /* * Create the population table. * Keys are record numbers, the format for values is * (5-byte string, short, long). * See ::wiredtiger_struct_pack for details of the format strings. * * If this program is run multiple times so the table already exists, * this call will verify that the table exists. It is not required in * that case, but is a safety check that the schema matches what the * program expects. */ ret = session->create(session, "table:population", "key_format=r," "value_format=5sHQ," "columns=(id,country,year,population)," "colgroups=(main,population)"); /* Create the column groups to store population in its own file. */ ret = session->create(session, "colgroup:population:main", "columns=(country,year)"); ret = session->create(session, "colgroup:population:population", "columns=(population)"); /* Create an index with composite key (country,year). */ ret = session->create(session, "index:population:country_year", "columns=(country,year)"); ret = session->open_cursor(session, "table:population", NULL, "append", &cursor); endp = pop_data + (sizeof (pop_data) / sizeof(pop_data[0])); for (p = pop_data; p < endp; p++) { cursor->set_value(cursor, p->country, p->year, p->population); ret = cursor->insert(cursor); } ret = cursor->close(cursor); /* Now just read through the countries we know about */ ret = session->open_cursor(session, "index:population:country_year(id)", NULL, NULL, &cursor); while ((ret = cursor->next(cursor)) == 0) { cursor->get_key(cursor, &country, &year); cursor->get_value(cursor, &recno); printf("Got country %s : row ID %d\n", country, (int)recno); } ret = conn->close(conn, NULL); /*! [schema work] */ return (ret); }
/* * build -- * Build a row- or column-store page in a file. */ void build(int ikey, int ivalue, int cnt) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_ITEM key, value; WT_SESSION *session; char config[256], kbuf[64], vbuf[64]; int new_slvg; /* * Disable logging: we're modifying files directly, we don't want to * run recovery. */ CHECK(wiredtiger_open( NULL, NULL, "create,log=(enabled=false)", &conn) == 0); CHECK(conn->open_session(conn, NULL, NULL, &session) == 0); CHECK(session->drop(session, "file:" LOAD, "force") == 0); switch (page_type) { case WT_PAGE_COL_FIX: (void)snprintf(config, sizeof(config), "key_format=r,value_format=7t," "allocation_size=%d," "internal_page_max=%d,internal_item_max=%d," "leaf_page_max=%d,leaf_item_max=%d", PSIZE, PSIZE, OSIZE, PSIZE, OSIZE); break; case WT_PAGE_COL_VAR: (void)snprintf(config, sizeof(config), "key_format=r," "allocation_size=%d," "internal_page_max=%d,internal_item_max=%d," "leaf_page_max=%d,leaf_item_max=%d", PSIZE, PSIZE, OSIZE, PSIZE, OSIZE); break; case WT_PAGE_ROW_LEAF: (void)snprintf(config, sizeof(config), "key_format=u," "allocation_size=%d," "internal_page_max=%d,internal_item_max=%d," "leaf_page_max=%d,leaf_item_max=%d", PSIZE, PSIZE, OSIZE, PSIZE, OSIZE); break; default: assert(0); } CHECK(session->create(session, "file:" LOAD, config) == 0); CHECK(session->open_cursor( session, "file:" LOAD, NULL, "bulk,append", &cursor) == 0); for (; cnt > 0; --cnt, ++ikey, ++ivalue) { switch (page_type) { /* Build the key. */ case WT_PAGE_COL_FIX: case WT_PAGE_COL_VAR: break; case WT_PAGE_ROW_LEAF: snprintf(kbuf, sizeof(kbuf), "%010d KEY------", ikey); key.data = kbuf; key.size = 20; cursor->set_key(cursor, &key); break; } switch (page_type) { /* Build the value. */ case WT_PAGE_COL_FIX: cursor->set_value(cursor, ivalue & 0x7f); break; case WT_PAGE_COL_VAR: case WT_PAGE_ROW_LEAF: snprintf(vbuf, sizeof(vbuf), "%010d VALUE----", value_unique ? ivalue : 37); value.data = vbuf; value.size = 20; cursor->set_value(cursor, &value); } CHECK(cursor->insert(cursor) == 0); } /* * The first time through this routine we create the salvage file and * then remove it (all we want is the appropriate schema entry, we're * creating the salvage file itself by hand). */ new_slvg = !file_exists(SLVG); if (new_slvg) { CHECK(session->drop(session, "file:" SLVG, "force") == 0); CHECK(session->create(session, "file:" SLVG, config) == 0); } CHECK(conn->close(conn, 0) == 0); if (new_slvg) (void)remove(SLVG); }
void worker(CONFIG *cfg, uint32_t worker_type) { WT_CONNECTION *conn; WT_SESSION *session; WT_CURSOR *cursor; const char *op_name = "search"; char *data_buf, *key_buf, *value; int ret, op_ret; uint64_t next_incr, next_val; session = NULL; data_buf = key_buf = NULL; op_ret = 0; conn = cfg->conn; key_buf = calloc(cfg->key_sz + 1, 1); if (key_buf == NULL) { lprintf(cfg, ret = ENOMEM, 0, "Populate key buffer"); goto err; } if (worker_type == WORKER_INSERT || worker_type == WORKER_UPDATE) { data_buf = calloc(cfg->data_sz, 1); if (data_buf == NULL) { lprintf(cfg, ret = ENOMEM, 0, "Populate data buffer"); goto err; } memset(data_buf, 'a', cfg->data_sz - 1); } if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { lprintf(cfg, ret, 0, "open_session failed in read thread"); goto err; } if ((ret = session->open_cursor(session, cfg->uri, NULL, NULL, &cursor)) != 0) { lprintf(cfg, ret, 0, "open_cursor failed in read thread"); goto err; } while (g_running) { /* Get a value in range, avoid zero. */ if (worker_type == WORKER_INSERT) next_incr = ATOMIC_ADD(g_nins_ops, 1); if (!F_ISSET(cfg, PERF_RAND_WORKLOAD) && worker_type == WORKER_INSERT) next_val = cfg->icount + next_incr; else next_val = wtperf_rand(cfg); /* * If the workload is started without a populate phase we * rely on at least one insert to get a valid item id. */ if (worker_type != WORKER_INSERT && wtperf_value_range(cfg) < next_val) continue; sprintf(key_buf, "%0*" PRIu64, cfg->key_sz, next_val); cursor->set_key(cursor, key_buf); switch(worker_type) { case WORKER_READ: op_name = "read"; op_ret = cursor->search(cursor); if (F_ISSET(cfg, PERF_RAND_WORKLOAD) && op_ret == WT_NOTFOUND) op_ret = 0; if (op_ret == 0) ++g_nread_ops; break; case WORKER_INSERT_RMW: op_name="insert_rmw"; op_ret = cursor->search(cursor); if (op_ret != WT_NOTFOUND) break; /* Fall through */ case WORKER_INSERT: op_name = "insert"; cursor->set_value(cursor, data_buf); op_ret = cursor->insert(cursor); if (F_ISSET(cfg, PERF_RAND_WORKLOAD) && op_ret == WT_DUPLICATE_KEY) op_ret = 0; if (op_ret != 0) ++g_nfailedins_ops; break; case WORKER_UPDATE: op_name = "update"; op_ret = cursor->search(cursor); if (op_ret == 0) { cursor->get_value(cursor, &value); memcpy(data_buf, value, cfg->data_sz); if (data_buf[0] == 'a') data_buf[0] = 'b'; else data_buf[0] = 'a'; cursor->set_value(cursor, data_buf); op_ret = cursor->update(cursor); } if (F_ISSET(cfg, PERF_RAND_WORKLOAD) && op_ret == WT_NOTFOUND) op_ret = 0; if (op_ret == 0) ++g_nupdate_ops; break; default: lprintf(cfg, EINVAL, 0, "Invalid worker type"); goto err; } /* Report errors and continue. */ if (op_ret != 0) lprintf(cfg, op_ret, 0, "%s failed for: %s", op_name, key_buf); else ++g_nworker_ops; } err: if (ret != 0) ++g_threads_quit; if (session != NULL) session->close(session, NULL); if (data_buf != NULL) free(data_buf); if (key_buf != NULL) free(key_buf); }
int main(int argc, char *argv[]) { TEST_OPTS *opts, _opts; WT_CURSOR *balancecur, *flagcur, *joincur, *postcur; WT_CURSOR *maincur; WT_SESSION *session; int balance, count, flag, key, key2, post, ret; char balanceuri[256]; char cfg[128]; char flaguri[256]; char joinuri[256]; char posturi[256]; const char *tablename; opts = &_opts; memset(opts, 0, sizeof(*opts)); testutil_check(testutil_parse_opts(argc, argv, opts)); testutil_make_work_dir(opts->home); testutil_progress(opts, "start"); testutil_check(wiredtiger_open(opts->home, NULL, "create,cache_size=250M", &opts->conn)); testutil_progress(opts, "wiredtiger_open"); testutil_check( opts->conn->open_session(opts->conn, NULL, NULL, &session)); testutil_progress(opts, "sessions opened"); /* * Note: repeated primary key 'id' as 'id2'. This makes * it easier to dump an index and know which record we're * looking at. */ testutil_check(session->create(session, opts->uri, "key_format=i,value_format=iiii," "columns=(id,post,balance,flag,id2)")); tablename = strchr(opts->uri, ':'); testutil_assert(tablename != NULL); tablename++; testutil_check(__wt_snprintf( posturi, sizeof(posturi), "index:%s:post", tablename)); testutil_check(__wt_snprintf( balanceuri, sizeof(balanceuri), "index:%s:balance", tablename)); testutil_check(__wt_snprintf( flaguri, sizeof(flaguri), "index:%s:flag", tablename)); testutil_check(__wt_snprintf( joinuri, sizeof(joinuri), "join:%s", opts->uri)); testutil_check(session->create(session, posturi, "columns=(post)")); testutil_check(session->create(session, balanceuri, "columns=(balance)")); testutil_check(session->create(session, flaguri, "columns=(flag)")); testutil_progress(opts, "setup complete"); /* * Insert a single record with all items we are search for, * this makes our logic easier. */ testutil_check(session->open_cursor(session, opts->uri, NULL, NULL, &maincur)); maincur->set_key(maincur, N_RECORDS); maincur->set_value(maincur, 54321, 0, "", 0, N_RECORDS); testutil_check(maincur->insert(maincur)); testutil_check(maincur->close(maincur)); testutil_check(session->close(session, NULL)); testutil_progress(opts, "populate start"); populate(opts); testutil_progress(opts, "populate end"); testutil_check(opts->conn->open_session( opts->conn, NULL, NULL, &session)); testutil_check(session->open_cursor(session, posturi, NULL, NULL, &postcur)); testutil_check(session->open_cursor(session, balanceuri, NULL, NULL, &balancecur)); testutil_check(session->open_cursor(session, flaguri, NULL, NULL, &flagcur)); testutil_check(session->open_cursor(session, joinuri, NULL, NULL, &joincur)); postcur->set_key(postcur, 54321); testutil_check(postcur->search(postcur)); testutil_check(session->join(session, joincur, postcur, "compare=eq")); balancecur->set_key(balancecur, 0); testutil_check(balancecur->search(balancecur)); testutil_check(__wt_snprintf(cfg, sizeof(cfg), "compare=lt,strategy=bloom,count=%d", N_RECORDS / 100)); testutil_check(session->join(session, joincur, balancecur, cfg)); flagcur->set_key(flagcur, 0); testutil_check(flagcur->search(flagcur)); testutil_check(__wt_snprintf(cfg, sizeof(cfg), "compare=eq,strategy=bloom,count=%d", N_RECORDS / 100)); testutil_check(session->join(session, joincur, flagcur, cfg)); /* Expect no values returned */ count = 0; while ((ret = joincur->next(joincur)) == 0) { /* * The values may already have been changed, but * print them for informational purposes. */ testutil_check(joincur->get_key(joincur, &key)); testutil_check(joincur->get_value(joincur, &post, &balance, &flag, &key2)); fprintf(stderr, "FAIL: " "key=%d/%d, postal_code=%d, balance=%d, flag=%d\n", key, key2, post, balance, flag); count++; } testutil_assert(ret == WT_NOTFOUND); testutil_assert(count == 0); testutil_progress(opts, "cleanup starting"); testutil_cleanup(opts); return (EXIT_SUCCESS); }
void * populate_thread(void *arg) { CONFIG *cfg; WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; char *data_buf, *key_buf; int ret; uint64_t op; cfg = (CONFIG *)arg; conn = cfg->conn; session = NULL; data_buf = key_buf = NULL; cfg->phase = WT_PERF_POP; data_buf = calloc(cfg->data_sz, 1); if (data_buf == NULL) { lprintf(cfg, ENOMEM, 0, "Populate data buffer"); goto err; } key_buf = calloc(cfg->key_sz + 1, 1); if (key_buf == NULL) { lprintf(cfg, ENOMEM, 0, "Populate key buffer"); goto err; } /* Open a session for the current thread's work. */ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { lprintf(cfg, ret, 0, "Error opening a session on %s", cfg->home); goto err; } /* Do a bulk load if populate is single-threaded. */ if ((ret = session->open_cursor( session, cfg->uri, NULL, cfg->populate_threads == 1 ? "bulk" : NULL, &cursor)) != 0) { lprintf(cfg, ret, 0, "Error opening cursor %s", cfg->uri); goto err; } memset(data_buf, 'a', cfg->data_sz - 1); cursor->set_value(cursor, data_buf); /* Populate the database. */ while (1) { get_next_op(&op); if (op > cfg->icount) break; sprintf(key_buf, "%0*" PRIu64, cfg->key_sz, op); cursor->set_key(cursor, key_buf); if ((ret = cursor->insert(cursor)) != 0) { lprintf(cfg, ret, 0, "Failed inserting"); goto err; } } /* To ensure managing thread knows if we exited early. */ err: if (ret != 0) ++g_threads_quit; if (session != NULL) session->close(session, NULL); if (data_buf) free(data_buf); if (key_buf) free(key_buf); return (arg); }
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] */ } { WT_CURSOR *overwrite_cursor; const char *key = "some key", *value = "some value"; /*! [Reconfigure a cursor] */ ret = session->open_cursor( session, "table:mytable", NULL, NULL, &cursor); cursor->set_key(cursor, key); /* Reconfigure the cursor to overwrite the record. */ ret = session->open_cursor( session, NULL, cursor, "overwrite", &overwrite_cursor); ret = cursor->close(cursor); overwrite_cursor->set_value(overwrite_cursor, value); ret = overwrite_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; 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] */ } { /*! [Search for an exact match] */ const char *key = "some key"; cursor->set_key(cursor, key); ret = cursor->search(cursor); /*! [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. */ 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", wiredtiger_strerror(ret)); return (ret); } /*! [Display an error] */ } /*! [Close the cursor] */ ret = cursor->close(cursor); /*! [Close the cursor] */ return (ret); }
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] */ { 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] */ } { WT_CURSOR *overwrite_cursor; const char *key = "some key", *value = "some value"; /*! [Reconfigure a cursor] */ ret = session->open_cursor( session, "table:mytable", NULL, NULL, &cursor); cursor->set_key(cursor, key); /* Reconfigure the cursor to overwrite the record. */ ret = session->open_cursor( session, NULL, cursor, "overwrite=true", &overwrite_cursor); ret = cursor->close(cursor); overwrite_cursor->set_value(overwrite_cursor, value); ret = overwrite_cursor->insert(cursor); /*! [Reconfigure a cursor] */ } { /*! [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] */ } { /*! [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] */ } { /*! [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] */ } { /*! [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 string key] */ /* Set the cursor's string key. */ const char *key = "another key"; cursor->set_key(cursor, key); /*! [Set the cursor's string 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] */ } { /*! [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] */ } { /*! [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] */ } { /*! [Search for an exact match] */ const char *key = "some key"; cursor->set_key(cursor, key); ret = cursor->search(cursor); /*! [Search for an exact match] */ } cursor_search_near(cursor); { /*! [Insert a new record] */ /* Insert a new record. */ const char *key = "some key", *value = "some value"; cursor->set_key(cursor, key); cursor->set_value(cursor, value); ret = cursor->insert(cursor); /*! [Insert a new record] */ } { const char *key = "some key", *value = "some value"; /*! [Insert a new record or overwrite an existing record] */ /* Insert a new record or overwrite an existing record. */ ret = session->open_cursor( session, "table:mytable", NULL, "overwrite", &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 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) recno = cursor->get_key(cursor, &recno); /*! [Insert a new record and assign a record number] */ } { /*! [Update an existing record] */ const char *key = "some key", *value = "some value"; cursor->set_key(cursor, key); cursor->set_value(cursor, value); ret = cursor->update(cursor); /*! [Update an existing record] */ } { /*! [Remove a record] */ const char *key = "some key"; cursor->set_key(cursor, key); ret = cursor->remove(cursor); /*! [Remove a record] */ } { /*! [Display an error] */ const char *key = "some key"; cursor->set_key(cursor, key); if ((ret = cursor->remove(cursor)) != 0) { fprintf(stderr, "cursor.remove: %s\n", wiredtiger_strerror(ret)); return (ret); } /*! [Display an error] */ } /*! [Close the cursor] */ ret = cursor->close(cursor); /*! [Close the cursor] */ return (ret); }
int util_write(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; uint64_t recno; int append, ch, overwrite, rkey, ret; const char *uri; char config[100]; append = overwrite = ret = 0; while ((ch = util_getopt(argc, argv, "ao")) != EOF) switch (ch) { case 'a': append = 1; break; case 'o': overwrite = 1; break; case '?': default: return (usage()); } argc -= util_optind; argv += util_optind; /* * The remaining arguments are a uri followed by a list of values (if * append is set), or key/value pairs (if append is not set). */ if (append) { if (argc < 2) return (usage()); } else if (argc < 3 || ((argc - 1) % 2 != 0)) return (usage()); if ((uri = util_name(*argv, "table", UTIL_FILE_OK | UTIL_TABLE_OK)) == NULL) return (1); /* Open the object. */ (void)snprintf(config, sizeof(config), "%s,%s", append ? "append=true" : "", overwrite ? "overwrite=true" : ""); if ((ret = session->open_cursor( session, uri, NULL, config, &cursor)) != 0) return (util_err(ret, "%s: session.open", uri)); /* * A simple search only makes sense if the key format is a string or a * record number, and the value format is a single string. */ if (strcmp(cursor->key_format, "r") != 0 && strcmp(cursor->key_format, "S") != 0) { fprintf(stderr, "%s: write command only possible when the key format is " "a record number or string\n", progname); return (1); } rkey = strcmp(cursor->key_format, "r") == 0 ? 1 : 0; if (strcmp(cursor->value_format, "S") != 0) { fprintf(stderr, "%s: write command only possible when the value format is " "a string\n", progname); return (1); } /* Run through the values or key/value pairs. */ while (*++argv != NULL) { if (!append) { if (rkey) { if (util_str2recno(*argv, &recno)) return (1); cursor->set_key(cursor, recno); } else cursor->set_key(cursor, *argv); ++argv; } cursor->set_value(cursor, *argv); if ((ret = cursor->insert(cursor)) != 0) return (util_cerr(uri, "search", ret)); } return (0); }
void wts_load(void) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_DECL_RET; WT_ITEM key, value; WT_SESSION *session; bool is_bulk; conn = g.wts_conn; testutil_check(conn->open_session(conn, NULL, NULL, &session)); if (g.logging != 0) (void)g.wt_api->msg_printf(g.wt_api, session, "=============== bulk load start ==============="); /* * No bulk load with data-sources. * * No bulk load with custom collators, the order of insertion will not * match the collation order. */ is_bulk = true; if (DATASOURCE("kvsbdb")) is_bulk = false; if (g.c_reverse) is_bulk = false; /* * open_cursor can return EBUSY if concurrent with a metadata * operation, retry in that case. */ while ((ret = session->open_cursor(session, g.uri, NULL, is_bulk ? "bulk,append" : NULL, &cursor)) == EBUSY) __wt_yield(); testutil_check(ret); /* Set up the key/value buffers. */ key_gen_init(&key); val_gen_init(&value); for (;;) { if (++g.key_cnt > g.c_rows) { g.key_cnt = g.rows = g.c_rows; break; } /* Report on progress every 100 inserts. */ if (g.key_cnt % 1000 == 0) track("bulk load", g.key_cnt, NULL); key_gen(&key, g.key_cnt); val_gen(NULL, &value, g.key_cnt); switch (g.type) { case FIX: if (!is_bulk) cursor->set_key(cursor, g.key_cnt); cursor->set_value(cursor, *(uint8_t *)value.data); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu64 " {0x%02" PRIx8 "}", "bulk V", g.key_cnt, ((uint8_t *)value.data)[0]); break; case VAR: if (!is_bulk) cursor->set_key(cursor, g.key_cnt); cursor->set_value(cursor, &value); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu64 " {%.*s}", "bulk V", g.key_cnt, (int)value.size, (char *)value.data); break; case ROW: cursor->set_key(cursor, &key); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu64 " {%.*s}", "bulk K", g.key_cnt, (int)key.size, (char *)key.data); cursor->set_value(cursor, &value); if (g.logging == LOG_OPS) (void)g.wt_api->msg_printf(g.wt_api, session, "%-10s %" PRIu64 " {%.*s}", "bulk V", g.key_cnt, (int)value.size, (char *)value.data); break; } /* * We don't want to size the cache to ensure the initial data * set can load in the in-memory case, guaranteeing the load * succeeds probably means future updates are also guaranteed * to succeed, which isn't what we want. If we run out of space * in the initial load, reset the row counter and continue. * * Decrease inserts, they can't be successful if we're at the * cache limit, and increase the delete percentage to get some * extra space once the run starts. */ if ((ret = cursor->insert(cursor)) != 0) { if (ret != WT_CACHE_FULL) testutil_die(ret, "cursor.insert"); g.rows = --g.key_cnt; g.c_rows = (uint32_t)g.key_cnt; if (g.c_insert_pct > 5) g.c_insert_pct = 5; if (g.c_delete_pct < 20) g.c_delete_pct += 20; break; } #ifdef HAVE_BERKELEY_DB if (SINGLETHREADED) bdb_insert(key.data, key.size, value.data, value.size); #endif } testutil_check(cursor->close(cursor)); if (g.logging != 0) (void)g.wt_api->msg_printf(g.wt_api, session, "=============== bulk load stop ==============="); testutil_check(session->close(session, NULL)); key_gen_teardown(&key); val_gen_teardown(&value); }