/* * __curds_remove -- * WT_CURSOR.remove method for the data-source cursor type. */ static int __curds_remove(WT_CURSOR *cursor) { WT_CURSOR *source; WT_DECL_RET; WT_SESSION_IMPL *session; source = ((WT_CURSOR_DATA_SOURCE *)cursor)->source; CURSOR_REMOVE_API_CALL(cursor, session, NULL); WT_STAT_CONN_INCR(session, cursor_remove); WT_STAT_DATA_INCR(session, cursor_remove); WT_STAT_DATA_INCRV(session, cursor_remove_bytes, cursor->key.size); WT_ERR(__curds_txn_enter(session, true)); WT_ERR(__curds_key_set(cursor)); ret = __curds_cursor_resolve(cursor, source->remove(source)); err: __curds_txn_leave(session); CURSOR_UPDATE_API_END(session, ret); return (ret); }
/* * __wt_metadata_remove -- * Remove a row from the metadata. */ int __wt_metadata_remove(WT_SESSION_IMPL *session, const char *key) { WT_CURSOR *cursor; WT_DECL_RET; WT_RET(__wt_verbose(session, WT_VERB_METADATA, "Remove: key: %s, tracking: %s, %s" "turtle", key, WT_META_TRACKING(session) ? "true" : "false", __metadata_turtle(key) ? "" : "not ")); if (__metadata_turtle(key)) WT_RET_MSG(session, EINVAL, "%s: remove not supported on the turtle file", key); WT_RET(__wt_metadata_cursor(session, NULL, &cursor)); cursor->set_key(cursor, key); WT_ERR(cursor->search(cursor)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_update(session, key)); WT_ERR(cursor->remove(cursor)); err: WT_TRET(cursor->close(cursor)); return (ret); }
int wt_id2entry_delete( Operation *op, WT_SESSION *session, Entry *e ) { int rc; WT_CURSOR *cursor = NULL; rc = session->open_cursor(session, WT_TABLE_ID2ENTRY, NULL, NULL, &cursor); if ( rc ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(wt_id2entry_delete) ": open_cursor failed: %s (%d)\n", wiredtiger_strerror(rc), rc, 0 ); goto done; } cursor->set_key(cursor, e->e_id); rc = cursor->remove(cursor); if ( rc ) { Debug( LDAP_DEBUG_ANY, LDAP_XSTRING(wt_id2entry_delete) ": remove failed: %s (%d)\n", wiredtiger_strerror(rc), rc, 0 ); goto done; } done: if(cursor){ cursor->close(cursor); } return rc; }
/* * __truncate_dsrc -- * WT_SESSION::truncate for a data-source without a truncate operation. */ static int __truncate_dsrc(WT_SESSION_IMPL *session, const char *uri) { WT_CURSOR *cursor; WT_DECL_RET; const char *cfg[2]; /* Open a cursor and traverse the object, removing every entry. */ cfg[0] = WT_CONFIG_BASE(session, session_open_cursor); cfg[1] = NULL; WT_RET(__wt_open_cursor(session, uri, NULL, cfg, &cursor)); while ((ret = cursor->next(cursor)) == 0) WT_ERR(cursor->remove(cursor)); WT_ERR_NOTFOUND_OK(ret); err: WT_TRET(cursor->close(cursor)); return (ret); }
int WiredTigerEngine::Del(const Slice& key, const Options& options) { ContextHolder& holder = GetContextHolder(); WT_SESSION* session = holder.session; if (NULL == session) { return -1; } // if (holder.trasc_ref > 0) // { // DelOperation* op = new DelOperation; // op->key.assign((const char*) key.data(), key.size()); // m_write_queue.Push(op); // holder.readonly_transc = false; // return 0; // } int ret = 0; WT_CURSOR *cursor = holder.batch == NULL ? create_wiredtiger_cursor(session) : holder.batch; if (NULL == cursor) { return -1; } WT_ITEM key_item; key_item.data = key.data(); key_item.size = key.size(); cursor->set_key(cursor, &key_item); ret = cursor->remove(cursor); CHECK_WT_RETURN(ret); if (holder.batch == NULL) { cursor->close(cursor); CHECK_WT_RETURN(ret); } else { holder.IncBatchWriteCount(); if (holder.batch_write_count >= m_cfg.batch_commit_watermark) { holder.RestartBatchWrite(); } } return 0; }
/* * __wt_metadata_remove -- * Remove a row from the metadata. */ int __wt_metadata_remove(WT_SESSION_IMPL *session, const char *key) { WT_CURSOR *cursor; WT_DECL_RET; if (__metadata_turtle(key)) WT_RET_MSG(session, EINVAL, "%s: remove not supported on the turtle file", key); WT_RET(__wt_metadata_cursor(session, NULL, &cursor)); cursor->set_key(cursor, key); WT_ERR(cursor->search(cursor)); if (WT_META_TRACKING(session)) WT_ERR(__wt_meta_track_update(session, key)); WT_ERR(cursor->remove(cursor)); err: WT_TRET(cursor->close(cursor)); return (ret); }
void WiredTigerRecordStore::deleteRecord(OperationContext* txn, const RecordId& loc) { WiredTigerCursor cursor(_uri, _tableId, true, txn); cursor.assertInActiveTxn(); WT_CURSOR* c = cursor.get(); c->set_key(c, _makeKey(loc)); int ret = WT_OP_CHECK(c->search(c)); invariantWTOK(ret); WT_ITEM old_value; ret = c->get_value(c, &old_value); invariantWTOK(ret); int old_length = old_value.size; ret = WT_OP_CHECK(c->remove(c)); invariantWTOK(ret); _changeNumRecords(txn, -1); _increaseDataSize(txn, -old_length); }
/* * Remove some items from the primary table. */ static void remove_items(WT_SESSION *session) { WT_CURSOR *cursor; struct president_data p; int i; /* * Removing items from the primary table will call the extractor * for the index and allow our custom extractor code to handle * each custom key. */ error_check(session->open_cursor( session, "table:presidents", NULL, NULL, &cursor)); /* * Just remove the first few items. */ for (i = 0; example_data[i].last_name != NULL && i < 2; i++) { p = example_data[i]; cursor->set_key(cursor, p.id); error_check(cursor->remove(cursor)); } }
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); }
/* * __wt_las_sweep -- * Sweep the lookaside table. */ int __wt_las_sweep(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; WT_CURSOR *cursor; WT_DECL_ITEM(las_addr); WT_DECL_ITEM(las_key); WT_DECL_RET; WT_ITEM *key; uint64_t cnt, las_counter, las_txnid; int64_t remove_cnt; uint32_t las_id, session_flags; int notused; conn = S2C(session); cursor = NULL; key = &conn->las_sweep_key; remove_cnt = 0; session_flags = 0; /* [-Werror=maybe-uninitialized] */ WT_ERR(__wt_scr_alloc(session, 0, &las_addr)); WT_ERR(__wt_scr_alloc(session, 0, &las_key)); WT_ERR(__wt_las_cursor(session, &cursor, &session_flags)); /* * If we're not starting a new sweep, position the cursor using the key * from the last call (we don't care if we're before or after the key, * just roughly in the same spot is fine). */ if (key->size != 0) { __wt_cursor_set_raw_key(cursor, key); ret = cursor->search_near(cursor, ¬used); /* * Don't search for the same key twice; if we don't set a new * key below, it's because we've reached the end of the table * and we want the next pass to start at the beginning of the * table. Searching for the same key could leave us stuck at * the end of the table, repeatedly checking the same rows. */ key->size = 0; if (ret != 0) goto srch_notfound; } /* * The sweep server wakes up every 10 seconds (by default), it's a slow * moving thread. Try to review the entire lookaside table once every 5 * minutes, or every 30 calls. * * The reason is because the lookaside table exists because we're seeing * cache/eviction pressure (it allows us to trade performance and disk * space for cache space), and it's likely lookaside blocks are being * evicted, and reading them back in doesn't help things. A trickier, * but possibly better, alternative might be to review all lookaside * blocks in the cache in order to get rid of them, and slowly review * lookaside blocks that have already been evicted. */ cnt = (uint64_t)WT_MAX(100, conn->las_record_cnt / 30); /* Discard pages we read as soon as we're done with them. */ F_SET(session, WT_SESSION_NO_CACHE); /* Walk the file. */ for (; cnt > 0 && (ret = cursor->next(cursor)) == 0; --cnt) { /* * If the loop terminates after completing a work unit, we will * continue the table sweep next time. Get a local copy of the * sweep key, we're going to reset the cursor; do so before * calling cursor.remove, cursor.remove can discard our hazard * pointer and the page could be evicted from underneath us. */ if (cnt == 1) { WT_ERR(__wt_cursor_get_raw_key(cursor, key)); if (!WT_DATA_IN_ITEM(key)) WT_ERR(__wt_buf_set( session, key, key->data, key->size)); } WT_ERR(cursor->get_key(cursor, &las_id, las_addr, &las_counter, &las_txnid, las_key)); /* * If the on-page record transaction ID associated with the * record is globally visible, the record can be discarded. * * Cursor opened overwrite=true: won't return WT_NOTFOUND should * another thread remove the record before we do, and the cursor * remains positioned in that case. */ if (__wt_txn_visible_all(session, las_txnid)) { WT_ERR(cursor->remove(cursor)); ++remove_cnt; } } srch_notfound: WT_ERR_NOTFOUND_OK(ret); if (0) { err: __wt_buf_free(session, key); } WT_TRET(__wt_las_cursor_close(session, &cursor, session_flags)); /* * If there were races to remove records, we can over-count. All * arithmetic is signed, so underflow isn't fatal, but check anyway so * we don't skew low over time. */ if (remove_cnt > S2C(session)->las_record_cnt) S2C(session)->las_record_cnt = 0; else if (remove_cnt > 0) (void)__wt_atomic_subi64(&conn->las_record_cnt, remove_cnt); F_CLR(session, WT_SESSION_NO_CACHE); __wt_scr_free(session, &las_addr); __wt_scr_free(session, &las_key); return (ret); }
/* * __wt_las_sweep -- * Sweep the lookaside table. */ int __wt_las_sweep(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; WT_CURSOR *cursor; WT_DECL_ITEM(las_addr); WT_DECL_ITEM(las_key); WT_DECL_RET; WT_ITEM *key; uint64_t cnt, las_counter, las_txnid; uint32_t las_id, session_flags; int notused; conn = S2C(session); cursor = NULL; key = &conn->las_sweep_key; session_flags = 0; /* [-Werror=maybe-uninitialized] */ WT_ERR(__wt_scr_alloc(session, 0, &las_addr)); WT_ERR(__wt_scr_alloc(session, 0, &las_key)); WT_ERR(__wt_las_cursor(session, &cursor, &session_flags)); /* * If we're not starting a new sweep, position the cursor using the key * from the last call (we don't care if we're before or after the key, * just roughly in the same spot is fine). */ if (conn->las_sweep_call != 0 && key->data != NULL) { __wt_cursor_set_raw_key(cursor, key); if ((ret = cursor->search_near(cursor, ¬used)) != 0) goto srch_notfound; } /* * The sweep server wakes up every 10 seconds (by default), it's a slow * moving thread. Try to review the entire lookaside table once every 5 * minutes, or every 30 calls. * * The reason is because the lookaside table exists because we're seeing * cache/eviction pressure (it allows us to trade performance and disk * space for cache space), and it's likely lookaside blocks are being * evicted, and reading them back in doesn't help things. A trickier, * but possibly better, alternative might be to review all lookaside * blocks in the cache in order to get rid of them, and slowly review * lookaside blocks that have already been evicted. * * We can't know for sure how many records are in the lookaside table, * the cursor insert and remove statistics aren't updated atomically. * Start with reviewing 100 rows, and if it takes more than the target * number of calls to finish, increase the number of rows checked on * each call; if it takes less than the target calls to finish, then * decrease the number of rows reviewed on each call (but never less * than 100). */ #define WT_SWEEP_LOOKASIDE_MIN_CNT 100 #define WT_SWEEP_LOOKASIDE_PASS_TARGET 30 ++conn->las_sweep_call; if ((cnt = conn->las_sweep_cnt) < WT_SWEEP_LOOKASIDE_MIN_CNT) cnt = conn->las_sweep_cnt = WT_SWEEP_LOOKASIDE_MIN_CNT; /* Walk the file. */ for (; cnt > 0 && (ret = cursor->next(cursor)) == 0; --cnt) { /* * If the loop terminates after completing a work unit, we will * continue the table sweep next time. Get a local copy of the * sweep key, we're going to reset the cursor; do so before * calling cursor.remove, cursor.remove can discard our hazard * pointer and the page could be evicted from underneath us. */ if (cnt == 1) { WT_ERR(__wt_cursor_get_raw_key(cursor, key)); if (!WT_DATA_IN_ITEM(key)) WT_ERR(__wt_buf_set( session, key, key->data, key->size)); } WT_ERR(cursor->get_key(cursor, &las_id, las_addr, &las_counter, &las_txnid, las_key)); /* * If the on-page record transaction ID associated with the * record is globally visible, the record can be discarded. * * Cursor opened overwrite=true: won't return WT_NOTFOUND should * another thread remove the record before we do, and the cursor * remains positioned in that case. */ if (__wt_txn_visible_all(session, las_txnid)) WT_ERR(cursor->remove(cursor)); } /* * When reaching the lookaside table end or the target number of calls, * adjust the row count. Decrease/increase the row count depending on * if the number of calls is less/more than the target. */ if (ret == WT_NOTFOUND || conn->las_sweep_call > WT_SWEEP_LOOKASIDE_PASS_TARGET) { if (conn->las_sweep_call < WT_SWEEP_LOOKASIDE_PASS_TARGET && conn->las_sweep_cnt > WT_SWEEP_LOOKASIDE_MIN_CNT) conn->las_sweep_cnt -= WT_SWEEP_LOOKASIDE_MIN_CNT; if (conn->las_sweep_call > WT_SWEEP_LOOKASIDE_PASS_TARGET) conn->las_sweep_cnt += WT_SWEEP_LOOKASIDE_MIN_CNT; } srch_notfound: if (ret == WT_NOTFOUND) conn->las_sweep_call = 0; WT_ERR_NOTFOUND_OK(ret); if (0) { err: __wt_buf_free(session, key); } WT_TRET(__wt_las_cursor_close(session, &cursor, session_flags)); __wt_scr_free(session, &las_addr); __wt_scr_free(session, &las_key); 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); }
/* * __txn_rollback_to_stable_lookaside_fixup -- * Remove any updates that need to be rolled back from the lookaside file. */ static int __txn_rollback_to_stable_lookaside_fixup(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; WT_CURSOR *cursor; WT_DECL_RET; WT_DECL_TIMESTAMP(rollback_timestamp) WT_ITEM las_addr, las_key, las_timestamp; WT_TXN_GLOBAL *txn_global; uint64_t las_counter, las_txnid, remove_cnt; uint32_t las_id, session_flags; conn = S2C(session); cursor = NULL; remove_cnt = 0; session_flags = 0; /* [-Werror=maybe-uninitialized] */ WT_CLEAR(las_timestamp); /* * Copy the stable timestamp, otherwise we'd need to lock it each time * it's accessed. Even though the stable timestamp isn't supposed to be * updated while rolling back, accessing it without a lock would * violate protocol. */ txn_global = &S2C(session)->txn_global; __wt_readlock(session, &txn_global->rwlock); __wt_timestamp_set(&rollback_timestamp, &txn_global->stable_timestamp); __wt_readunlock(session, &txn_global->rwlock); __wt_las_cursor(session, &cursor, &session_flags); /* Discard pages we read as soon as we're done with them. */ F_SET(session, WT_SESSION_NO_CACHE); /* Walk the file. */ for (; (ret = cursor->next(cursor)) == 0; ) { WT_ERR(cursor->get_key(cursor, &las_id, &las_addr, &las_counter, &las_txnid, &las_timestamp, &las_key)); /* Check the file ID so we can skip durable tables */ if (__bit_test(conn->stable_rollback_bitstring, las_id)) continue; /* * Entries with no timestamp will have a timestamp of zero, * which will fail the following check and cause them to never * be removed. */ if (__wt_timestamp_cmp( &rollback_timestamp, las_timestamp.data) < 0) { WT_ERR(cursor->remove(cursor)); ++remove_cnt; } } WT_ERR_NOTFOUND_OK(ret); err: WT_TRET(__wt_las_cursor_close(session, &cursor, session_flags)); /* * If there were races to remove records, we can over-count. Underflow * isn't fatal, but check anyway so we don't skew low over time. */ if (remove_cnt > conn->las_record_cnt) conn->las_record_cnt = 0; else if (remove_cnt > 0) (void)__wt_atomic_sub64(&conn->las_record_cnt, remove_cnt); F_CLR(session, WT_SESSION_NO_CACHE); return (ret); }
static void run(CONFIG *cp, int bigkey, size_t bytes) { WT_CONNECTION *conn; WT_SESSION *session; WT_CURSOR *cursor; uint64_t keyno; int ret; void *p; big[bytes - 1] = '\0'; printf(SIZET_FMT "%s%s: %s %s big %s\n", bytes < MEGABYTE ? bytes : (bytes < GIGABYTE ? bytes / MEGABYTE : bytes / GIGABYTE), bytes < MEGABYTE ? "" : (bytes < GIGABYTE ? (bytes % MEGABYTE == 0 ? "" : "+") : (bytes % GIGABYTE == 0 ? "" : "+")), bytes < MEGABYTE ? "B" : (bytes < GIGABYTE ? "MB" : "GB"), cp->uri, cp->config, bigkey ? "key" : "value"); testutil_make_work_dir(home); /* * Open/create the database, connection, session and cursor; set the * cache size large, we don't want to try and evict anything. */ if ((ret = wiredtiger_open( home, NULL, "create,cache_size=10GB", &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION.open_session"); if ((ret = session->create(session, cp->uri, cp->config)) != 0) testutil_die(ret, "WT_SESSION.create: %s %s", cp->uri, cp->config); if ((ret = session->open_cursor(session, cp->uri, NULL, NULL, &cursor)) != 0) testutil_die(ret, "WT_SESSION.open_cursor: %s", cp->uri); /* Set the key/value. */ if (bigkey) cursor->set_key(cursor, big); else if (cp->recno) { keyno = 1; cursor->set_key(cursor, keyno); } else cursor->set_key(cursor, "key001"); cursor->set_value(cursor, big); /* Insert the record (use update, insert discards the key). */ if ((ret = cursor->update(cursor)) != 0) testutil_die(ret, "WT_CURSOR.insert"); /* Retrieve the record and check it. */ if ((ret = cursor->search(cursor)) != 0) testutil_die(ret, "WT_CURSOR.search"); if (bigkey && (ret = cursor->get_key(cursor, &p)) != 0) testutil_die(ret, "WT_CURSOR.get_key"); if ((ret = cursor->get_value(cursor, &p)) != 0) testutil_die(ret, "WT_CURSOR.get_value"); if (memcmp(p, big, bytes) != 0) testutil_die(0, "retrieved big key/value item did not match original"); /* Remove the record. */ if ((ret = cursor->remove(cursor)) != 0) testutil_die(ret, "WT_CURSOR.remove"); if ((ret = conn->close(conn, NULL)) != 0) testutil_die(ret, "WT_CONNECTION.close"); big[bytes - 1] = 'a'; }
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); }