/* * __wt_metadata_read -- * Reads and copies a row from the metadata. * The caller is responsible for freeing the allocated memory. */ int __wt_metadata_read( WT_SESSION_IMPL *session, const char *key, const char **valuep) { WT_CURSOR *cursor; WT_DECL_RET; const char *value; *valuep = NULL; if (__metadata_turtle(key)) return (__wt_meta_turtle_read(session, key, valuep)); WT_RET(__wt_metadata_cursor(session, NULL, &cursor)); cursor->set_key(cursor, key); WT_ERR(cursor->search(cursor)); WT_ERR(cursor->get_value(cursor, &value)); WT_ERR(__wt_strdup(session, value, valuep)); err: WT_TRET(cursor->close(cursor)); return (ret); }
StatusWith<std::string> WiredTigerUtil::getMetadata(OperationContext* opCtx, StringData uri) { invariant(opCtx); WiredTigerCursor curwrap("metadata:create", WiredTigerSession::kMetadataTableId, false, opCtx); WT_CURSOR* cursor = curwrap.get(); invariant(cursor); std::string strUri = uri.toString(); cursor->set_key(cursor, strUri.c_str()); int ret = cursor->search(cursor); if (ret == WT_NOTFOUND) { return StatusWith<std::string>(ErrorCodes::NoSuchKey, str::stream() << "Unable to find metadata for " << uri); } else if (ret != 0) { return StatusWith<std::string>(wtRCToStatus(ret)); } const char* metadata = NULL; ret = cursor->get_value(cursor, &metadata); if (ret != 0) { return StatusWith<std::string>(wtRCToStatus(ret)); } invariant(metadata); return StatusWith<std::string>(metadata); }
// static StatusWith<uint64_t> WiredTigerUtil::getStatisticsValue(WT_SESSION* session, const std::string& uri, const std::string& config, int statisticsKey) { invariant(session); WT_CURSOR* cursor = NULL; const char* cursorConfig = config.empty() ? NULL : config.c_str(); int ret = session->open_cursor(session, uri.c_str(), NULL, cursorConfig, &cursor); if (ret != 0) { return StatusWith<uint64_t>(ErrorCodes::CursorNotFound, str::stream() << "unable to open cursor at URI " << uri << ". reason: " << wiredtiger_strerror(ret)); } invariant(cursor); ON_BLOCK_EXIT(cursor->close, cursor); cursor->set_key(cursor, statisticsKey); ret = cursor->search(cursor); if (ret != 0) { return StatusWith<uint64_t>( ErrorCodes::NoSuchKey, str::stream() << "unable to find key " << statisticsKey << " at URI " << uri << ". reason: " << wiredtiger_strerror(ret)); } uint64_t value; ret = cursor->get_value(cursor, NULL, NULL, &value); if (ret != 0) { return StatusWith<uint64_t>( ErrorCodes::BadValue, str::stream() << "unable to get value for key " << statisticsKey << " at URI " << uri << ". reason: " << wiredtiger_strerror(ret)); } return StatusWith<uint64_t>(value); }
int print_overflow_pages(WT_SESSION *session) { /*! [statistics retrieve by key] */ WT_CURSOR *cursor; const char *desc, *pvalue; uint64_t value; int ret; if ((ret = session->open_cursor(session, "statistics:table:access", NULL, NULL, &cursor)) != 0) return (ret); cursor->set_key(cursor, WT_STAT_DSRC_BTREE_OVERFLOW); ret = cursor->search(cursor); ret = cursor->get_value(cursor, &desc, &pvalue, &value); printf("%s=%s\n", desc, pvalue); ret = cursor->close(cursor); /*! [statistics retrieve by key] */ return (ret); }
StatusWith<std::string> WiredTigerUtil::getMetadataRaw(WT_SESSION* session, StringData uri) { WT_CURSOR* cursor; invariantWTOK(session->open_cursor(session, "metadata:create", nullptr, "", &cursor)); invariant(cursor); ON_BLOCK_EXIT([cursor] { invariantWTOK(cursor->close(cursor)); }); std::string strUri = uri.toString(); cursor->set_key(cursor, strUri.c_str()); int ret = cursor->search(cursor); if (ret == WT_NOTFOUND) { return StatusWith<std::string>(ErrorCodes::NoSuchKey, str::stream() << "Unable to find metadata for " << uri); } else if (ret != 0) { return StatusWith<std::string>(wtRCToStatus(ret)); } const char* metadata = NULL; ret = cursor->get_value(cursor, &metadata); if (ret != 0) { return StatusWith<std::string>(wtRCToStatus(ret)); } invariant(metadata); return StatusWith<std::string>(metadata); }
void indexSearch(size_t indexId, fstring key, valvec<llong>* recIdvec) override { assert(started == m_status); assert(indexId < m_indices.size()); WT_ITEM item; WT_SESSION* ses = m_session.ses; const Schema& schema = m_sconf.getIndexSchema(indexId); WT_CURSOR* cur = m_indices[indexId].insert; WtWritableIndex::setKeyVal(schema, cur, key, 0, &item, &m_wrtBuf); recIdvec->erase_all(); if (schema.m_isUnique) { int err = cur->search(cur); BOOST_SCOPE_EXIT(cur) { cur->reset(cur); } BOOST_SCOPE_EXIT_END; if (WT_NOTFOUND == err) { return; } if (err) { THROW_STD(invalid_argument , "ERROR: wiredtiger search: %s", ses->strerror(ses, err)); } llong recId = 0; cur->get_value(cur, &recId); recIdvec->push_back(recId); }
void WiredTigerSizeStorer::loadFrom( WiredTigerSession* session, const std::string& uri ) { _checkMagic(); Map m; { WT_SESSION* s = session->getSession(); WT_CURSOR* c = NULL; int ret = s->open_cursor( s, uri.c_str(), NULL, NULL, &c ); if ( ret == ENOENT ) { // doesn't exist, we'll create later return; } invariantWTOK( ret ); while ( c->next(c) == 0 ) { WT_ITEM key; WT_ITEM value; invariantWTOK( c->get_key(c, &key ) ); invariantWTOK( c->get_value(c, &value ) ); std::string uriKey( reinterpret_cast<const char*>( key.data ), key.size ); BSONObj data( reinterpret_cast<const char*>( value.data ) ); LOG(2) << "WiredTigerSizeStorer::loadFrom " << uriKey << " -> " << data; Entry& e = m[uriKey]; e.numRecords = data["numRecords"].safeNumberLong(); e.dataSize = data["dataSize"].safeNumberLong(); e.dirty = false; e.rs = NULL; } invariantWTOK( c->close(c) ); } boost::mutex::scoped_lock lk( _entriesMutex ); _entries = m; }
/* * __wt_metadata_search -- * Return a copied row from the metadata. * The caller is responsible for freeing the allocated memory. */ int __wt_metadata_search(WT_SESSION_IMPL *session, const char *key, char **valuep) { WT_CURSOR *cursor; WT_DECL_RET; const char *value; *valuep = NULL; WT_RET(__wt_verbose(session, WT_VERB_METADATA, "Search: key: %s, tracking: %s, %s" "turtle", key, WT_META_TRACKING(session) ? "true" : "false", __metadata_turtle(key) ? "" : "not ")); if (__metadata_turtle(key)) return (__wt_turtle_read(session, key, valuep)); /* * All metadata reads are at read-uncommitted isolation. That's * because once a schema-level operation completes, subsequent * operations must see the current version of checkpoint metadata, or * they may try to read blocks that may have been freed from a file. * Metadata updates use non-transactional techniques (such as the * schema and metadata locks) to protect access to in-flight updates. */ WT_RET(__wt_metadata_cursor(session, &cursor)); cursor->set_key(cursor, key); WT_WITH_TXN_ISOLATION(session, WT_ISO_READ_UNCOMMITTED, ret = cursor->search(cursor)); WT_ERR(ret); WT_ERR(cursor->get_value(cursor, &value)); WT_ERR(__wt_strdup(session, value, valuep)); err: WT_TRET(__wt_metadata_cursor_release(session, &cursor)); return (ret); }
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); }
int64_t WiredTigerRecordStore::cappedDeleteAsNeeded_inlock(OperationContext* txn, const RecordId& justInserted) { // we do this is a side transaction in case it aborts WiredTigerRecoveryUnit* realRecoveryUnit = checked_cast<WiredTigerRecoveryUnit*>(txn->releaseRecoveryUnit()); invariant(realRecoveryUnit); WiredTigerSessionCache* sc = realRecoveryUnit->getSessionCache(); OperationContext::RecoveryUnitState const realRUstate = txn->setRecoveryUnit(new WiredTigerRecoveryUnit(sc), OperationContext::kNotInUnitOfWork); WiredTigerRecoveryUnit::get(txn)->markNoTicketRequired(); // realRecoveryUnit already has WT_SESSION* session = WiredTigerRecoveryUnit::get(txn)->getSession(txn)->getSession(); int64_t dataSize = _dataSize.load(); int64_t numRecords = _numRecords.load(); int64_t sizeOverCap = (dataSize > _cappedMaxSize) ? dataSize - _cappedMaxSize : 0; int64_t sizeSaved = 0; int64_t docsOverCap = 0, docsRemoved = 0; if (_cappedMaxDocs != -1 && numRecords > _cappedMaxDocs) docsOverCap = numRecords - _cappedMaxDocs; try { WriteUnitOfWork wuow(txn); WiredTigerCursor curwrap(_uri, _tableId, true, txn); WT_CURSOR* c = curwrap.get(); RecordId newestOld; int ret = 0; while ((sizeSaved < sizeOverCap || docsRemoved < docsOverCap) && (docsRemoved < 20000) && (ret = WT_OP_CHECK(c->next(c))) == 0) { int64_t key; ret = c->get_key(c, &key); invariantWTOK(ret); // don't go past the record we just inserted newestOld = _fromKey(key); if (newestOld >= justInserted) // TODO: use oldest uncommitted instead break; if (_shuttingDown) break; WT_ITEM old_value; invariantWTOK(c->get_value(c, &old_value)); ++docsRemoved; sizeSaved += old_value.size; if (_cappedDeleteCallback) { uassertStatusOK(_cappedDeleteCallback->aboutToDeleteCapped( txn, newestOld, RecordData(static_cast<const char*>(old_value.data), old_value.size))); } } if (ret != WT_NOTFOUND) { invariantWTOK(ret); } if (docsRemoved > 0) { // if we scanned to the end of the collection or past our insert, go back one if (ret == WT_NOTFOUND || newestOld >= justInserted) { ret = WT_OP_CHECK(c->prev(c)); } invariantWTOK(ret); WiredTigerCursor startWrap(_uri, _tableId, true, txn); WT_CURSOR* start = startWrap.get(); ret = WT_OP_CHECK(start->next(start)); invariantWTOK(ret); ret = session->truncate(session, NULL, start, c, NULL); if (ret == ENOENT || ret == WT_NOTFOUND) { // TODO we should remove this case once SERVER-17141 is resolved log() << "Soft failure truncating capped collection. Will try again later."; docsRemoved = 0; } else { invariantWTOK(ret); _changeNumRecords(txn, -docsRemoved); _increaseDataSize(txn, -sizeSaved); wuow.commit(); } } } catch (const WriteConflictException& wce) { delete txn->releaseRecoveryUnit(); txn->setRecoveryUnit(realRecoveryUnit, realRUstate); log() << "got conflict truncating capped, ignoring"; return 0; } catch (...) { delete txn->releaseRecoveryUnit(); txn->setRecoveryUnit(realRecoveryUnit, realRUstate); throw; } delete txn->releaseRecoveryUnit(); txn->setRecoveryUnit(realRecoveryUnit, realRUstate); return docsRemoved; }
/* * __schema_open_index -- * Open one or more indices for a table (internal version). */ static int __schema_open_index(WT_SESSION_IMPL *session, WT_TABLE *table, const char *idxname, size_t len, WT_INDEX **indexp) { WT_CURSOR *cursor; WT_DECL_ITEM(tmp); WT_DECL_RET; WT_INDEX *idx; u_int i; int cmp; bool match; const char *idxconf, *name, *tablename, *uri; /* Check if we've already done the work. */ if (idxname == NULL && table->idx_complete) return (0); cursor = NULL; idx = NULL; match = false; /* Build a search key. */ tablename = table->name; (void)WT_PREFIX_SKIP(tablename, "table:"); WT_ERR(__wt_scr_alloc(session, 512, &tmp)); WT_ERR(__wt_buf_fmt(session, tmp, "index:%s:", tablename)); /* Find matching indices. */ WT_ERR(__wt_metadata_cursor(session, &cursor)); cursor->set_key(cursor, tmp->data); if ((ret = cursor->search_near(cursor, &cmp)) == 0 && cmp < 0) ret = cursor->next(cursor); for (i = 0; ret == 0; i++, ret = cursor->next(cursor)) { WT_ERR(cursor->get_key(cursor, &uri)); name = uri; if (!WT_PREFIX_SKIP(name, tmp->data)) break; /* Is this the index we are looking for? */ match = idxname == NULL || WT_STRING_MATCH(name, idxname, len); /* * Ensure there is space, including if we have to make room for * a new entry in the middle of the list. */ WT_ERR(__wt_realloc_def(session, &table->idx_alloc, WT_MAX(i, table->nindices) + 1, &table->indices)); /* Keep the in-memory list in sync with the metadata. */ cmp = 0; while (table->indices[i] != NULL && (cmp = strcmp(uri, table->indices[i]->name)) > 0) { /* Index no longer exists, remove it. */ __wt_free(session, table->indices[i]); memmove(&table->indices[i], &table->indices[i + 1], (table->nindices - i) * sizeof(WT_INDEX *)); table->indices[--table->nindices] = NULL; } if (cmp < 0) { /* Make room for a new index. */ memmove(&table->indices[i + 1], &table->indices[i], (table->nindices - i) * sizeof(WT_INDEX *)); table->indices[i] = NULL; ++table->nindices; } if (!match) continue; if (table->indices[i] == NULL) { WT_ERR(cursor->get_value(cursor, &idxconf)); WT_ERR(__wt_calloc_one(session, &idx)); WT_ERR(__wt_strdup(session, uri, &idx->name)); WT_ERR(__wt_strdup(session, idxconf, &idx->config)); WT_ERR(__open_index(session, table, idx)); /* * If we're checking the creation of an index before a * table is fully created, don't save the index: it * will need to be reopened once the table is complete. */ if (!table->cg_complete) { WT_ERR( __wt_schema_destroy_index(session, &idx)); if (idxname != NULL) break; continue; } table->indices[i] = idx; idx = NULL; /* * If the slot is bigger than anything else we've seen, * bump the number of indices. */ if (i >= table->nindices) table->nindices = i + 1; } /* If we were looking for a single index, we're done. */ if (indexp != NULL) *indexp = table->indices[i]; if (idxname != NULL) break; } WT_ERR_NOTFOUND_OK(ret); if (idxname != NULL && !match) ret = WT_NOTFOUND; /* If we did a full pass, we won't need to do it again. */ if (idxname == NULL) { table->nindices = i; table->idx_complete = true; } err: WT_TRET(__wt_metadata_cursor_release(session, &cursor)); WT_TRET(__wt_schema_destroy_index(session, &idx)); __wt_scr_free(session, &tmp); return (ret); }
/* * wts_stats -- * Dump the run's statistics. */ void wts_stats(void) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; FILE *fp; char *stat_name; const char *pval, *desc; uint64_t v; int ret; track("stat", 0ULL, NULL); conn = g.wts_conn; if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); if ((fp = fopen("RUNDIR/stats", "w")) == NULL) die(errno, "fopen: RUNDIR/stats"); /* Connection statistics. */ fprintf(fp, "====== Connection statistics:\n"); if ((ret = session->open_cursor(session, "statistics:", NULL, NULL, &cursor)) != 0) die(ret, "session.open_cursor"); while ((ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pval, &v)) == 0) if (fprintf(fp, "%s=%s\n", desc, pval) < 0) die(errno, "fprintf"); if (ret != WT_NOTFOUND) die(ret, "cursor.next"); if ((ret = cursor->close(cursor)) != 0) die(ret, "cursor.close"); /* * XXX * WiredTiger only supports file object statistics. */ if (strcmp(g.c_data_source, "file") != 0) goto skip; /* File statistics. */ fprintf(fp, "\n\n====== File statistics:\n"); if ((stat_name = malloc(strlen("statistics:") + strlen(g.uri) + 1)) == NULL) syserr("malloc"); sprintf(stat_name, "statistics:%s", g.uri); if ((ret = session->open_cursor( session, stat_name, NULL, NULL, &cursor)) != 0) die(ret, "session.open_cursor"); free(stat_name); while ((ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pval, &v)) == 0) if (fprintf(fp, "%s=%s\n", desc, pval) < 0) die(errno, "fprintf"); if (ret != WT_NOTFOUND) die(ret, "cursor.next"); if ((ret = cursor->close(cursor)) != 0) die(ret, "cursor.close"); skip: if ((ret = fclose(fp)) != 0) die(ret, "fclose"); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); }
int util_read(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; uint64_t recno; int ch; bool rkey, rval; char *uri, *value; uri = NULL; while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* The remaining arguments are a uri followed by a list of keys. */ if (argc < 2) return (usage()); if ((uri = util_uri(session, *argv, "table")) == NULL) return (1); /* * Open the object; free allocated memory immediately to simplify * future error handling. */ if ((ret = session->open_cursor(session, uri, NULL, NULL, &cursor)) != 0) (void)util_err(session, ret, "%s: session.open_cursor", uri); free(uri); if (ret != 0) return (ret); /* * 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: read command only possible when the key format is " "a record number or string\n", progname); return (1); } rkey = strcmp(cursor->key_format, "r") == 0; if (strcmp(cursor->value_format, "S") != 0) { fprintf(stderr, "%s: read command only possible when the value format is " "a string\n", progname); return (1); } /* * Run through the keys, returning non-zero on error or if any requested * key isn't found. */ for (rval = false; *++argv != NULL;) { if (rkey) { if (util_str2recno(session, *argv, &recno)) return (1); cursor->set_key(cursor, recno); } else cursor->set_key(cursor, *argv); switch (ret = cursor->search(cursor)) { case 0: if ((ret = cursor->get_value(cursor, &value)) != 0) return (util_cerr(cursor, "get_value", ret)); if (printf("%s\n", value) < 0) return (util_err(session, EIO, NULL)); break; case WT_NOTFOUND: (void)util_err(session, 0, "%s: not found", *argv); rval = true; break; default: return (util_cerr(cursor, "search", ret)); } } return (rval ? 1 : 0); }
int util_stat(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; WT_DECL_RET; size_t urilen; int ch; bool objname_free; const char *config, *pval, *desc; char *objname, *uri; objname_free = false; objname = uri = NULL; config = NULL; while ((ch = __wt_getopt(progname, argc, argv, "af")) != EOF) switch (ch) { case 'a': /* * Historically, the -a option meant include all of the * statistics; because we are opening the database with * statistics=(all), that is now the default, allow the * option for compatibility. */ config = NULL; break; case 'f': config = "statistics=(fast)"; break; case '?': default: return (usage()); } argc -= __wt_optind; argv += __wt_optind; /* * If there are no arguments, the statistics cursor operates on the * connection, otherwise, the optional remaining argument is a file * or LSM name. */ switch (argc) { case 0: objname = (char *)""; break; case 1: if ((objname = util_name(session, *argv, "table")) == NULL) return (1); objname_free = true; break; default: return (usage()); } urilen = strlen("statistics:") + strlen(objname) + 1; if ((uri = calloc(urilen, 1)) == NULL) { fprintf(stderr, "%s: %s\n", progname, strerror(errno)); goto err; } snprintf(uri, urilen, "statistics:%s", objname); if ((ret = session->open_cursor(session, uri, NULL, config, &cursor)) != 0) { fprintf(stderr, "%s: cursor open(%s) failed: %s\n", progname, uri, session->strerror(session, ret)); goto err; } /* List the statistics. */ while ( (ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pval, NULL)) == 0) if (printf("%s=%s\n", desc, pval) < 0) { ret = errno; break; } if (ret == WT_NOTFOUND) ret = 0; if (ret != 0) { fprintf(stderr, "%s: cursor get(%s) failed: %s\n", progname, objname, session->strerror(session, ret)); goto err; } if (0) { err: ret = 1; } if (objname_free) free(objname); free(uri); 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); }
/* * __wt_schema_open_table -- * Open a named table. */ int __wt_schema_open_table(WT_SESSION_IMPL *session, const char *name, size_t namelen, WT_TABLE **tablep) { WT_CONFIG cparser; WT_CONFIG_ITEM ckey, cval; WT_CURSOR *cursor; WT_DECL_RET; WT_ITEM buf; WT_TABLE *table; const char *tconfig; char *tablename; cursor = NULL; table = NULL; WT_CLEAR(buf); WT_RET(__wt_buf_fmt(session, &buf, "table:%.*s", (int)namelen, name)); tablename = __wt_buf_steal(session, &buf, NULL); WT_ERR(__wt_metadata_cursor(session, NULL, &cursor)); cursor->set_key(cursor, tablename); WT_ERR(cursor->search(cursor)); WT_ERR(cursor->get_value(cursor, &tconfig)); WT_ERR(__wt_calloc_def(session, 1, &table)); table->name = tablename; tablename = NULL; WT_ERR(__wt_config_getones(session, tconfig, "columns", &cval)); WT_ERR(__wt_config_getones(session, tconfig, "key_format", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->key_format)); WT_ERR(__wt_config_getones(session, tconfig, "value_format", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->value_format)); WT_ERR(__wt_strdup(session, tconfig, &table->config)); /* Point to some items in the copy to save re-parsing. */ WT_ERR(__wt_config_getones(session, table->config, "columns", &table->colconf)); /* * Count the number of columns: tables are "simple" if the columns * are not named. */ WT_ERR(__wt_config_subinit(session, &cparser, &table->colconf)); table->is_simple = 1; while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0) table->is_simple = 0; if (ret != WT_NOTFOUND) goto err; /* Check that the columns match the key and value formats. */ if (!table->is_simple) WT_ERR(__wt_schema_colcheck(session, table->key_format, table->value_format, &table->colconf, &table->nkey_columns, NULL)); WT_ERR(__wt_config_getones(session, table->config, "colgroups", &table->cgconf)); /* Count the number of column groups. */ WT_ERR(__wt_config_subinit(session, &cparser, &table->cgconf)); table->ncolgroups = 0; while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0) ++table->ncolgroups; if (ret != WT_NOTFOUND) goto err; WT_ERR(__wt_calloc_def(session, WT_COLGROUPS(table), &table->cgroups)); WT_ERR(__wt_schema_open_colgroups(session, table)); *tablep = table; if (0) { err: if (table != NULL) __wt_schema_destroy_table(session, table); } if (cursor != NULL) WT_TRET(cursor->close(cursor)); __wt_free(session, tablename); return (ret); }
int util_stat(WT_SESSION *session, int argc, char *argv[]) { WT_CURSOR *cursor; uint64_t v; size_t urilen; int ch, objname_free, ret; const char *pval, *desc; char *objname, *uri; objname_free = 0; objname = uri = NULL; while ((ch = util_getopt(argc, argv, "")) != EOF) switch (ch) { case '?': default: return (usage()); } argc -= util_optind; argv += util_optind; /* * If there are no arguments, the statistics cursor operates on the * connection, otherwise, the optional remaining argument is a file * name. */ switch (argc) { case 0: objname = (char *)""; break; case 1: if ((objname = util_name(*argv, "file", UTIL_FILE_OK)) == NULL) return (1); objname_free = 1; break; default: return (usage()); } urilen = strlen("statistics:") + strlen(objname) + 1; if ((uri = calloc(urilen, 1)) == NULL) { fprintf(stderr, "%s: %s\n", progname, strerror(errno)); return (1); } snprintf(uri, urilen, "statistics:%s", objname); if ((ret = session->open_cursor( session, uri, NULL, NULL, &cursor)) != 0) { fprintf(stderr, "%s: cursor open(%s) failed: %s\n", progname, uri, wiredtiger_strerror(ret)); goto err; } /* List the statistics. */ while ( (ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pval, &v)) == 0) if (printf("%s=%s\n", desc, pval) < 0) { ret = errno; break; } if (ret == WT_NOTFOUND) ret = 0; if (ret != 0) { fprintf(stderr, "%s: cursor get(%s) failed: %s\n", progname, objname, wiredtiger_strerror(ret)); goto err; } err: if (objname_free) free(objname); free(uri); return (ret); }
/* * __curjoin_entry_member -- * Do a membership check for a particular index that was joined, * if not a member, returns WT_NOTFOUND. */ static int __curjoin_entry_member(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin, WT_CURSOR_JOIN_ENTRY *entry, bool skip_left) { WT_CURJOIN_EXTRACTOR extract_cursor; WT_CURSOR *c; WT_CURSOR_STATIC_INIT(iface, __wt_cursor_get_key, /* get-key */ __wt_cursor_get_value, /* get-value */ __wt_cursor_set_key, /* set-key */ __wt_cursor_set_value, /* set-value */ __wt_cursor_notsup, /* compare */ __wt_cursor_notsup, /* equals */ __wt_cursor_notsup, /* next */ __wt_cursor_notsup, /* prev */ __wt_cursor_notsup, /* reset */ __wt_cursor_notsup, /* search */ __wt_cursor_notsup, /* search-near */ __curjoin_extract_insert, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* reconfigure */ __wt_cursor_notsup, /* remove */ __wt_cursor_notsup); /* close */ WT_DECL_RET; WT_INDEX *idx; WT_ITEM *key, v; bool bloom_found; key = cjoin->iter->curkey; entry->stats.accesses++; bloom_found = false; if (entry->bloom != NULL) { /* * If we don't own the Bloom filter, we must be sharing one * in a previous entry. So the shared filter has already * been checked and passed. */ if (!F_ISSET(entry, WT_CURJOIN_ENTRY_OWN_BLOOM)) return (0); /* * If the item is not in the Bloom filter, we return * immediately, otherwise, we still need to check the * long way. */ WT_ERR(__wt_bloom_inmem_get(entry->bloom, key)); bloom_found = true; } if (entry->index != NULL) { memset(&v, 0, sizeof(v)); /* Keep lint quiet. */ c = entry->main; c->set_key(c, key); if ((ret = c->search(c)) == 0) ret = c->get_value(c, &v); else if (ret == WT_NOTFOUND) WT_ERR_MSG(session, WT_ERROR, "main table for join is missing entry."); WT_TRET(c->reset(c)); WT_ERR(ret); } else v = *key; if ((idx = entry->index) != NULL && idx->extractor != NULL) { extract_cursor.iface = iface; extract_cursor.iface.session = &session->iface; extract_cursor.iface.key_format = idx->exkey_format; extract_cursor.ismember = 0; extract_cursor.entry = entry; WT_ERR(idx->extractor->extract(idx->extractor, &session->iface, key, &v, &extract_cursor.iface)); if (!extract_cursor.ismember) WT_ERR(WT_NOTFOUND); } else WT_ERR(__curjoin_entry_in_range(session, entry, &v, skip_left)); if (0) { err: if (ret == WT_NOTFOUND && bloom_found) entry->stats.bloom_false_positive++; } return (ret); }
Status WiredTigerUtil::exportTableToBSON(WT_SESSION* session, const std::string& uri, const std::string& config, BSONObjBuilder* bob) { invariant(session); invariant(bob); WT_CURSOR* c = NULL; const char *cursorConfig = config.empty() ? NULL : config.c_str(); int ret = session->open_cursor(session, uri.c_str(), NULL, cursorConfig, &c); if (ret != 0) { return Status(ErrorCodes::CursorNotFound, str::stream() << "unable to open cursor at URI " << uri << ". reason: " << wiredtiger_strerror(ret)); } bob->append("uri", uri); invariant(c); ON_BLOCK_EXIT(c->close, c); std::map<string,BSONObjBuilder*> subs; const char *desc, *pvalue; uint64_t value; while (c->next(c) == 0 && c->get_value(c, &desc, &pvalue, &value) == 0) { StringData key( desc ); StringData prefix; StringData suffix; size_t idx = key.find( ':' ); if ( idx != string::npos ) { prefix = key.substr( 0, idx ); suffix = key.substr( idx + 1 ); } else { idx = key.find( ' ' ); } if ( idx != string::npos ) { prefix = key.substr( 0, idx ); suffix = key.substr( idx + 1 ); } else { prefix = key; suffix = "num"; } // Convert unsigned 64-bit integral value of statistic to BSON-friendly long long. // If there is an overflow, set statistic value to max(long long). const long long maxLL = std::numeric_limits<long long>::max(); long long v = value > static_cast<uint64_t>(maxLL) ? maxLL : static_cast<long long>(value); if ( prefix.size() == 0 ) { bob->appendNumber(desc, v); } else { BSONObjBuilder*& sub = subs[prefix.toString()]; if ( !sub ) sub = new BSONObjBuilder(); sub->appendNumber(mongoutils::str::ltrim(suffix.toString()), v); } } for ( std::map<string,BSONObjBuilder*>::const_iterator it = subs.begin(); it != subs.end(); ++it ) { const std::string& s = it->first; bob->append( s, it->second->obj() ); delete it->second; } return Status::OK(); }
void * stat_worker(void *arg) { CONFIG *cfg; WT_CONNECTION *conn; WT_SESSION *session; WT_CURSOR *cursor; const char *desc, *pvalue; char *lsm_uri; double secs; int ret; struct timeval e; uint64_t value; cfg = (CONFIG *)arg; conn = cfg->conn; lsm_uri = NULL; if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { fprintf(stderr, "open_session failed in read thread: %d\n", ret); return (NULL); } if (strncmp(cfg->uri, "lsm:", strlen("lsm:")) == 0) { lsm_uri = calloc( strlen(cfg->uri) + strlen("statistics:") + 1, 1); if (lsm_uri == NULL) { fprintf(stderr, "No memory in stat thread.\n"); goto err; } sprintf(lsm_uri, "statistics:%s", cfg->uri); } while (stat_running) { sleep(cfg->report_interval); /* Generic header. */ fprintf(cfg->logf, "=======================================\n"); gettimeofday(&e, NULL); 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, "%s completed: %" PRIu64", elapsed time: %.2f\n", cfg->phase == LSM_TEST_PERF_READ ? "reads" : "inserts", nops, secs); /* Report LSM tree stats, if using LSM. */ if (lsm_uri != NULL) { if ((ret = session->open_cursor(session, lsm_uri, NULL, NULL, &cursor)) != 0) { fprintf(stderr, "open_cursor LSM statistics: %d\n", ret); goto err; } while ( (ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value( cursor, &desc, &pvalue, &value)) == 0) fprintf(cfg->logf, "stat:lsm: %s=%s\n", desc, pvalue); cursor->close(cursor); fprintf(cfg->logf, "\n"); } /* Dump the connection statistics since last time. */ if ((ret = session->open_cursor(session, "statistics:", NULL, "statistics_clear", &cursor)) != 0) { fprintf(stderr, "open_cursor statistics: %d\n", ret); goto err; } while ( (ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value( cursor, &desc, &pvalue, &value)) == 0) fprintf(cfg->logf, "stat:conn: %s=%s\n", desc, pvalue); cursor->close(cursor); } err: session->close(session, NULL); if (lsm_uri != NULL) free(lsm_uri); return (arg); }
/* * __curjoin_entry_member -- * Do a membership check for a particular index that was joined, * if not a member, returns WT_NOTFOUND. */ static int __curjoin_entry_member(WT_SESSION_IMPL *session, WT_CURSOR_JOIN_ENTRY *entry, WT_ITEM *key, WT_CURSOR_JOIN_ITER *iter) { WT_CURJOIN_EXTRACTOR extract_cursor; WT_CURSOR *c; WT_CURSOR_STATIC_INIT(iface, __wt_cursor_get_key, /* get-key */ __wt_cursor_get_value, /* get-value */ __wt_cursor_set_key, /* set-key */ __wt_cursor_set_value, /* set-value */ __wt_cursor_compare_notsup, /* compare */ __wt_cursor_equals_notsup, /* equals */ __wt_cursor_notsup, /* next */ __wt_cursor_notsup, /* prev */ __wt_cursor_notsup, /* reset */ __wt_cursor_notsup, /* search */ __wt_cursor_search_near_notsup, /* search-near */ __curjoin_extract_insert, /* insert */ __wt_cursor_modify_notsup, /* modify */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ __wt_cursor_notsup, /* reserve */ __wt_cursor_reconfigure_notsup, /* reconfigure */ __wt_cursor_notsup, /* cache */ __wt_cursor_reopen_notsup, /* reopen */ __wt_cursor_notsup); /* close */ WT_DECL_RET; WT_INDEX *idx; WT_ITEM v; bool bloom_found; if (entry->subjoin == NULL && iter != NULL && (iter->end_pos + iter->end_skip >= entry->ends_next || (iter->end_skip > 0 && F_ISSET(entry, WT_CURJOIN_ENTRY_DISJUNCTION)))) return (0); /* no checks to make */ entry->stats.membership_check++; bloom_found = false; if (entry->bloom != NULL) { /* * If the item is not in the Bloom filter, we return * immediately, otherwise, we still may need to check the * long way, since it may be a false positive. * * If we don't own the Bloom filter, we must be sharing one * in a previous entry. So the shared filter has already * been checked and passed, we don't need to check it again. * We'll still need to check the long way. */ if (F_ISSET(entry, WT_CURJOIN_ENTRY_OWN_BLOOM)) WT_ERR(__wt_bloom_inmem_get(entry->bloom, key)); if (F_ISSET(entry, WT_CURJOIN_ENTRY_FALSE_POSITIVES)) return (0); bloom_found = true; } if (entry->subjoin != NULL) { WT_ASSERT(session, iter == NULL || entry->subjoin == iter->child->cjoin); ret = __curjoin_entries_in_range(session, entry->subjoin, key, iter == NULL ? NULL : iter->child); if (iter != NULL && WT_CURJOIN_ITER_CONSUMED(iter->child)) { WT_ERR(__curjoin_iter_bump(iter)); ret = WT_NOTFOUND; } return (ret); } if (entry->index != NULL) { /* * If this entry is used by the iterator, then we already * have the index key, and we won't have to do any * extraction either. */ if (iter != NULL && entry == iter->entry) WT_ITEM_SET(v, iter->idxkey); else { memset(&v, 0, sizeof(v)); /* Keep lint quiet. */ c = entry->main; c->set_key(c, key); entry->stats.main_access++; if ((ret = c->search(c)) == 0) ret = c->get_value(c, &v); else if (ret == WT_NOTFOUND) { __wt_err(session, ret, "main table for join is missing entry"); ret = WT_ERROR; } WT_TRET(c->reset(c)); WT_ERR(ret); } } else WT_ITEM_SET(v, *key); if ((idx = entry->index) != NULL && idx->extractor != NULL && (iter == NULL || entry != iter->entry)) { WT_CLEAR(extract_cursor); extract_cursor.iface = iface; extract_cursor.iface.session = &session->iface; extract_cursor.iface.key_format = idx->exkey_format; extract_cursor.ismember = false; extract_cursor.entry = entry; WT_ERR(idx->extractor->extract(idx->extractor, &session->iface, key, &v, &extract_cursor.iface)); __wt_buf_free(session, &extract_cursor.iface.key); __wt_buf_free(session, &extract_cursor.iface.value); if (!extract_cursor.ismember) WT_ERR(WT_NOTFOUND); } else WT_ERR(__curjoin_entry_in_range(session, entry, &v, iter)); if (0) { err: if (ret == WT_NOTFOUND && bloom_found) entry->stats.bloom_false_positive++; } return (ret); }
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); }
/* * __las_page_instantiate -- * Instantiate lookaside update records in a recently read page. */ static int __las_page_instantiate(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t read_id, const uint8_t *addr, size_t addr_size) { WT_CURSOR *cursor; WT_CURSOR_BTREE cbt; WT_DECL_ITEM(current_key); WT_DECL_ITEM(las_addr); WT_DECL_ITEM(las_key); WT_DECL_ITEM(las_value); WT_DECL_RET; WT_PAGE *page; WT_UPDATE *first_upd, *last_upd, *upd; size_t incr, total_incr; uint64_t current_recno, las_counter, las_txnid, recno, upd_txnid; uint32_t las_id, upd_size, session_flags; int exact; const uint8_t *p; cursor = NULL; page = ref->page; first_upd = last_upd = upd = NULL; total_incr = 0; current_recno = recno = WT_RECNO_OOB; session_flags = 0; /* [-Werror=maybe-uninitialized] */ __wt_btcur_init(session, &cbt); __wt_btcur_open(&cbt); WT_ERR(__wt_scr_alloc(session, 0, ¤t_key)); WT_ERR(__wt_scr_alloc(session, 0, &las_addr)); WT_ERR(__wt_scr_alloc(session, 0, &las_key)); WT_ERR(__wt_scr_alloc(session, 0, &las_value)); /* Open a lookaside table cursor. */ WT_ERR(__wt_las_cursor(session, &cursor, &session_flags)); /* * The lookaside records are in key and update order, that is, there * will be a set of in-order updates for a key, then another set of * in-order updates for a subsequent key. We process all of the updates * for a key and then insert those updates into the page, then all the * updates for the next key, and so on. * * Search for the block's unique prefix, stepping through any matching * records. */ las_addr->data = addr; las_addr->size = addr_size; las_key->size = 0; cursor->set_key( cursor, read_id, las_addr, (uint64_t)0, (uint32_t)0, las_key); if ((ret = cursor->search_near(cursor, &exact)) == 0 && exact < 0) ret = cursor->next(cursor); for (; ret == 0; ret = cursor->next(cursor)) { WT_ERR(cursor->get_key(cursor, &las_id, las_addr, &las_counter, &las_txnid, las_key)); /* * Confirm the search using the unique prefix; if not a match, * we're done searching for records for this page. */ if (las_id != read_id || las_addr->size != addr_size || memcmp(las_addr->data, addr, addr_size) != 0) break; /* * If the on-page value has become globally visible, this record * is no longer needed. */ if (__wt_txn_visible_all(session, las_txnid)) continue; /* Allocate the WT_UPDATE structure. */ WT_ERR(cursor->get_value( cursor, &upd_txnid, &upd_size, las_value)); WT_ERR(__wt_update_alloc(session, (upd_size == WT_UPDATE_DELETED_VALUE) ? NULL : las_value, &upd, &incr)); total_incr += incr; upd->txnid = upd_txnid; switch (page->type) { case WT_PAGE_COL_FIX: case WT_PAGE_COL_VAR: p = las_key->data; WT_ERR(__wt_vunpack_uint(&p, 0, &recno)); if (current_recno == recno) break; WT_ASSERT(session, current_recno < recno); if (first_upd != NULL) { WT_ERR(__col_instantiate(session, current_recno, ref, &cbt, first_upd)); first_upd = NULL; } current_recno = recno; break; case WT_PAGE_ROW_LEAF: if (current_key->size == las_key->size && memcmp(current_key->data, las_key->data, las_key->size) == 0) break; if (first_upd != NULL) { WT_ERR(__row_instantiate(session, current_key, ref, &cbt, first_upd)); first_upd = NULL; } WT_ERR(__wt_buf_set(session, current_key, las_key->data, las_key->size)); break; WT_ILLEGAL_VALUE_ERR(session); } /* Append the latest update to the list. */ if (first_upd == NULL) first_upd = last_upd = upd; else { last_upd->next = upd; last_upd = upd; } upd = NULL; } WT_ERR_NOTFOUND_OK(ret); /* Insert the last set of updates, if any. */ if (first_upd != NULL) switch (page->type) { case WT_PAGE_COL_FIX: case WT_PAGE_COL_VAR: WT_ERR(__col_instantiate(session, current_recno, ref, &cbt, first_upd)); first_upd = NULL; break; case WT_PAGE_ROW_LEAF: WT_ERR(__row_instantiate(session, current_key, ref, &cbt, first_upd)); first_upd = NULL; break; WT_ILLEGAL_VALUE_ERR(session); } /* Discard the cursor. */ WT_ERR(__wt_las_cursor_close(session, &cursor, session_flags)); if (total_incr != 0) { __wt_cache_page_inmem_incr(session, page, total_incr); /* * We've modified/dirtied the page, but that's not necessary and * if we keep the page clean, it's easier to evict. We leave the * lookaside table updates in place, so if we evict this page * without dirtying it, any future instantiation of it will find * the records it needs. If the page is dirtied before eviction, * then we'll write any needed lookaside table records for the * new location of the page. */ __wt_page_modify_clear(session, page); } err: WT_TRET(__wt_las_cursor_close(session, &cursor, session_flags)); WT_TRET(__wt_btcur_close(&cbt, 1)); /* * On error, upd points to a single unlinked WT_UPDATE structure, * first_upd points to a list. */ if (upd != NULL) __wt_free(session, upd); if (first_upd != NULL) __wt_free_update_list(session, first_upd); __wt_scr_free(session, ¤t_key); __wt_scr_free(session, &las_addr); __wt_scr_free(session, &las_key); __wt_scr_free(session, &las_value); return (ret); }
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); }
/* * list_print -- * List the high-level objects in the database. */ static int list_print(WT_SESSION *session, const char *name, int cflag, int vflag) { WT_CURSOR *cursor; WT_DECL_RET; int found; const char *key, *value; /* Open the metadata file. */ if ((ret = session->open_cursor( session, WT_METADATA_URI, NULL, NULL, &cursor)) != 0) { /* * If there is no metadata (yet), this will return ENOENT. * Treat that the same as an empty metadata. */ if (ret == ENOENT) return (0); fprintf(stderr, "%s: %s: session.open_cursor: %s\n", progname, WT_METADATA_URI, session->strerror(session, ret)); return (1); } found = name == NULL; while ((ret = cursor->next(cursor)) == 0) { /* Get the key. */ if ((ret = cursor->get_key(cursor, &key)) != 0) return (util_cerr(cursor, "get_key", ret)); /* * If a name is specified, only show objects that match. */ if (name != NULL) { if (!WT_PREFIX_MATCH(key, name)) continue; found = 1; } /* * !!! * We don't normally say anything about the WiredTiger metadata * and lookaside tables, they're not application/user "objects" * in the database. I'm making an exception for the checkpoint * and verbose options. */ if (cflag || vflag || (strcmp(key, WT_METADATA_URI) != 0 && strcmp(key, WT_LAS_URI) != 0)) printf("%s\n", key); if (!cflag && !vflag) continue; if (cflag && (ret = list_print_checkpoint(session, key)) != 0) return (ret); if (vflag) { if ((ret = cursor->get_value(cursor, &value)) != 0) return (util_cerr(cursor, "get_value", ret)); printf("%s\n", value); } } if (ret != WT_NOTFOUND) return (util_cerr(cursor, "next", ret)); if (!found) { fprintf(stderr, "%s: %s: not found\n", progname, name); return (1); } return (0); }
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 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); }
void * stat_worker(void *arg) { CONFIG *cfg; WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; const char *desc, *pvalue; char *stat_uri; double secs; int ret; size_t uri_len; struct timeval e; uint32_t i; uint64_t value; session = NULL; cfg = (CONFIG *)arg; conn = cfg->conn; stat_uri = NULL; if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { lprintf(cfg, ret, 0, "open_session failed in statistics thread."); goto err; } uri_len = strlen("statistics:") + strlen(cfg->uri) + 1; if ((stat_uri = malloc(uri_len)) == NULL) { lprintf(cfg, ENOMEM, 0, "Statistics thread uri create."); goto err; } (void)snprintf(stat_uri, uri_len, "statistics:%s", cfg->uri); while (g_util_running) { /* Break the sleep up, so we notice interrupts faster. */ for (i = 0; i < cfg->stat_interval; i++) { sleep(cfg->report_interval); if (!g_util_running) break; } /* Generic header. */ lprintf(cfg, 0, cfg->verbose, "======================================="); gettimeofday(&e, NULL); 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; if (cfg->phase == WT_PERF_POP) lprintf(cfg, 0, cfg->verbose, "inserts: %" PRIu64 ", elapsed time: %.2f", g_npop_ops, secs); else lprintf(cfg, 0, cfg->verbose, "reads: %" PRIu64 " inserts: %" PRIu64 " updates: %" PRIu64 ", elapsed time: %.2f", g_nread_ops, g_nins_ops, g_nupdate_ops, secs); /* Report data source stats. */ if ((ret = session->open_cursor(session, stat_uri, NULL, "statistics_fast", &cursor)) != 0) { lprintf(cfg, ret, 0, "open_cursor failed for data source statistics"); goto err; } while ((ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pvalue, &value)) == 0 && value != 0) lprintf(cfg, 0, cfg->verbose, "stat:lsm: %s=%s", desc, pvalue); cursor->close(cursor); lprintf(cfg, 0, cfg->verbose, "-----------------"); /* Dump the connection statistics since last time. */ if ((ret = session->open_cursor(session, "statistics:", NULL, "statistics_clear", &cursor)) != 0) { lprintf(cfg, ret, 0, "open_cursor failed in statistics"); goto err; } while ((ret = cursor->next(cursor)) == 0 && (ret = cursor->get_value(cursor, &desc, &pvalue, &value)) == 0 && value != 0) lprintf(cfg, 0, cfg->verbose, "stat:conn: %s=%s", desc, pvalue); cursor->close(cursor); } err: if (session != NULL) session->close(session, NULL); if (stat_uri != NULL) free(stat_uri); return (arg); }
/* * __schema_open_table -- * Open a named table (internal version). */ static int __schema_open_table(WT_SESSION_IMPL *session, const char *name, size_t namelen, bool ok_incomplete, WT_TABLE **tablep) { WT_CONFIG cparser; WT_CONFIG_ITEM ckey, cval; WT_CURSOR *cursor; WT_DECL_ITEM(buf); WT_DECL_RET; WT_TABLE *table; const char *tconfig; char *tablename; cursor = NULL; table = NULL; tablename = NULL; WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE)); WT_ERR(__wt_scr_alloc(session, 0, &buf)); WT_ERR(__wt_buf_fmt(session, buf, "table:%.*s", (int)namelen, name)); WT_ERR(__wt_strndup(session, buf->data, buf->size, &tablename)); WT_ERR(__wt_metadata_cursor(session, &cursor)); cursor->set_key(cursor, tablename); WT_ERR(cursor->search(cursor)); WT_ERR(cursor->get_value(cursor, &tconfig)); WT_ERR(__wt_calloc_one(session, &table)); table->name = tablename; tablename = NULL; table->name_hash = __wt_hash_city64(name, namelen); WT_ERR(__wt_config_getones(session, tconfig, "columns", &cval)); WT_ERR(__wt_config_getones(session, tconfig, "key_format", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->key_format)); WT_ERR(__wt_config_getones(session, tconfig, "value_format", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->value_format)); WT_ERR(__wt_strdup(session, tconfig, &table->config)); /* Point to some items in the copy to save re-parsing. */ WT_ERR(__wt_config_getones(session, table->config, "columns", &table->colconf)); /* * Count the number of columns: tables are "simple" if the columns * are not named. */ WT_ERR(__wt_config_subinit(session, &cparser, &table->colconf)); table->is_simple = true; while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0) table->is_simple = false; if (ret != WT_NOTFOUND) goto err; /* Check that the columns match the key and value formats. */ if (!table->is_simple) WT_ERR(__wt_schema_colcheck(session, table->key_format, table->value_format, &table->colconf, &table->nkey_columns, NULL)); WT_ERR(__wt_config_getones(session, table->config, "colgroups", &table->cgconf)); /* Count the number of column groups. */ WT_ERR(__wt_config_subinit(session, &cparser, &table->cgconf)); table->ncolgroups = 0; while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0) ++table->ncolgroups; if (ret != WT_NOTFOUND) goto err; if (table->ncolgroups > 0 && table->is_simple) WT_ERR_MSG(session, EINVAL, "%s requires a table with named columns", tablename); WT_ERR(__wt_calloc_def(session, WT_COLGROUPS(table), &table->cgroups)); WT_ERR(__wt_schema_open_colgroups(session, table)); if (!ok_incomplete && !table->cg_complete) WT_ERR_MSG(session, EINVAL, "'%s' cannot be used " "until all column groups are created", table->name); /* Copy the schema generation into the new table. */ table->schema_gen = S2C(session)->schema_gen; *tablep = table; if (0) { err: WT_TRET(__wt_schema_destroy_table(session, &table)); } WT_TRET(__wt_metadata_cursor_release(session, &cursor)); __wt_free(session, tablename); __wt_scr_free(session, &buf); 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); }