/* * __session_reconfigure -- * WT_SESSION->reconfigure method. */ static int __session_reconfigure(WT_SESSION *wt_session, const char *config) { WT_CONFIG_ITEM cval; WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, reconfigure, config, cfg); if (F_ISSET(&session->txn, TXN_RUNNING)) WT_ERR_MSG(session, EINVAL, "transaction in progress"); WT_TRET(__session_reset_cursors(session)); WT_ERR(__wt_config_gets_defno(session, cfg, "isolation", &cval)); if (cval.len != 0) { if (!F_ISSET(S2C(session), WT_CONN_TRANSACTIONAL)) WT_ERR_MSG(session, EINVAL, "Database not configured for transactions"); session->isolation = session->txn.isolation = WT_STRING_MATCH("snapshot", cval.str, cval.len) ? TXN_ISO_SNAPSHOT : WT_STRING_MATCH("read-uncommitted", cval.str, cval.len) ? TXN_ISO_READ_UNCOMMITTED : TXN_ISO_READ_COMMITTED; } err: API_END_NOTFOUND_MAP(session, ret); }
/* * __wt_curfile_open -- * WT_SESSION->open_cursor method for the btree cursor type. */ int __wt_curfile_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_CONFIG_ITEM cval; WT_DECL_RET; uint32_t flags; /* * Bulk and no cache handles are exclusive and may not be used by more * than a single thread. * Additionally set the discard flag on no cache handles so they are * destroyed on close. */ flags = 0; WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval)); if (cval.val != 0) LF_SET(WT_BTREE_EXCLUSIVE | WT_BTREE_BULK); WT_RET(__wt_config_gets_defno(session, cfg, "no_cache", &cval)); if (cval.val != 0) LF_SET(WT_BTREE_EXCLUSIVE | WT_BTREE_NO_CACHE); /* TODO: handle projections. */ /* Get the handle and lock it while the cursor is using it. */ if (WT_PREFIX_MATCH(uri, "file:")) WT_RET(__wt_session_get_btree_ckpt(session, uri, cfg, flags)); else WT_RET(__wt_bad_object_type(session, uri)); WT_ERR(__wt_curfile_create(session, owner, cfg, cursorp)); return (0); err: /* If the cursor could not be opened, release the handle. */ (void)__wt_session_release_btree(session); return (ret); }
int __wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_DATA_SOURCE *dsrc; WT_DECL_RET; int force; WT_RET(__wt_config_gets_defno(session, cfg, "force", &cval)); force = (cval.val != 0); /* Disallow drops from the WiredTiger name space. */ WT_RET(__wt_schema_name_check(session, uri)); WT_RET(__wt_meta_track_on(session)); /* Be careful to ignore any btree handle in our caller. */ WT_CLEAR_BTREE_IN_SESSION(session); if (WT_PREFIX_MATCH(uri, "colgroup:")) ret = __drop_colgroup(session, uri, cfg); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __drop_file(session, uri, force, cfg); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __drop_index(session, uri, cfg); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __drop_table(session, uri, force, cfg); else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0) ret = dsrc->drop(dsrc, &session->iface, uri, cfg); /* * Map WT_NOTFOUND to ENOENT (or to 0 if "force" is set), based on the * assumption WT_NOTFOUND means there was no metadata entry. The * underlying drop functions should handle this case (we passed them * the "force" value), but better safe than sorry. */ if (ret == WT_NOTFOUND) ret = force ? 0 : ENOENT; /* Bump the schema generation so that stale data is ignored. */ ++S2C(session)->schema_gen; WT_TRET(__wt_meta_track_off(session, ret != 0)); return (ret); }
/* * __wt_curfile_open -- * WT_SESSION->open_cursor method for the btree cursor type. */ int __wt_curfile_open(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { WT_CONFIG_ITEM cval; WT_DECL_RET; int bitmap, bulk; uint32_t flags; flags = 0; WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval)); if (cval.type == ITEM_NUM && (cval.val == 0 || cval.val == 1)) { bitmap = 0; bulk = (cval.val != 0); } else if (WT_STRING_MATCH("bitmap", cval.str, cval.len)) bitmap = bulk = 1; else WT_RET_MSG(session, EINVAL, "Value for 'bulk' must be a boolean or 'bitmap'"); /* Bulk handles require exclusive access. */ if (bulk) LF_SET(WT_BTREE_BULK | WT_BTREE_EXCLUSIVE); /* TODO: handle projections. */ /* Get the handle and lock it while the cursor is using it. */ if (WT_PREFIX_MATCH(uri, "file:")) WT_RET(__wt_session_get_btree_ckpt(session, uri, cfg, flags)); else WT_RET(__wt_bad_object_type(session, uri)); WT_ERR(__wt_curfile_create(session, owner, cfg, bulk, bitmap, cursorp)); return (0); err: /* If the cursor could not be opened, release the handle. */ WT_TRET(__wt_session_release_btree(session)); return (ret); }
/* * __wt_curfile_create -- * Open a cursor for a given btree handle. */ int __wt_curfile_create(WT_SESSION_IMPL *session, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) { static WT_CURSOR iface = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, __curfile_compare, __curfile_next, __curfile_prev, __curfile_reset, __curfile_search, __curfile_search_near, __curfile_insert, __curfile_update, __curfile_remove, __curfile_close, { NULL, NULL }, /* TAILQ_ENTRY q */ 0, /* recno key */ { 0 }, /* recno raw buffer */ { NULL, 0, 0, NULL, 0 },/* WT_ITEM key */ { NULL, 0, 0, NULL, 0 },/* WT_ITEM value */ 0, /* int saved_err */ 0 /* uint32_t flags */ }; WT_BTREE *btree; WT_CONFIG_ITEM cval; WT_CURSOR *cursor; WT_CURSOR_BTREE *cbt; WT_DECL_RET; size_t csize; int bitmap, bulk; cbt = NULL; btree = session->btree; WT_ASSERT(session, btree != NULL); WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval)); if ((cval.type == ITEM_ID || cval.type == ITEM_STRING) && WT_STRING_MATCH("bitmap", cval.str, cval.len)) bitmap = bulk = 1; else { bitmap = 0; bulk = (cval.val != 0); } csize = bulk ? sizeof(WT_CURSOR_BULK) : sizeof(WT_CURSOR_BTREE); WT_RET(__wt_calloc(session, 1, csize, &cbt)); cursor = &cbt->iface; *cursor = iface; cursor->session = &session->iface; cursor->uri = btree->name; cursor->key_format = btree->key_format; cursor->value_format = btree->value_format; cbt->btree = session->btree; if (bulk) WT_ERR(__wt_curbulk_init((WT_CURSOR_BULK *)cbt, bitmap)); /* * no_cache * No cache cursors are read-only. */ WT_ERR(__wt_config_gets_defno(session, cfg, "no_cache", &cval)); if (cval.val != 0) { cursor->insert = __wt_cursor_notsup; cursor->update = __wt_cursor_notsup; cursor->remove = __wt_cursor_notsup; } /* * random_retrieval * Random retrieval cursors only support next, reset and close. */ WT_ERR(__wt_config_gets_defno(session, cfg, "next_random", &cval)); if (cval.val != 0) { __wt_cursor_set_notsup(cursor); cursor->next = __curfile_next_random; cursor->reset = __curfile_reset; } /* __wt_cursor_init is last so we don't have to clean up on error. */ STATIC_ASSERT(offsetof(WT_CURSOR_BTREE, iface) == 0); WT_ERR(__wt_cursor_init(cursor, cursor->uri, owner, cfg, cursorp)); if (0) { err: __wt_free(session, cbt); } return (ret); }
/* * __wt_txn_begin -- * Begin a transaction. */ int __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[]) { WT_CONFIG_ITEM cval; WT_CONNECTION_IMPL *conn; WT_TXN *txn; WT_TXN_GLOBAL *txn_global; WT_TXN_STATE *s, *txn_state; wt_txnid_t id, oldest_snap_min; uint32_t i, n, session_cnt; conn = S2C(session); txn = &session->txn; txn_global = &conn->txn_global; txn_state = &txn_global->states[session->id]; WT_ASSERT(session, txn_state->id == WT_TXN_NONE); WT_RET(__wt_config_gets_defno(session, cfg, "isolation", &cval)); if (cval.len == 0) txn->isolation = session->isolation; else txn->isolation = WT_STRING_MATCH("snapshot", cval.str, cval.len) ? TXN_ISO_SNAPSHOT : WT_STRING_MATCH("read-committed", cval.str, cval.len) ? TXN_ISO_READ_COMMITTED : TXN_ISO_READ_UNCOMMITTED; F_SET(txn, TXN_RUNNING); do { /* * Allocate a transaction ID. * * We use an atomic increment to ensure that we get a unique * ID, then publish that to the global state table. * * If two threads race to allocate an ID, only the latest ID * will proceed. The winning thread can be sure its snapshot * contains all of the earlier active IDs. Threads that race * and get an earlier ID may not appear in the snapshot, * but they will loop and allocate a new ID before proceeding * to make any updates. * * This potentially wastes transaction IDs when threads race to * begin transactions, but that is the price we pay to keep * this path latch free. */ do { txn->id = WT_ATOMIC_ADD(txn_global->current, 1); } while (txn->id == WT_TXN_NONE || txn->id == WT_TXN_ABORTED); WT_PUBLISH(txn_state->id, txn->id); /* * If we are starting a snapshot isolation transaction, get * a snapshot of the running transactions. * * If we already have a snapshot (e.g., for an auto-commit * operation), update it so that the newly-allocated ID is * visible. */ if (txn->isolation == TXN_ISO_SNAPSHOT) { txn->last_gen = txn->last_oldest_gen = txn_global->gen; oldest_snap_min = txn->id; /* Copy the array of concurrent transactions. */ WT_ORDERED_READ(session_cnt, conn->session_cnt); for (i = n = 0, s = txn_global->states; i < session_cnt; i++, s++) { if ((id = s->snap_min) != WT_TXN_NONE) if (TXNID_LT(id, oldest_snap_min)) oldest_snap_min = id; if ((id = s->id) == WT_TXN_NONE) continue; else txn->snapshot[n++] = id; } __txn_sort_snapshot( session, n, txn->id, oldest_snap_min); txn_state->snap_min = txn->snap_min; } /* * Ensure the snapshot reads are complete before re-checking * the global current ID. */ WT_READ_BARRIER(); } while (txn->id != txn_global->current); return (0); }
/* * __wt_curfile_create -- * Open a cursor for a given btree handle. */ int __wt_curfile_create(WT_SESSION_IMPL *session, WT_CURSOR *owner, const char *cfg[], int bulk, int bitmap, WT_CURSOR **cursorp) { WT_CURSOR_STATIC_INIT(iface, NULL, /* get-key */ NULL, /* get-value */ NULL, /* set-key */ NULL, /* set-value */ __curfile_compare, /* compare */ __curfile_next, /* next */ __curfile_prev, /* prev */ __curfile_reset, /* reset */ __curfile_search, /* search */ __curfile_search_near, /* search-near */ __curfile_insert, /* insert */ __curfile_update, /* update */ __curfile_remove, /* remove */ __curfile_close); /* close */ WT_BTREE *btree; WT_CONFIG_ITEM cval; WT_CURSOR *cursor; WT_CURSOR_BTREE *cbt; WT_DECL_RET; size_t csize; cbt = NULL; btree = session->btree; WT_ASSERT(session, btree != NULL); csize = bulk ? sizeof(WT_CURSOR_BULK) : sizeof(WT_CURSOR_BTREE); WT_RET(__wt_calloc(session, 1, csize, &cbt)); cursor = &cbt->iface; *cursor = iface; cursor->session = &session->iface; cursor->uri = btree->name; cursor->key_format = btree->key_format; cursor->value_format = btree->value_format; cbt->btree = session->btree; if (bulk) WT_ERR(__wt_curbulk_init((WT_CURSOR_BULK *)cbt, bitmap)); /* * random_retrieval * Random retrieval cursors only support next, reset and close. */ WT_ERR(__wt_config_gets_defno(session, cfg, "next_random", &cval)); if (cval.val != 0) { __wt_cursor_set_notsup(cursor); cursor->next = __curfile_next_random; cursor->reset = __curfile_reset; } /* __wt_cursor_init is last so we don't have to clean up on error. */ STATIC_ASSERT(offsetof(WT_CURSOR_BTREE, iface) == 0); WT_ERR(__wt_cursor_init(cursor, cursor->uri, owner, cfg, cursorp)); if (0) { err: __wt_free(session, cbt); } return (ret); }