/* * __session_drop -- * WT_SESSION->drop method. */ static int __session_drop(WT_SESSION *wt_session, const char *name, const char *config) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, drop, config, cfg); ret = __wt_schema_drop(session, name, cfg); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_dumpfile -- * WT_SESSION->dumpfile method. */ static int __session_dumpfile(WT_SESSION *wt_session, const char *uri, const char *config) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, dumpfile, config, cfg); ret = __wt_schema_worker(session, uri, cfg, __wt_dumpfile, WT_BTREE_EXCLUSIVE | WT_BTREE_VERIFY); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_sync -- * WT_SESSION->sync method. */ static int __session_sync(WT_SESSION *wt_session, const char *uri, const char *config) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, sync, config, cfg); ret = __wt_schema_worker(session, uri, cfg, __wt_btree_sync, 0); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_rename -- * WT_SESSION->rename method. */ static int __session_rename(WT_SESSION *wt_session, const char *uri, const char *newname, const char *config) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, rename, config, cfg); ret = __wt_schema_rename(session, uri, newname, cfg); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_create -- * WT_SESSION->create method. */ static int __session_create(WT_SESSION *wt_session, const char *name, const char *config) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, create, config, cfg); WT_UNUSED(cfg); WT_ERR(__wt_schema_create(session, name, config)); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_compact_worker -- * Worker function to do the actual compaction call. */ static int __session_compact_worker( WT_SESSION *wt_session, const char *uri, const char *config) { WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, compact, config, cfg); WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_compact, cfg, 0)); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __conn_configure_method -- * WT_CONNECTION.configure_method method. */ static int __conn_configure_method(WT_CONNECTION *wt_conn, const char *method, const char *uri, const char *config, const char *type, const char *check) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_SESSION_IMPL *session; conn = (WT_CONNECTION_IMPL *)wt_conn; CONNECTION_API_CALL_NOCONF(conn, session, configure_method); ret = __wt_configure_method(session, method, uri, config, type, check); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_verify -- * WT_SESSION->verify method. */ static int __session_verify(WT_SESSION *wt_session, const char *uri, const char *config) { WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, verify, config, cfg); WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_verify, cfg, WT_BTREE_EXCLUSIVE | WT_BTREE_VERIFY)); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_drop -- * WT_SESSION->drop method. */ static int __session_drop(WT_SESSION *wt_session, const char *uri, const char *config) { WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, drop, config, cfg); WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_drop(session, uri, cfg)); err: /* Note: drop operations cannot be unrolled (yet?). */ API_END_NOTFOUND_MAP(session, ret); }
/* * __session_rename -- * WT_SESSION->rename method. */ static int __session_rename(WT_SESSION *wt_session, const char *uri, const char *newname, const char *config) { WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, rename, config, cfg); WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_rename(session, uri, newname, cfg)); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __conn_load_extension -- * WT_CONNECTION->load_extension method. */ static int __conn_load_extension( WT_CONNECTION *wt_conn, const char *path, const char *config) { WT_CONFIG_ITEM cval; WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_DLH *dlh; WT_SESSION_IMPL *session; int (*entry)(WT_SESSION *, WT_EXTENSION_API *, const char *); const char *entry_name; dlh = NULL; conn = (WT_CONNECTION_IMPL *)wt_conn; CONNECTION_API_CALL(conn, session, load_extension, config, cfg); entry_name = NULL; WT_ERR(__wt_config_gets(session, cfg, "entry", &cval)); WT_ERR(__wt_strndup(session, cval.str, cval.len, &entry_name)); /* * This assumes the underlying shared libraries are reference counted, * that is, that re-opening a shared library simply increments a ref * count, and closing it simply decrements the ref count, and the last * close discards the reference entirely -- in other words, we do not * check to see if we've already opened this shared library. */ WT_ERR(__wt_dlopen(session, path, &dlh)); WT_ERR(__wt_dlsym(session, dlh, entry_name, &entry)); /* Call the entry function. */ WT_ERR(entry(&session->iface, &__api, config)); /* Link onto the environment's list of open libraries. */ __wt_spin_lock(session, &conn->api_lock); TAILQ_INSERT_TAIL(&conn->dlhqh, dlh, q); __wt_spin_unlock(session, &conn->api_lock); if (0) { err: if (dlh != NULL) WT_TRET(__wt_dlclose(session, dlh)); } __wt_free(session, entry_name); API_END_NOTFOUND_MAP(session, ret); }
/* * __session_create -- * WT_SESSION->create method. */ static int __session_create(WT_SESSION *wt_session, const char *uri, const char *config) { WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, create, config, cfg); WT_UNUSED(cfg); /* Disallow objects in the WiredTiger name space. */ WT_ERR(__wt_schema_name_check(session, uri)); WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_create(session, uri, config)); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __conn_add_extractor -- * WT_CONNECTION->add_extractor method. */ static int __conn_add_extractor(WT_CONNECTION *wt_conn, const char *name, WT_EXTRACTOR *extractor, const char *config) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_SESSION_IMPL *session; WT_UNUSED(name); WT_UNUSED(extractor); ret = ENOTSUP; conn = (WT_CONNECTION_IMPL *)wt_conn; CONNECTION_API_CALL(conn, session, add_extractor, config, cfg); WT_UNUSED(cfg); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_checkpoint -- * WT_SESSION->checkpoint method. */ static int __session_checkpoint(WT_SESSION *wt_session, const char *config) { WT_DECL_RET; WT_SESSION_IMPL *session; WT_TXN *txn; session = (WT_SESSION_IMPL *)wt_session; txn = &session->txn; WT_CSTAT_INCR(session, checkpoint); SESSION_API_CALL(session, checkpoint, config, cfg); /* * Checkpoints require a snapshot to write a transactionally consistent * snapshot of the data. * * We can't use an application's transaction: if it has uncommitted * changes, they will be written in the checkpoint and may appear after * a crash. * * Use a real snapshot transaction: we don't want any chance of the * snapshot being updated during the checkpoint. Eviction is prevented * from evicting anything newer than this because we track the oldest * transaction ID in the system that is not visible to all readers. */ if (F_ISSET(txn, TXN_RUNNING)) WT_ERR_MSG(session, EINVAL, "Checkpoint not permitted in a transaction"); /* * Reset open cursors. * * We do this here explicitly even though it will happen implicitly in * the call to begin_transaction for the checkpoint, in case some * implementation of WT_CURSOR::reset needs the schema lock. */ WT_ERR(__session_reset_cursors(session)); WT_WITH_SCHEMA_LOCK(session, ret = __wt_txn_checkpoint(session, cfg)); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __conn_open_session -- * WT_CONNECTION->open_session method. */ static int __conn_open_session(WT_CONNECTION *wt_conn, WT_EVENT_HANDLER *event_handler, const char *config, WT_SESSION **wt_sessionp) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_SESSION_IMPL *session, *session_ret; conn = (WT_CONNECTION_IMPL *)wt_conn; session_ret = NULL; CONNECTION_API_CALL(conn, session, open_session, config, cfg); WT_UNUSED(cfg); WT_ERR(__wt_open_session(conn, 0, event_handler, config, &session_ret)); *wt_sessionp = &session_ret->iface; err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_open_cursor -- * WT_SESSION->open_cursor method. */ static int __session_open_cursor(WT_SESSION *wt_session, const char *uri, WT_CURSOR *to_dup, const char *config, WT_CURSOR **cursorp) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, open_cursor, config, cfg); if (uri != NULL && to_dup != NULL) WT_ERR_MSG(session, EINVAL, "should be passed either a URI or a cursor, but not both"); if (to_dup != NULL) ret = __wt_cursor_dup(session, to_dup, config, cursorp); else if (WT_PREFIX_MATCH(uri, "colgroup:")) ret = __wt_curfile_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "config:")) ret = __wt_curconfig_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "file:")) ret = __wt_curfile_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "index:")) ret = __wt_curindex_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "statistics:")) ret = __wt_curstat_open(session, uri, cfg, cursorp); else if (WT_PREFIX_MATCH(uri, "table:")) ret = __wt_curtable_open(session, uri, cfg, cursorp); else { __wt_err(session, EINVAL, "Unknown cursor type '%s'", uri); ret = EINVAL; } err: API_END_NOTFOUND_MAP(session, ret); }
/* * __conn_close -- * WT_CONNECTION->close method. */ static int __conn_close(WT_CONNECTION *wt_conn, const char *config) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_NAMED_COLLATOR *ncoll; WT_NAMED_COMPRESSOR *ncomp; WT_NAMED_DATA_SOURCE *ndsrc; WT_SESSION *wt_session; WT_SESSION_IMPL *s, *session; uint32_t i; conn = (WT_CONNECTION_IMPL *)wt_conn; CONNECTION_API_CALL(conn, session, close, config, cfg); WT_UNUSED(cfg); /* * Close open, external sessions. * Additionally, the session's hazard pointer memory isn't discarded * during normal session close because access to it isn't serialized. * Discard it now. Note the loop for the hazard pointer memory, it's * the entire session array, not only the active session count, as the * active session count may be less than the maximum session count. */ for (s = conn->sessions, i = 0; i < conn->session_cnt; ++s, ++i) if (s->active && !F_ISSET(s, WT_SESSION_INTERNAL)) { wt_session = &s->iface; WT_TRET(wt_session->close(wt_session, config)); } for (s = conn->sessions, i = 0; i < conn->session_size; ++s, ++i) if (!F_ISSET(s, WT_SESSION_INTERNAL)) __wt_free(session, s->hazard); /* * Shut down server threads other than the eviction server, which is * needed later to close btree handles. Some of these threads access * btree handles, so take care in ordering shutdown to make sure they * exit before files are closed. */ F_CLR(conn, WT_CONN_SERVER_RUN); WT_TRET(__wt_checkpoint_destroy(conn)); WT_TRET(__wt_statlog_destroy(conn)); /* Clean up open LSM handles. */ WT_ERR(__wt_lsm_cleanup(&conn->iface)); /* Close open btree handles. */ WT_TRET(__wt_conn_btree_discard(conn)); /* Free memory for collators */ while ((ncoll = TAILQ_FIRST(&conn->collqh)) != NULL) __conn_remove_collator(conn, ncoll); /* Free memory for compressors */ while ((ncomp = TAILQ_FIRST(&conn->compqh)) != NULL) __conn_remove_compressor(conn, ncomp); /* Free memory for data sources */ while ((ndsrc = TAILQ_FIRST(&conn->dsrcqh)) != NULL) __conn_remove_data_source(conn, ndsrc); WT_TRET(__wt_connection_close(conn)); /* We no longer have a session, don't try to update it. */ session = NULL; err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_close -- * WT_SESSION->close method. */ static int __session_close(WT_SESSION *wt_session, const char *config) { WT_CONNECTION_IMPL *conn; WT_CURSOR *cursor; WT_DECL_RET; WT_SESSION_IMPL *session; int tret; conn = (WT_CONNECTION_IMPL *)wt_session->connection; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, close, config, cfg); WT_UNUSED(cfg); /* Rollback any active transaction. */ if (F_ISSET(&session->txn, TXN_RUNNING)) WT_TRET(__session_rollback_transaction(wt_session, NULL)); /* Close all open cursors. */ while ((cursor = TAILQ_FIRST(&session->cursors)) != NULL) WT_TRET(cursor->close(cursor)); WT_ASSERT(session, session->ncursors == 0); /* * Acquire the schema lock: we may be closing btree handles. * * Note that in some special cases, the schema may already be locked * (e.g., if this session is an LSM tree worker and the tree is being * dropped). */ WT_WITH_SCHEMA_LOCK_OPT(session, tret = __session_close_cache(session)); WT_TRET(tret); /* Discard metadata tracking. */ __wt_meta_track_discard(session); /* Discard scratch buffers. */ __wt_scr_discard(session); /* Free transaction information. */ __wt_txn_destroy(session); /* Confirm we're not holding any hazard references. */ __wt_hazard_close(session); /* Free the reconciliation information. */ __wt_rec_destroy(session, &session->reconcile); /* Free the eviction exclusive-lock information. */ __wt_free(session, session->excl); /* Destroy the thread's mutex. */ if (session->cond != NULL) (void)__wt_cond_destroy(session, session->cond); /* The API lock protects opening and closing of sessions. */ __wt_spin_lock(session, &conn->api_lock); /* * Sessions are re-used, clear the structure: this code sets the active * field to 0, which will exclude the hazard array from review by the * eviction thread. Note: there's no serialization support around the * review of the hazard array, which means threads checking for hazard * references first check the active field (which may be 0) and then use * the hazard pointer (which cannot be NULL). For this reason, clear * the session structure carefully. * * We don't need to publish here, because regardless of the active field * being non-zero, the hazard reference is always valid. */ WT_SESSION_CLEAR(session); session = conn->default_session; /* * Decrement the count of active sessions if that's possible: a session * being closed may or may not be at the end of the array, step toward * the beginning of the array until we reach an active session. */ while (conn->sessions[conn->session_cnt - 1].active == 0) if (--conn->session_cnt == 0) break; __wt_spin_unlock(session, &conn->api_lock); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_close -- * WT_SESSION->close method. */ static int __session_close(WT_SESSION *wt_session, const char *config) { WT_BTREE_SESSION *btree_session; WT_CONNECTION_IMPL *conn; WT_CURSOR *cursor; WT_SESSION_IMPL *session, **tp; int ret; conn = (WT_CONNECTION_IMPL *)wt_session->connection; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, close, config, cfg); WT_UNUSED(cfg); while ((cursor = TAILQ_FIRST(&session->cursors)) != NULL) WT_TRET(cursor->close(cursor)); while ((btree_session = TAILQ_FIRST(&session->btrees)) != NULL) WT_TRET(__wt_session_remove_btree(session, btree_session, 0)); WT_TRET(__wt_schema_close_tables(session)); __wt_spin_lock(session, &conn->spinlock); /* Discard scratch buffers. */ __wt_scr_discard(session); /* Confirm we're not holding any hazard references. */ __wt_hazard_empty(session); /* Free the reconciliation information. */ __wt_rec_destroy(session); /* Free the eviction exclusive-lock information. */ __wt_free(session, session->excl); /* Destroy the thread's mutex. */ if (session->cond != NULL) (void)__wt_cond_destroy(session, session->cond); /* * Replace the session reference we're closing with the last entry in * the table, then clear the last entry. As far as the walk of the * server threads is concerned, it's OK if the session appears twice, * or if it doesn't appear at all, so these lines can race all they * want. */ for (tp = conn->sessions; *tp != session; ++tp) ; --conn->session_cnt; *tp = conn->sessions[conn->session_cnt]; conn->sessions[conn->session_cnt] = NULL; /* * Publish, making the session array entry available for re-use. There * must be a barrier here to ensure the cleanup above completes before * the entry is re-used. */ WT_PUBLISH(session->iface.connection, NULL); session = &conn->default_session; __wt_spin_unlock(session, &conn->spinlock); err: API_END_NOTFOUND_MAP(session, ret); }
/* * __session_truncate -- * WT_SESSION->truncate method. */ static int __session_truncate(WT_SESSION *wt_session, const char *uri, WT_CURSOR *start, WT_CURSOR *stop, const char *config) { WT_SESSION_IMPL *session; int ret; session = (WT_SESSION_IMPL *)wt_session; SESSION_API_CALL(session, truncate, config, cfg); /* * If the URI is specified, we don't need a start/stop, if start/stop * is specified, we don't need a URI. * * If no URI is specified, and both cursors are specified, start/stop * must reference the same object. * * Any specified cursor must have been initialized. */ if ((uri == NULL && start == NULL && stop == NULL) || (uri != NULL && (start != NULL || stop != NULL))) WT_ERR_MSG(session, EINVAL, "the truncate method should be passed either a URI or " "start/stop cursors, but not both"); if (start != NULL && stop != NULL && strcmp(start->uri, stop->uri) != 0) WT_ERR_MSG(session, EINVAL, "truncate method cursors must reference the same object"); if ((start != NULL && !F_ISSET(start, WT_CURSTD_KEY_SET)) || (stop != NULL && !F_ISSET(stop, WT_CURSTD_KEY_SET))) WT_ERR_MSG(session, EINVAL, "the truncate method cursors must have their keys set"); if (uri == NULL) { /* * From a starting/stopping cursor to the begin/end of the * object is easy, walk the object. */ if (start == NULL) for (;;) { WT_ERR(stop->remove(stop)); if ((ret = stop->prev(stop)) != 0) { if (ret == WT_NOTFOUND) ret = 0; break; } } else for (;;) { WT_ERR(start->remove(start)); if (stop != NULL && start->equals(start, stop)) break; if ((ret = start->next(start)) != 0) { if (ret == WT_NOTFOUND) ret = 0; break; } } } else ret = __wt_schema_truncate(session, uri, cfg); err: API_END_NOTFOUND_MAP(session, ret); }