/* * __curindex_search_near -- * WT_CURSOR->search_near method for index cursors. */ static int __curindex_search_near(WT_CURSOR *cursor, int *exact) { WT_CURSOR *child; WT_CURSOR_INDEX *cindex; WT_DECL_RET; WT_ITEM found_key; WT_SESSION_IMPL *session; int cmp; cindex = (WT_CURSOR_INDEX *)cursor; child = cindex->child; JOINABLE_CURSOR_API_CALL(cursor, session, search, NULL); /* * We are searching using the application-specified key, which * (usually) doesn't contain the primary key, so it is just a prefix of * any matching index key. That said, if there is an exact match, we * want to find the first matching index entry and set exact equal to * zero. * * Do a search_near, and if we find an entry that is too small, step to * the next one. In the unlikely event of a search past the end of the * tree, go back to the last key. */ __wt_cursor_set_raw_key(child, &cursor->key); WT_ERR(child->search_near(child, &cmp)); if (cmp < 0) { if ((ret = child->next(child)) == WT_NOTFOUND) ret = child->prev(child); WT_ERR(ret); } /* * We expect partial matches, and want the smallest record with a key * greater than or equal to the search key. * * If the found key starts with the search key, we indicate a match by * setting exact equal to zero. * * The compare function expects application-supplied keys to come first * so we flip the sign of the result to match what callers expect. */ found_key = child->key; if (found_key.size > cursor->key.size) found_key.size = cursor->key.size; WT_ERR(__wt_compare( session, cindex->index->collator, &cursor->key, &found_key, exact)); *exact = -*exact; WT_ERR(__curindex_move(cindex)); if (0) { err: F_CLR(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_VALUE_INT); } API_END_RET(session, ret); }
/* * Ensure that icount matches the number of records in the * existing table. */ int find_table_count(CONFIG *cfg) { WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; char *key; int ret; conn = cfg->conn; if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) { lprintf(cfg, ret, 0, "open_session failed finding existing table count"); goto err; } if ((ret = session->open_cursor(session, cfg->uri, NULL, NULL, &cursor)) != 0) { lprintf(cfg, ret, 0, "open_cursor failed finding existing table count"); goto err; } if ((ret = cursor->prev(cursor)) != 0) { lprintf(cfg, ret, 0, "cursor prev failed finding existing table count"); goto err; } cursor->get_key(cursor, &key); cfg->icount = (uint32_t)atoi(key); err: session->close(session, NULL); return (ret); }
boost::optional<RecordId> WiredTigerRecordStore::oplogStartHack( OperationContext* txn, const RecordId& startingPosition) const { if (!_useOplogHack) return boost::none; { WiredTigerRecoveryUnit* wru = WiredTigerRecoveryUnit::get(txn); _oplogSetStartHack(wru); } WiredTigerCursor cursor(_uri, _tableId, true, txn); WT_CURSOR* c = cursor.get(); int cmp; c->set_key(c, _makeKey(startingPosition)); int ret = WT_OP_CHECK(c->search_near(c, &cmp)); if (ret == 0 && cmp > 0) ret = c->prev(c); // landed one higher than startingPosition if (ret == WT_NOTFOUND) return RecordId(); // nothing <= startingPosition invariantWTOK(ret); int64_t key; ret = c->get_key(c, &key); invariantWTOK(ret); return _fromKey(key); }
/* * __wt_bloom_open -- * Open a Bloom filter object for use by a single session. The filter must * have been created and finalized. */ int __wt_bloom_open(WT_SESSION_IMPL *session, const char *uri, uint32_t factor, uint32_t k, WT_CURSOR *owner, WT_BLOOM **bloomp) { WT_BLOOM *bloom; WT_CURSOR *c; WT_DECL_RET; uint64_t size; WT_RET(__bloom_init(session, uri, NULL, &bloom)); WT_ERR(__bloom_open_cursor(bloom, owner)); c = bloom->c; /* Find the largest key, to get the size of the filter. */ WT_ERR(c->prev(c)); WT_ERR(c->get_key(c, &size)); WT_ERR(c->reset(c)); WT_ERR(__bloom_setup(bloom, 0, size, factor, k)); *bloomp = bloom; return (0); err: (void)__wt_bloom_close(bloom); return (ret); }
boost::optional<Record> next() final { if (_eof) return {}; WT_CURSOR* c = _cursor->get(); bool mustAdvance = true; if (_lastReturnedId.isNull() && !_forward && _rs._isCapped) { // In this case we need to seek to the highest visible record. const RecordId reverseCappedInitialSeekPoint = _readUntilForOplog.isNull() ? _rs.lowestCappedHiddenRecord() : _readUntilForOplog; if (!reverseCappedInitialSeekPoint.isNull()) { c->set_key(c, _makeKey(reverseCappedInitialSeekPoint)); int cmp; int seekRet = WT_OP_CHECK(c->search_near(c, &cmp)); if (seekRet == WT_NOTFOUND) { _eof = true; return {}; } invariantWTOK(seekRet); // If we landed at or past the lowest hidden record, we must advance to be in // the visible range. mustAdvance = _rs.isCappedHidden(reverseCappedInitialSeekPoint) ? (cmp >= 0) : (cmp > 0); // No longer hidden. } } if (mustAdvance) { // Nothing after the next line can throw WCEs. // Note that an unpositioned (or eof) WT_CURSOR returns the first/last entry in the // table when you call next/prev. int advanceRet = WT_OP_CHECK(_forward ? c->next(c) : c->prev(c)); if (advanceRet == WT_NOTFOUND) { _eof = true; return {}; } invariantWTOK(advanceRet); } int64_t key; invariantWTOK(c->get_key(c, &key)); const RecordId id = _fromKey(key); if (!isVisible(id)) { _eof = true; return {}; } WT_ITEM value; invariantWTOK(c->get_value(c, &value)); _lastReturnedId = id; return {{id, {static_cast<const char*>(value.data), static_cast<int>(value.size)}}}; }
bool restore() final { if (!_cursor) _cursor.emplace(_rs.getURI(), _rs.tableId(), true, _txn); // This will ensure an active session exists, so any restored cursors will bind to it invariant(WiredTigerRecoveryUnit::get(_txn)->getSession(_txn) == _cursor->getSession()); // If we've hit EOF, then this iterator is done and need not be restored. if (_eof) return true; if (_lastReturnedId.isNull()) return true; WT_CURSOR* c = _cursor->get(); c->set_key(c, _makeKey(_lastReturnedId)); int cmp; int ret = WT_OP_CHECK(c->search_near(c, &cmp)); if (ret == WT_NOTFOUND) { _eof = true; return !_rs._isCapped; } invariantWTOK(ret); if (cmp == 0) return true; // Landed right where we left off. if (_rs._isCapped) { // Doc was deleted either by cappedDeleteAsNeeded() or cappedTruncateAfter(). // It is important that we error out in this case so that consumers don't // silently get 'holes' when scanning capped collections. We don't make // this guarantee for normal collections so it is ok to skip ahead in that case. _eof = true; return false; } if (_forward && cmp > 0) { // We landed after where we were. Move back one so that next() will return this // document. ret = WT_OP_CHECK(c->prev(c)); } else if (!_forward && cmp < 0) { // Do the opposite for reverse cursors. ret = WT_OP_CHECK(c->next(c)); } if (ret != WT_NOTFOUND) invariantWTOK(ret); return true; }
/* * __curds_prev -- * WT_CURSOR.prev method for the data-source cursor type. */ static int __curds_prev(WT_CURSOR *cursor) { WT_CURSOR *source; WT_DECL_RET; WT_SESSION_IMPL *session; source = ((WT_CURSOR_DATA_SOURCE *)cursor)->source; CURSOR_API_CALL(cursor, session, prev, NULL); WT_STAT_CONN_INCR(session, cursor_prev); WT_STAT_DATA_INCR(session, cursor_prev); WT_ERR(__curds_txn_enter(session, false)); F_CLR(cursor, WT_CURSTD_KEY_SET | WT_CURSTD_VALUE_SET); ret = __curds_cursor_resolve(cursor, source->prev(source)); err: __curds_txn_leave(session); API_END_RET(session, 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] */ /*! [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 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; }
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 setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) { TRUNCATE_CONFIG *trunc_cfg; TRUNCATE_QUEUE_ENTRY *truncate_item; WORKLOAD *workload; WT_CURSOR *cursor; char *key, *truncate_key; int ret; uint64_t end_point, final_stone_gap, i, start_point; end_point = final_stone_gap = start_point = 0; trunc_cfg = &thread->trunc_cfg; workload = thread->workload; /* We are limited to only one table when running truncate. */ if ((ret = session->open_cursor( session, cfg->uris[0], NULL, NULL, &cursor)) != 0) goto err; /* How many entries between each stone. */ trunc_cfg->stone_gap = (workload->truncate_count * workload->truncate_pct) / 100; /* How many stones we need. */ trunc_cfg->needed_stones = workload->truncate_count / trunc_cfg->stone_gap; final_stone_gap = trunc_cfg->stone_gap; /* Reset this value for use again. */ trunc_cfg->stone_gap = 0; /* * Here we check if there is data in the collection. If there is * data available, then we need to setup some initial truncation * stones. */ if ((ret = cursor->next(cursor)) != 0 || (ret = cursor->get_key(cursor, &key)) != 0) { lprintf(cfg, ret, 0, "truncate setup start: failed"); goto err; } start_point = decode_key(key); if ((cursor->reset(cursor)) != 0 || (ret = cursor->prev(cursor)) != 0 || (ret = cursor->get_key(cursor, &key)) != 0) { lprintf(cfg, ret, 0, "truncate setup end: failed"); goto err; } end_point = decode_key(key); /* Assign stones if there are enough documents. */ if (start_point + trunc_cfg->needed_stones > end_point) trunc_cfg->stone_gap = 0; else trunc_cfg->stone_gap = (end_point - start_point) / trunc_cfg->needed_stones; /* If we have enough data allocate some stones. */ if (trunc_cfg->stone_gap != 0) { trunc_cfg->expected_total = (end_point - start_point); for (i = 1; i <= trunc_cfg->needed_stones; i++) { truncate_key = calloc(cfg->key_sz, 1); if (truncate_key == NULL) { ret = enomem(cfg); goto err; } truncate_item = calloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); if (truncate_item == NULL) { free(truncate_key); ret = enomem(cfg); goto err; } generate_key( cfg, truncate_key, trunc_cfg->stone_gap * i); truncate_item->key = truncate_key; truncate_item->diff = (trunc_cfg->stone_gap * i) - trunc_cfg->last_key; TAILQ_INSERT_TAIL( &cfg->stone_head, truncate_item, q); trunc_cfg->last_key = trunc_cfg->stone_gap * i; trunc_cfg->num_stones++; } } trunc_cfg->stone_gap = final_stone_gap; err: if ((ret = cursor->close(cursor)) != 0) { lprintf(cfg, ret, 0, "truncate setup: cursor close failed"); } return (ret); }
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); }