diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/session/session_api.c')
-rw-r--r-- | src/third_party/wiredtiger/src/session/session_api.c | 3450 |
1 files changed, 1660 insertions, 1790 deletions
diff --git a/src/third_party/wiredtiger/src/session/session_api.c b/src/third_party/wiredtiger/src/session/session_api.c index 86c7a18e4ae..09148db3018 100644 --- a/src/third_party/wiredtiger/src/session/session_api.c +++ b/src/third_party/wiredtiger/src/session/session_api.c @@ -12,2399 +12,2269 @@ static int __session_rollback_transaction(WT_SESSION *, const char *); /* * __wt_session_notsup -- - * Unsupported session method. + * Unsupported session method. */ int __wt_session_notsup(WT_SESSION_IMPL *session) { - WT_RET_MSG(session, ENOTSUP, "Unsupported session method"); + WT_RET_MSG(session, ENOTSUP, "Unsupported session method"); } /* * __wt_session_reset_cursors -- - * Reset all open cursors. + * Reset all open cursors. */ int __wt_session_reset_cursors(WT_SESSION_IMPL *session, bool free_buffers) { - WT_CURSOR *cursor; - WT_DECL_RET; - - TAILQ_FOREACH(cursor, &session->cursors, q) { - /* Stop when there are no positioned cursors. */ - if (session->ncursors == 0) - break; - if (!F_ISSET(cursor, WT_CURSTD_JOINED)) - WT_TRET(cursor->reset(cursor)); - /* Optionally, free the cursor buffers */ - if (free_buffers) { - __wt_buf_free(session, &cursor->key); - __wt_buf_free(session, &cursor->value); - } - } - - WT_ASSERT(session, session->ncursors == 0); - return (ret); + WT_CURSOR *cursor; + WT_DECL_RET; + + TAILQ_FOREACH (cursor, &session->cursors, q) { + /* Stop when there are no positioned cursors. */ + if (session->ncursors == 0) + break; + if (!F_ISSET(cursor, WT_CURSTD_JOINED)) + WT_TRET(cursor->reset(cursor)); + /* Optionally, free the cursor buffers */ + if (free_buffers) { + __wt_buf_free(session, &cursor->key); + __wt_buf_free(session, &cursor->value); + } + } + + WT_ASSERT(session, session->ncursors == 0); + return (ret); } /* * __wt_session_cursor_cache_sweep -- - * Sweep the cursor cache. + * Sweep the cursor cache. */ int __wt_session_cursor_cache_sweep(WT_SESSION_IMPL *session) { - WT_CURSOR *cursor, *cursor_tmp; - WT_CURSOR_LIST *cached_list; - WT_DECL_RET; - uint64_t now; - uint32_t position; - int i, t_ret, nbuckets, nexamined, nclosed; - bool productive; - - if (!F_ISSET(session, WT_SESSION_CACHE_CURSORS)) - return (0); - - /* - * Periodically sweep for dead cursors; if we've swept recently, don't - * do it again. - */ - __wt_seconds(session, &now); - if (now - session->last_cursor_sweep < 1) - return (0); - session->last_cursor_sweep = now; - - position = session->cursor_sweep_position; - productive = true; - nbuckets = nexamined = nclosed = 0; - - /* Turn off caching so that cursor close doesn't try to cache. */ - F_CLR(session, WT_SESSION_CACHE_CURSORS); - for (i = 0; i < WT_SESSION_CURSOR_SWEEP_MAX && productive; i++) { - ++nbuckets; - cached_list = &session->cursor_cache[position]; - position = (position + 1) % WT_HASH_ARRAY_SIZE; - TAILQ_FOREACH_SAFE(cursor, cached_list, q, cursor_tmp) { - /* - * First check to see if the cursor could be reopened. - */ - ++nexamined; - t_ret = cursor->reopen(cursor, true); - if (t_ret != 0) { - WT_TRET_NOTFOUND_OK(t_ret); - WT_TRET_NOTFOUND_OK( - cursor->reopen(cursor, false)); - WT_TRET(cursor->close(cursor)); - ++nclosed; - } - } - - /* - * We continue sweeping as long as we have some good average - * productivity, or we are under the minimum. - */ - productive = (nclosed + WT_SESSION_CURSOR_SWEEP_MIN > i); - } - - session->cursor_sweep_position = position; - F_SET(session, WT_SESSION_CACHE_CURSORS); - - WT_STAT_CONN_INCR(session, cursor_sweep); - WT_STAT_CONN_INCRV(session, cursor_sweep_buckets, nbuckets); - WT_STAT_CONN_INCRV(session, cursor_sweep_examined, nexamined); - WT_STAT_CONN_INCRV(session, cursor_sweep_closed, nclosed); - - return (ret); + WT_CURSOR *cursor, *cursor_tmp; + WT_CURSOR_LIST *cached_list; + WT_DECL_RET; + uint64_t now; + uint32_t position; + int i, t_ret, nbuckets, nexamined, nclosed; + bool productive; + + if (!F_ISSET(session, WT_SESSION_CACHE_CURSORS)) + return (0); + + /* + * Periodically sweep for dead cursors; if we've swept recently, don't do it again. + */ + __wt_seconds(session, &now); + if (now - session->last_cursor_sweep < 1) + return (0); + session->last_cursor_sweep = now; + + position = session->cursor_sweep_position; + productive = true; + nbuckets = nexamined = nclosed = 0; + + /* Turn off caching so that cursor close doesn't try to cache. */ + F_CLR(session, WT_SESSION_CACHE_CURSORS); + for (i = 0; i < WT_SESSION_CURSOR_SWEEP_MAX && productive; i++) { + ++nbuckets; + cached_list = &session->cursor_cache[position]; + position = (position + 1) % WT_HASH_ARRAY_SIZE; + TAILQ_FOREACH_SAFE(cursor, cached_list, q, cursor_tmp) + { + /* + * First check to see if the cursor could be reopened. + */ + ++nexamined; + t_ret = cursor->reopen(cursor, true); + if (t_ret != 0) { + WT_TRET_NOTFOUND_OK(t_ret); + WT_TRET_NOTFOUND_OK(cursor->reopen(cursor, false)); + WT_TRET(cursor->close(cursor)); + ++nclosed; + } + } + + /* + * We continue sweeping as long as we have some good average productivity, or we are under + * the minimum. + */ + productive = (nclosed + WT_SESSION_CURSOR_SWEEP_MIN > i); + } + + session->cursor_sweep_position = position; + F_SET(session, WT_SESSION_CACHE_CURSORS); + + WT_STAT_CONN_INCR(session, cursor_sweep); + WT_STAT_CONN_INCRV(session, cursor_sweep_buckets, nbuckets); + WT_STAT_CONN_INCRV(session, cursor_sweep_examined, nexamined); + WT_STAT_CONN_INCRV(session, cursor_sweep_closed, nclosed); + + return (ret); } /* * __wt_session_copy_values -- - * Copy values into all positioned cursors, so that they don't keep - * transaction IDs pinned. + * Copy values into all positioned cursors, so that they don't keep transaction IDs pinned. */ int __wt_session_copy_values(WT_SESSION_IMPL *session) { - WT_CURSOR *cursor; + WT_CURSOR *cursor; - TAILQ_FOREACH(cursor, &session->cursors, q) - if (F_ISSET(cursor, WT_CURSTD_VALUE_INT)) { + TAILQ_FOREACH (cursor, &session->cursors, q) + if (F_ISSET(cursor, WT_CURSTD_VALUE_INT)) { #ifdef HAVE_DIAGNOSTIC - /* - * We have to do this with a transaction ID pinned - * unless the cursor is reading from a checkpoint. - */ - WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session); - WT_ASSERT(session, - txn_state->pinned_id != WT_TXN_NONE || - (WT_PREFIX_MATCH(cursor->uri, "file:") && - F_ISSET((WT_CURSOR_BTREE *)cursor, WT_CBT_NO_TXN))); + /* + * We have to do this with a transaction ID pinned unless the cursor is reading from a + * checkpoint. + */ + WT_TXN_STATE *txn_state = WT_SESSION_TXN_STATE(session); + WT_ASSERT(session, txn_state->pinned_id != WT_TXN_NONE || + (WT_PREFIX_MATCH(cursor->uri, "file:") && + F_ISSET((WT_CURSOR_BTREE *)cursor, WT_CBT_NO_TXN))); #endif - WT_RET(__cursor_localvalue(cursor)); - } + WT_RET(__cursor_localvalue(cursor)); + } - return (0); + return (0); } /* * __wt_session_release_resources -- - * Release common session resources. + * Release common session resources. */ int __wt_session_release_resources(WT_SESSION_IMPL *session) { - WT_DECL_RET; + WT_DECL_RET; - /* Transaction cleanup */ - __wt_txn_release_resources(session); + /* Transaction cleanup */ + __wt_txn_release_resources(session); - /* Block manager cleanup */ - if (session->block_manager_cleanup != NULL) - WT_TRET(session->block_manager_cleanup(session)); + /* Block manager cleanup */ + if (session->block_manager_cleanup != NULL) + WT_TRET(session->block_manager_cleanup(session)); - /* Reconciliation cleanup */ - if (session->reconcile_cleanup != NULL) - WT_TRET(session->reconcile_cleanup(session)); + /* Reconciliation cleanup */ + if (session->reconcile_cleanup != NULL) + WT_TRET(session->reconcile_cleanup(session)); - /* Stashed memory. */ - __wt_stash_discard(session); + /* Stashed memory. */ + __wt_stash_discard(session); - /* - * Discard scratch buffers, error memory; last, just in case a cleanup - * routine uses scratch buffers. - */ - __wt_scr_discard(session); - __wt_buf_free(session, &session->err); + /* + * Discard scratch buffers, error memory; last, just in case a cleanup routine uses scratch + * buffers. + */ + __wt_scr_discard(session); + __wt_buf_free(session, &session->err); - return (ret); + return (ret); } /* * __session_clear -- - * Clear a session structure. + * Clear a session structure. */ static void __session_clear(WT_SESSION_IMPL *session) { - /* - * There's no serialization support around the review of the hazard - * array, which means threads checking for hazard pointers first check - * the active field (which may be 0) and then use the hazard pointer - * (which cannot be NULL). - * - * Additionally, the session structure can include information that - * persists past the session's end-of-life, stored as part of page - * splits. - * - * For these reasons, be careful when clearing the session structure. - */ - __wt_txn_clear_timestamp_queues(session); - memset(session, 0, WT_SESSION_CLEAR_SIZE); - - WT_INIT_LSN(&session->bg_sync_lsn); - - session->hazard_inuse = 0; - session->nhazard = 0; + /* + * There's no serialization support around the review of the hazard + * array, which means threads checking for hazard pointers first check + * the active field (which may be 0) and then use the hazard pointer + * (which cannot be NULL). + * + * Additionally, the session structure can include information that + * persists past the session's end-of-life, stored as part of page + * splits. + * + * For these reasons, be careful when clearing the session structure. + */ + __wt_txn_clear_timestamp_queues(session); + memset(session, 0, WT_SESSION_CLEAR_SIZE); + + WT_INIT_LSN(&session->bg_sync_lsn); + + session->hazard_inuse = 0; + session->nhazard = 0; } /* * __session_close_cursors -- - * Close all cursors in a list. + * Close all cursors in a list. */ static int __session_close_cursors(WT_SESSION_IMPL *session, WT_CURSOR_LIST *cursors) { - WT_CURSOR *cursor, *cursor_tmp; - WT_DECL_RET; - - /* Close all open cursors. */ - WT_TAILQ_SAFE_REMOVE_BEGIN(cursor, cursors, q, cursor_tmp) { - if (F_ISSET(cursor, WT_CURSTD_CACHED)) - /* - * Put the cached cursor in an open state - * that allows it to be closed. - */ - WT_TRET_NOTFOUND_OK(cursor->reopen(cursor, false)); - else if (session->event_handler->handle_close != NULL && - strcmp(cursor->internal_uri, WT_LAS_URI) != 0) - /* - * Notify the user that we are closing the cursor - * handle via the registered close callback. - */ - WT_TRET(session->event_handler->handle_close( - session->event_handler, &session->iface, cursor)); - - WT_TRET(cursor->close(cursor)); - } WT_TAILQ_SAFE_REMOVE_END - - return (ret); + WT_CURSOR *cursor, *cursor_tmp; + WT_DECL_RET; + + /* Close all open cursors. */ + WT_TAILQ_SAFE_REMOVE_BEGIN(cursor, cursors, q, cursor_tmp) + { + if (F_ISSET(cursor, WT_CURSTD_CACHED)) + /* + * Put the cached cursor in an open state that allows it to be closed. + */ + WT_TRET_NOTFOUND_OK(cursor->reopen(cursor, false)); + else if (session->event_handler->handle_close != NULL && + strcmp(cursor->internal_uri, WT_LAS_URI) != 0) + /* + * Notify the user that we are closing the cursor handle via the registered close + * callback. + */ + WT_TRET(session->event_handler->handle_close( + session->event_handler, &session->iface, cursor)); + + WT_TRET(cursor->close(cursor)); + } + WT_TAILQ_SAFE_REMOVE_END + + return (ret); } /* * __session_close_cached_cursors -- - * Fully close all cached cursors. + * Fully close all cached cursors. */ static int __session_close_cached_cursors(WT_SESSION_IMPL *session) { - WT_DECL_RET; - int i; + WT_DECL_RET; + int i; - for (i = 0; i < WT_HASH_ARRAY_SIZE; i++) - WT_TRET(__session_close_cursors(session, - &session->cursor_cache[i])); - return (ret); + for (i = 0; i < WT_HASH_ARRAY_SIZE; i++) + WT_TRET(__session_close_cursors(session, &session->cursor_cache[i])); + return (ret); } /* * __session_close -- - * WT_SESSION->close method. + * WT_SESSION->close method. */ static int __session_close(WT_SESSION *wt_session, const char *config) { - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - WT_SESSION_IMPL *session; - - conn = (WT_CONNECTION_IMPL *)wt_session->connection; - session = (WT_SESSION_IMPL *)wt_session; - - SESSION_API_CALL_PREPARE_ALLOWED(session, close, config, cfg); - WT_UNUSED(cfg); - - /* Close all open cursors while the cursor cache is disabled. */ - F_CLR(session, WT_SESSION_CACHE_CURSORS); - - /* Rollback any active transaction. */ - if (F_ISSET(&session->txn, WT_TXN_RUNNING)) - WT_TRET(__session_rollback_transaction(wt_session, NULL)); - - /* - * Also release any pinned transaction ID from a non-transactional - * operation. - */ - if (conn->txn_global.states != NULL) - __wt_txn_release_snapshot(session); - - /* Close all open cursors. */ - WT_TRET(__session_close_cursors(session, &session->cursors)); - WT_TRET(__session_close_cached_cursors(session)); - - WT_ASSERT(session, session->ncursors == 0); - - /* Discard cached handles. */ - __wt_session_close_cache(session); - - /* Confirm we're not holding any hazard pointers. */ - __wt_hazard_close(session); - - /* Discard metadata tracking. */ - __wt_meta_track_discard(session); - - /* Free transaction information. */ - __wt_txn_destroy(session); - - /* - * Close the file where we tracked long operations. Do this before - * releasing resources, as we do scratch buffer management when we - * flush optrack buffers to disk. - */ - if (F_ISSET(conn, WT_CONN_OPTRACK)) { - if (session->optrackbuf_ptr > 0) { - __wt_optrack_flush_buffer(session); - WT_TRET(__wt_close(session, &session->optrack_fh)); - } - - /* Free the operation tracking buffer */ - __wt_free(session, session->optrack_buf); - } - - /* Release common session resources. */ - WT_TRET(__wt_session_release_resources(session)); - - /* The API lock protects opening and closing of sessions. */ - __wt_spin_lock(session, &conn->api_lock); - - /* Decrement the count of open sessions. */ - WT_STAT_CONN_DECR(session, session_open); - - /* - * Sessions are re-used, clear the structure: the clear sets the active - * field to 0, which will exclude the hazard array from review by the - * eviction thread. Because some session fields are accessed by other - * threads, the structure must be cleared carefully. - * - * We don't need to publish here, because regardless of the active field - * being non-zero, the hazard pointer is always valid. - */ - __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); - - /* We no longer have a session, don't try to update it. */ - session = NULL; - -err: API_END_RET_NOTFOUND_MAP(session, ret); + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_SESSION_IMPL *session; + + conn = (WT_CONNECTION_IMPL *)wt_session->connection; + session = (WT_SESSION_IMPL *)wt_session; + + SESSION_API_CALL_PREPARE_ALLOWED(session, close, config, cfg); + WT_UNUSED(cfg); + + /* Close all open cursors while the cursor cache is disabled. */ + F_CLR(session, WT_SESSION_CACHE_CURSORS); + + /* Rollback any active transaction. */ + if (F_ISSET(&session->txn, WT_TXN_RUNNING)) + WT_TRET(__session_rollback_transaction(wt_session, NULL)); + + /* + * Also release any pinned transaction ID from a non-transactional operation. + */ + if (conn->txn_global.states != NULL) + __wt_txn_release_snapshot(session); + + /* Close all open cursors. */ + WT_TRET(__session_close_cursors(session, &session->cursors)); + WT_TRET(__session_close_cached_cursors(session)); + + WT_ASSERT(session, session->ncursors == 0); + + /* Discard cached handles. */ + __wt_session_close_cache(session); + + /* Confirm we're not holding any hazard pointers. */ + __wt_hazard_close(session); + + /* Discard metadata tracking. */ + __wt_meta_track_discard(session); + + /* Free transaction information. */ + __wt_txn_destroy(session); + + /* + * Close the file where we tracked long operations. Do this before releasing resources, as we do + * scratch buffer management when we flush optrack buffers to disk. + */ + if (F_ISSET(conn, WT_CONN_OPTRACK)) { + if (session->optrackbuf_ptr > 0) { + __wt_optrack_flush_buffer(session); + WT_TRET(__wt_close(session, &session->optrack_fh)); + } + + /* Free the operation tracking buffer */ + __wt_free(session, session->optrack_buf); + } + + /* Release common session resources. */ + WT_TRET(__wt_session_release_resources(session)); + + /* The API lock protects opening and closing of sessions. */ + __wt_spin_lock(session, &conn->api_lock); + + /* Decrement the count of open sessions. */ + WT_STAT_CONN_DECR(session, session_open); + + /* + * Sessions are re-used, clear the structure: the clear sets the active + * field to 0, which will exclude the hazard array from review by the + * eviction thread. Because some session fields are accessed by other + * threads, the structure must be cleared carefully. + * + * We don't need to publish here, because regardless of the active field + * being non-zero, the hazard pointer is always valid. + */ + __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); + + /* We no longer have a session, don't try to update it. */ + session = NULL; + +err: + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_reconfigure -- - * WT_SESSION->reconfigure method. + * 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; - /* - * Indicated as allowed in prepared state, even though not allowed, - * so that running transaction check below take precedence. - */ - SESSION_API_CALL_PREPARE_ALLOWED(session, reconfigure, config, cfg); - - /* - * Note that this method only checks keys that are passed in by the - * application: we don't want to reset other session settings to their - * default values. - */ - WT_UNUSED(cfg); - - WT_ERR(__wt_txn_context_check(session, false)); - - WT_ERR(__wt_session_reset_cursors(session, false)); - - WT_ERR(__wt_txn_reconfigure(session, config)); - - ret = __wt_config_getones(session, config, "ignore_cache_size", &cval); - if (ret == 0) { - if (cval.val) - F_SET(session, WT_SESSION_IGNORE_CACHE_SIZE); - else - F_CLR(session, WT_SESSION_IGNORE_CACHE_SIZE); - } - WT_ERR_NOTFOUND_OK(ret); - - ret = __wt_config_getones(session, config, "cache_cursors", &cval); - if (ret == 0) { - if (cval.val) - F_SET(session, WT_SESSION_CACHE_CURSORS); - else { - F_CLR(session, WT_SESSION_CACHE_CURSORS); - WT_ERR(__session_close_cached_cursors(session)); - } - } - WT_ERR_NOTFOUND_OK(ret); - -err: API_END_RET_NOTFOUND_MAP(session, ret); + WT_CONFIG_ITEM cval; + WT_DECL_RET; + WT_SESSION_IMPL *session; + + session = (WT_SESSION_IMPL *)wt_session; + /* + * Indicated as allowed in prepared state, even though not allowed, so that running transaction + * check below take precedence. + */ + SESSION_API_CALL_PREPARE_ALLOWED(session, reconfigure, config, cfg); + + /* + * Note that this method only checks keys that are passed in by the application: we don't want + * to reset other session settings to their default values. + */ + WT_UNUSED(cfg); + + WT_ERR(__wt_txn_context_check(session, false)); + + WT_ERR(__wt_session_reset_cursors(session, false)); + + WT_ERR(__wt_txn_reconfigure(session, config)); + + ret = __wt_config_getones(session, config, "ignore_cache_size", &cval); + if (ret == 0) { + if (cval.val) + F_SET(session, WT_SESSION_IGNORE_CACHE_SIZE); + else + F_CLR(session, WT_SESSION_IGNORE_CACHE_SIZE); + } + WT_ERR_NOTFOUND_OK(ret); + + ret = __wt_config_getones(session, config, "cache_cursors", &cval); + if (ret == 0) { + if (cval.val) + F_SET(session, WT_SESSION_CACHE_CURSORS); + else { + F_CLR(session, WT_SESSION_CACHE_CURSORS); + WT_ERR(__session_close_cached_cursors(session)); + } + } + WT_ERR_NOTFOUND_OK(ret); + +err: + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_open_cursor_int -- - * Internal version of WT_SESSION::open_cursor, with second cursor arg. + * Internal version of WT_SESSION::open_cursor, with second cursor arg. */ static int -__session_open_cursor_int(WT_SESSION_IMPL *session, const char *uri, - WT_CURSOR *owner, WT_CURSOR *other, const char *cfg[], WT_CURSOR **cursorp) +__session_open_cursor_int(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, + WT_CURSOR *other, const char *cfg[], WT_CURSOR **cursorp) { - WT_COLGROUP *colgroup; - WT_DATA_SOURCE *dsrc; - WT_DECL_RET; - - *cursorp = NULL; - - /* - * Open specific cursor types we know about, or call the generic data - * source open function. - * - * Unwind a set of string comparisons into a switch statement hoping - * the compiler can make it fast, but list the common choices first - * instead of sorting so if/else patterns are still fast. - */ - switch (uri[0]) { - /* - * Common cursor types. - */ - case 't': - if (WT_PREFIX_MATCH(uri, "table:")) - WT_RET(__wt_curtable_open( - session, uri, owner, cfg, cursorp)); - break; - case 'c': - if (WT_PREFIX_MATCH(uri, "colgroup:")) { - /* - * Column groups are a special case: open a cursor on - * the underlying data source. - */ - WT_RET(__wt_schema_get_colgroup( - session, uri, false, NULL, &colgroup)); - WT_RET(__wt_open_cursor( - session, colgroup->source, owner, cfg, cursorp)); - } else if (WT_PREFIX_MATCH(uri, "config:")) - WT_RET(__wt_curconfig_open( - session, uri, cfg, cursorp)); - break; - case 'i': - if (WT_PREFIX_MATCH(uri, "index:")) - WT_RET(__wt_curindex_open( - session, uri, owner, cfg, cursorp)); - break; - case 'j': - if (WT_PREFIX_MATCH(uri, "join:")) - WT_RET(__wt_curjoin_open( - session, uri, owner, cfg, cursorp)); - break; - case 'l': - if (WT_PREFIX_MATCH(uri, "lsm:")) - WT_RET(__wt_clsm_open( - session, uri, owner, cfg, cursorp)); - else if (WT_PREFIX_MATCH(uri, "log:")) - WT_RET(__wt_curlog_open(session, uri, cfg, cursorp)); - break; - - /* - * Less common cursor types. - */ - case 'f': - if (WT_PREFIX_MATCH(uri, "file:")) - WT_RET(__wt_curfile_open( - session, uri, owner, cfg, cursorp)); - break; - case 'm': - if (WT_PREFIX_MATCH(uri, WT_METADATA_URI)) - WT_RET(__wt_curmetadata_open( - session, uri, owner, cfg, cursorp)); - break; - case 'b': - if (WT_PREFIX_MATCH(uri, "backup:")) - WT_RET(__wt_curbackup_open( - session, uri, other, cfg, cursorp)); - break; - case 's': - if (WT_PREFIX_MATCH(uri, "statistics:")) - WT_RET(__wt_curstat_open(session, uri, other, cfg, - cursorp)); - break; - default: - break; - } - - if (*cursorp == NULL && - (dsrc = __wt_schema_get_source(session, uri)) != NULL) - WT_RET(dsrc->open_cursor == NULL ? - __wt_object_unsupported(session, uri) : - __wt_curds_open(session, uri, owner, cfg, dsrc, cursorp)); - - if (*cursorp == NULL) - return (__wt_bad_object_type(session, uri)); - - if (owner != NULL) { - /* - * We support caching simple cursors that have no - * children. If this cursor is a child, we're not going - * to cache this child or its parent. - */ - F_CLR(owner, WT_CURSTD_CACHEABLE); - F_CLR(*cursorp, WT_CURSTD_CACHEABLE); - } - - /* - * When opening simple tables, the table code calls this function on the - * underlying data source, in which case the application's URI has been - * copied. - */ - if ((*cursorp)->uri == NULL && - (ret = __wt_strdup(session, uri, &(*cursorp)->uri)) != 0) { - WT_TRET((*cursorp)->close(*cursorp)); - *cursorp = NULL; - } - - return (ret); + WT_COLGROUP *colgroup; + WT_DATA_SOURCE *dsrc; + WT_DECL_RET; + + *cursorp = NULL; + + /* + * Open specific cursor types we know about, or call the generic data + * source open function. + * + * Unwind a set of string comparisons into a switch statement hoping + * the compiler can make it fast, but list the common choices first + * instead of sorting so if/else patterns are still fast. + */ + switch (uri[0]) { + /* + * Common cursor types. + */ + case 't': + if (WT_PREFIX_MATCH(uri, "table:")) + WT_RET(__wt_curtable_open(session, uri, owner, cfg, cursorp)); + break; + case 'c': + if (WT_PREFIX_MATCH(uri, "colgroup:")) { + /* + * Column groups are a special case: open a cursor on the underlying data source. + */ + WT_RET(__wt_schema_get_colgroup(session, uri, false, NULL, &colgroup)); + WT_RET(__wt_open_cursor(session, colgroup->source, owner, cfg, cursorp)); + } else if (WT_PREFIX_MATCH(uri, "config:")) + WT_RET(__wt_curconfig_open(session, uri, cfg, cursorp)); + break; + case 'i': + if (WT_PREFIX_MATCH(uri, "index:")) + WT_RET(__wt_curindex_open(session, uri, owner, cfg, cursorp)); + break; + case 'j': + if (WT_PREFIX_MATCH(uri, "join:")) + WT_RET(__wt_curjoin_open(session, uri, owner, cfg, cursorp)); + break; + case 'l': + if (WT_PREFIX_MATCH(uri, "lsm:")) + WT_RET(__wt_clsm_open(session, uri, owner, cfg, cursorp)); + else if (WT_PREFIX_MATCH(uri, "log:")) + WT_RET(__wt_curlog_open(session, uri, cfg, cursorp)); + break; + + /* + * Less common cursor types. + */ + case 'f': + if (WT_PREFIX_MATCH(uri, "file:")) + WT_RET(__wt_curfile_open(session, uri, owner, cfg, cursorp)); + break; + case 'm': + if (WT_PREFIX_MATCH(uri, WT_METADATA_URI)) + WT_RET(__wt_curmetadata_open(session, uri, owner, cfg, cursorp)); + break; + case 'b': + if (WT_PREFIX_MATCH(uri, "backup:")) + WT_RET(__wt_curbackup_open(session, uri, other, cfg, cursorp)); + break; + case 's': + if (WT_PREFIX_MATCH(uri, "statistics:")) + WT_RET(__wt_curstat_open(session, uri, other, cfg, cursorp)); + break; + default: + break; + } + + if (*cursorp == NULL && (dsrc = __wt_schema_get_source(session, uri)) != NULL) + WT_RET(dsrc->open_cursor == NULL ? + __wt_object_unsupported(session, uri) : + __wt_curds_open(session, uri, owner, cfg, dsrc, cursorp)); + + if (*cursorp == NULL) + return (__wt_bad_object_type(session, uri)); + + if (owner != NULL) { + /* + * We support caching simple cursors that have no children. If this cursor is a child, we're + * not going to cache this child or its parent. + */ + F_CLR(owner, WT_CURSTD_CACHEABLE); + F_CLR(*cursorp, WT_CURSTD_CACHEABLE); + } + + /* + * When opening simple tables, the table code calls this function on the underlying data source, + * in which case the application's URI has been copied. + */ + if ((*cursorp)->uri == NULL && (ret = __wt_strdup(session, uri, &(*cursorp)->uri)) != 0) { + WT_TRET((*cursorp)->close(*cursorp)); + *cursorp = NULL; + } + + return (ret); } /* * __wt_open_cursor -- - * Internal version of WT_SESSION::open_cursor. + * Internal version of WT_SESSION::open_cursor. */ int -__wt_open_cursor(WT_SESSION_IMPL *session, - const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) +__wt_open_cursor(WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *owner, const char *cfg[], + WT_CURSOR **cursorp) { - WT_DECL_RET; - - /* We do not cache any subordinate tables/files cursors. */ - if (owner == NULL) { - if ((ret = __wt_cursor_cache_get( - session, uri, NULL, cfg, cursorp)) == 0) - return (0); - WT_RET_NOTFOUND_OK(ret); - } - - return (__session_open_cursor_int(session, uri, owner, NULL, cfg, - cursorp)); + WT_DECL_RET; + + /* We do not cache any subordinate tables/files cursors. */ + if (owner == NULL) { + if ((ret = __wt_cursor_cache_get(session, uri, NULL, cfg, cursorp)) == 0) + return (0); + WT_RET_NOTFOUND_OK(ret); + } + + return (__session_open_cursor_int(session, uri, owner, NULL, cfg, cursorp)); } /* * __session_open_cursor -- - * WT_SESSION->open_cursor method. + * 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) +__session_open_cursor(WT_SESSION *wt_session, const char *uri, WT_CURSOR *to_dup, + const char *config, WT_CURSOR **cursorp) { - WT_CURSOR *cursor; - WT_DECL_RET; - WT_SESSION_IMPL *session; - bool dup_backup, statjoin; - - cursor = *cursorp = NULL; - - dup_backup = false; - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, open_cursor, config, cfg); - - statjoin = (to_dup != NULL && uri != NULL && - strcmp(uri, "statistics:join") == 0); - if (!statjoin) { - if ((to_dup == NULL && uri == NULL) || - (to_dup != NULL && uri != NULL)) - WT_ERR_MSG(session, EINVAL, - "should be passed either a URI or a cursor to " - "duplicate, but not both"); - - if ((ret = __wt_cursor_cache_get( - session, uri, to_dup, cfg, &cursor)) == 0) - goto done; - - /* - * Detect if we're duplicating a backup cursor specifically. - * That needs special handling. - */ - if (to_dup != NULL && strcmp(to_dup->uri, "backup:") == 0) - dup_backup = true; - WT_ERR_NOTFOUND_OK(ret); - - if (to_dup != NULL) { - uri = to_dup->uri; - if (!WT_PREFIX_MATCH(uri, "backup:") && - !WT_PREFIX_MATCH(uri, "colgroup:") && - !WT_PREFIX_MATCH(uri, "index:") && - !WT_PREFIX_MATCH(uri, "file:") && - !WT_PREFIX_MATCH(uri, "lsm:") && - !WT_PREFIX_MATCH(uri, WT_METADATA_URI) && - !WT_PREFIX_MATCH(uri, "table:") && - __wt_schema_get_source(session, uri) == NULL) - WT_ERR(__wt_bad_object_type(session, uri)); - } - } - - WT_ERR(__session_open_cursor_int(session, uri, NULL, - statjoin || dup_backup ? to_dup : NULL, cfg, &cursor)); + WT_CURSOR *cursor; + WT_DECL_RET; + WT_SESSION_IMPL *session; + bool dup_backup, statjoin; + + cursor = *cursorp = NULL; + + dup_backup = false; + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL(session, open_cursor, config, cfg); + + statjoin = (to_dup != NULL && uri != NULL && strcmp(uri, "statistics:join") == 0); + if (!statjoin) { + if ((to_dup == NULL && uri == NULL) || (to_dup != NULL && uri != NULL)) + WT_ERR_MSG(session, EINVAL, + "should be passed either a URI or a cursor to " + "duplicate, but not both"); + + if ((ret = __wt_cursor_cache_get(session, uri, to_dup, cfg, &cursor)) == 0) + goto done; + + /* + * Detect if we're duplicating a backup cursor specifically. That needs special handling. + */ + if (to_dup != NULL && strcmp(to_dup->uri, "backup:") == 0) + dup_backup = true; + WT_ERR_NOTFOUND_OK(ret); + + if (to_dup != NULL) { + uri = to_dup->uri; + if (!WT_PREFIX_MATCH(uri, "backup:") && !WT_PREFIX_MATCH(uri, "colgroup:") && + !WT_PREFIX_MATCH(uri, "index:") && !WT_PREFIX_MATCH(uri, "file:") && + !WT_PREFIX_MATCH(uri, "lsm:") && !WT_PREFIX_MATCH(uri, WT_METADATA_URI) && + !WT_PREFIX_MATCH(uri, "table:") && __wt_schema_get_source(session, uri) == NULL) + WT_ERR(__wt_bad_object_type(session, uri)); + } + } + + WT_ERR(__session_open_cursor_int( + session, uri, NULL, statjoin || dup_backup ? to_dup : NULL, cfg, &cursor)); done: - if (to_dup != NULL && !statjoin && !dup_backup) - WT_ERR(__wt_cursor_dup_position(to_dup, cursor)); - - *cursorp = cursor; - - if (0) { -err: if (cursor != NULL) - WT_TRET(cursor->close(cursor)); - } - /* - * Opening a cursor on a non-existent data source will set ret to - * either of ENOENT or WT_NOTFOUND at this point. However, - * applications may reasonably do this inside a transaction to check - * for the existence of a table or index. - * - * Failure in opening a cursor should not set an error on the - * transaction and WT_NOTFOUND will be mapped to ENOENT. - */ - - API_END_RET_NO_TXN_ERROR(session, ret); + if (to_dup != NULL && !statjoin && !dup_backup) + WT_ERR(__wt_cursor_dup_position(to_dup, cursor)); + + *cursorp = cursor; + + if (0) { +err: + if (cursor != NULL) + WT_TRET(cursor->close(cursor)); + } + /* + * Opening a cursor on a non-existent data source will set ret to + * either of ENOENT or WT_NOTFOUND at this point. However, + * applications may reasonably do this inside a transaction to check + * for the existence of a table or index. + * + * Failure in opening a cursor should not set an error on the + * transaction and WT_NOTFOUND will be mapped to ENOENT. + */ + + API_END_RET_NO_TXN_ERROR(session, ret); } /* * __session_alter -- - * Alter a table setting. + * Alter a table setting. */ static int __session_alter(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, alter, config, cfg); + SESSION_API_CALL(session, alter, config, cfg); - /* In-memory ignores alter operations. */ - if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY)) - goto err; + /* In-memory ignores alter operations. */ + if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY)) + goto err; - /* Disallow objects in the WiredTiger name space. */ - WT_ERR(__wt_str_name_check(session, uri)); + /* Disallow objects in the WiredTiger name space. */ + WT_ERR(__wt_str_name_check(session, uri)); - /* - * We replace the default configuration listing with the current - * configuration. Otherwise the defaults for values that can be - * altered would override settings used by the user in create. - */ - cfg[0] = cfg[1]; - cfg[1] = NULL; - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - ret = __wt_schema_alter(session, uri, cfg))); + /* + * We replace the default configuration listing with the current configuration. Otherwise the + * defaults for values that can be altered would override settings used by the user in create. + */ + cfg[0] = cfg[1]; + cfg[1] = NULL; + WT_WITH_CHECKPOINT_LOCK( + session, WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_alter(session, uri, cfg))); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_alter_fail); - else - WT_STAT_CONN_INCR(session, session_table_alter_success); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_alter_fail); + else + WT_STAT_CONN_INCR(session, session_table_alter_success); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_alter_readonly -- - * WT_SESSION->alter method; readonly version. + * WT_SESSION->alter method; readonly version. */ static int -__session_alter_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_alter_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, alter); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, alter); - WT_STAT_CONN_INCR(session, session_table_alter_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_alter_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __wt_session_create -- - * Internal version of WT_SESSION::create. + * Internal version of WT_SESSION::create. */ int -__wt_session_create( - WT_SESSION_IMPL *session, const char *uri, const char *config) +__wt_session_create(WT_SESSION_IMPL *session, const char *uri, const char *config) { - WT_DECL_RET; + WT_DECL_RET; - WT_WITH_SCHEMA_LOCK(session, - WT_WITH_TABLE_WRITE_LOCK(session, - ret = __wt_schema_create(session, uri, config))); - return (ret); + WT_WITH_SCHEMA_LOCK( + session, WT_WITH_TABLE_WRITE_LOCK(session, ret = __wt_schema_create(session, uri, config))); + return (ret); } /* * __session_create -- - * WT_SESSION->create method. + * WT_SESSION->create method. */ static int __session_create(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_CONFIG_ITEM cval; - 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_str_name_check(session, uri)); - - /* - * Type configuration only applies to tables, column groups and indexes. - * We don't want applications to attempt to layer LSM on top of their - * extended data-sources, and the fact we allow LSM as a valid URI is an - * invitation to that mistake: nip it in the bud. - */ - if (!WT_PREFIX_MATCH(uri, "colgroup:") && - !WT_PREFIX_MATCH(uri, "index:") && - !WT_PREFIX_MATCH(uri, "table:")) { - /* - * We can't disallow type entirely, a configuration string might - * innocently include it, for example, a dump/load pair. If the - * underlying type is "file", it's OK ("file" is the underlying - * type for every type); if the URI type prefix and the type are - * the same, let it go. - */ - if ((ret = - __wt_config_getones(session, config, "type", &cval)) == 0 && - !WT_STRING_MATCH("file", cval.str, cval.len) && - (strncmp(uri, cval.str, cval.len) != 0 || - uri[cval.len] != ':')) - WT_ERR_MSG(session, EINVAL, - "%s: unsupported type configuration", uri); - WT_ERR_NOTFOUND_OK(ret); - } - - ret = __wt_session_create(session, uri, config); + WT_CONFIG_ITEM cval; + 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_str_name_check(session, uri)); + + /* + * Type configuration only applies to tables, column groups and indexes. We don't want + * applications to attempt to layer LSM on top of their extended data-sources, and the fact we + * allow LSM as a valid URI is an invitation to that mistake: nip it in the bud. + */ + if (!WT_PREFIX_MATCH(uri, "colgroup:") && !WT_PREFIX_MATCH(uri, "index:") && + !WT_PREFIX_MATCH(uri, "table:")) { + /* + * We can't disallow type entirely, a configuration string might innocently include it, for + * example, a dump/load pair. If the underlying type is "file", it's OK ("file" is the + * underlying type for every type); if the URI type prefix and the type are the same, let it + * go. + */ + if ((ret = __wt_config_getones(session, config, "type", &cval)) == 0 && + !WT_STRING_MATCH("file", cval.str, cval.len) && + (strncmp(uri, cval.str, cval.len) != 0 || uri[cval.len] != ':')) + WT_ERR_MSG(session, EINVAL, "%s: unsupported type configuration", uri); + WT_ERR_NOTFOUND_OK(ret); + } + + ret = __wt_session_create(session, uri, config); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_create_fail); - else - WT_STAT_CONN_INCR(session, session_table_create_success); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_create_fail); + else + WT_STAT_CONN_INCR(session, session_table_create_success); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_create_readonly -- - * WT_SESSION->create method; readonly version. + * WT_SESSION->create method; readonly version. */ static int -__session_create_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_create_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, create); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, create); - WT_STAT_CONN_INCR(session, session_table_create_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_create_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_log_flush -- - * WT_SESSION->log_flush method. + * WT_SESSION->log_flush method. */ static int __session_log_flush(WT_SESSION *wt_session, const char *config) { - WT_CONFIG_ITEM cval; - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - WT_SESSION_IMPL *session; - uint32_t flags; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, log_flush, config, cfg); - WT_STAT_CONN_INCR(session, log_flush); - - conn = S2C(session); - flags = 0; - /* - * If logging is not enabled there is nothing to do. - */ - if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) - WT_ERR_MSG(session, EINVAL, "logging not enabled"); - - WT_ERR(__wt_config_gets_def(session, cfg, "sync", 0, &cval)); - if (WT_STRING_MATCH("background", cval.str, cval.len)) - flags = WT_LOG_BACKGROUND; - else if (WT_STRING_MATCH("off", cval.str, cval.len)) - flags = WT_LOG_FLUSH; - else if (WT_STRING_MATCH("on", cval.str, cval.len)) - flags = WT_LOG_FSYNC; - ret = __wt_log_flush(session, flags); - -err: API_END_RET(session, ret); + WT_CONFIG_ITEM cval; + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_SESSION_IMPL *session; + uint32_t flags; + + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL(session, log_flush, config, cfg); + WT_STAT_CONN_INCR(session, log_flush); + + conn = S2C(session); + flags = 0; + /* + * If logging is not enabled there is nothing to do. + */ + if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) + WT_ERR_MSG(session, EINVAL, "logging not enabled"); + + WT_ERR(__wt_config_gets_def(session, cfg, "sync", 0, &cval)); + if (WT_STRING_MATCH("background", cval.str, cval.len)) + flags = WT_LOG_BACKGROUND; + else if (WT_STRING_MATCH("off", cval.str, cval.len)) + flags = WT_LOG_FLUSH; + else if (WT_STRING_MATCH("on", cval.str, cval.len)) + flags = WT_LOG_FSYNC; + ret = __wt_log_flush(session, flags); + +err: + API_END_RET(session, ret); } /* * __session_log_flush_readonly -- - * WT_SESSION->log_flush method; readonly version. + * WT_SESSION->log_flush method; readonly version. */ static int __session_log_flush_readonly(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(config); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, log_flush); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, log_flush); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_log_printf -- - * WT_SESSION->log_printf method. + * WT_SESSION->log_printf method. */ static int __session_log_printf(WT_SESSION *wt_session, const char *fmt, ...) - WT_GCC_FUNC_ATTRIBUTE((format (printf, 2, 3))) + WT_GCC_FUNC_ATTRIBUTE((format(printf, 2, 3))) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - va_list ap; + WT_DECL_RET; + WT_SESSION_IMPL *session; + va_list ap; - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF_PREPARE_NOT_ALLOWED(session, log_printf); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF_PREPARE_NOT_ALLOWED(session, log_printf); - va_start(ap, fmt); - ret = __wt_log_vprintf(session, fmt, ap); - va_end(ap); + va_start(ap, fmt); + ret = __wt_log_vprintf(session, fmt, ap); + va_end(ap); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __session_log_printf_readonly -- - * WT_SESSION->log_printf method; readonly version. + * WT_SESSION->log_printf method; readonly version. */ static int __session_log_printf_readonly(WT_SESSION *wt_session, const char *fmt, ...) - WT_GCC_FUNC_ATTRIBUTE((format (printf, 2, 3))) + WT_GCC_FUNC_ATTRIBUTE((format(printf, 2, 3))) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(fmt); + WT_UNUSED(fmt); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, log_printf); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, log_printf); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_rebalance -- - * WT_SESSION->rebalance method. + * WT_SESSION->rebalance method. */ static int __session_rebalance(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, rebalance, config, cfg); + SESSION_API_CALL(session, rebalance, config, cfg); - /* In-memory ignores rebalance operations. */ - if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY)) - goto err; + /* In-memory ignores rebalance operations. */ + if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY)) + goto err; - /* Block out checkpoints to avoid spurious EBUSY errors. */ - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - ret = __wt_schema_worker(session, uri, __wt_bt_rebalance, - NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_REBALANCE))); + /* Block out checkpoints to avoid spurious EBUSY errors. */ + WT_WITH_CHECKPOINT_LOCK(session, + WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_bt_rebalance, NULL, + cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_REBALANCE))); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_rebalance_fail); - else - WT_STAT_CONN_INCR(session, session_table_rebalance_success); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_rebalance_fail); + else + WT_STAT_CONN_INCR(session, session_table_rebalance_success); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_rebalance_readonly -- - * WT_SESSION->rebalance method; readonly version. + * WT_SESSION->rebalance method; readonly version. */ static int -__session_rebalance_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_rebalance_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, rebalance); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, rebalance); - WT_STAT_CONN_INCR(session, session_table_rebalance_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_rebalance_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_rename -- - * WT_SESSION->rename method. + * WT_SESSION->rename method. */ static int -__session_rename(WT_SESSION *wt_session, - const char *uri, const char *newuri, const char *config) +__session_rename(WT_SESSION *wt_session, const char *uri, const char *newuri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, rename, config, cfg); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL(session, rename, config, cfg); - /* Disallow objects in the WiredTiger name space. */ - WT_ERR(__wt_str_name_check(session, uri)); - WT_ERR(__wt_str_name_check(session, newuri)); + /* Disallow objects in the WiredTiger name space. */ + WT_ERR(__wt_str_name_check(session, uri)); + WT_ERR(__wt_str_name_check(session, newuri)); - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - WT_WITH_TABLE_WRITE_LOCK(session, - ret = __wt_schema_rename(session, uri, newuri, cfg)))); + WT_WITH_CHECKPOINT_LOCK(session, + WT_WITH_SCHEMA_LOCK(session, WT_WITH_TABLE_WRITE_LOCK(session, + ret = __wt_schema_rename(session, uri, newuri, cfg)))); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_rename_fail); - else - WT_STAT_CONN_INCR(session, session_table_rename_success); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_rename_fail); + else + WT_STAT_CONN_INCR(session, session_table_rename_success); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_rename_readonly -- - * WT_SESSION->rename method; readonly version. + * WT_SESSION->rename method; readonly version. */ static int -__session_rename_readonly(WT_SESSION *wt_session, - const char *uri, const char *newuri, const char *config) +__session_rename_readonly( + WT_SESSION *wt_session, const char *uri, const char *newuri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(newuri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(newuri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, rename); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, rename); - WT_STAT_CONN_INCR(session, session_table_rename_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_rename_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_reset -- - * WT_SESSION->reset method. + * WT_SESSION->reset method. */ static int __session_reset(WT_SESSION *wt_session) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, reset); + SESSION_API_CALL_NOCONF(session, reset); - WT_ERR(__wt_txn_context_check(session, false)); + WT_ERR(__wt_txn_context_check(session, false)); - WT_TRET(__wt_session_reset_cursors(session, true)); + WT_TRET(__wt_session_reset_cursors(session, true)); - if (--session->cursor_sweep_countdown == 0) { - session->cursor_sweep_countdown = - WT_SESSION_CURSOR_SWEEP_COUNTDOWN; - WT_TRET(__wt_session_cursor_cache_sweep(session)); - } + if (--session->cursor_sweep_countdown == 0) { + session->cursor_sweep_countdown = WT_SESSION_CURSOR_SWEEP_COUNTDOWN; + WT_TRET(__wt_session_cursor_cache_sweep(session)); + } - /* Release common session resources. */ - WT_TRET(__wt_session_release_resources(session)); + /* Release common session resources. */ + WT_TRET(__wt_session_release_resources(session)); - /* Reset the session statistics. */ - if (WT_STAT_ENABLED(session)) - __wt_stat_session_clear_single(&session->stats); + /* Reset the session statistics. */ + if (WT_STAT_ENABLED(session)) + __wt_stat_session_clear_single(&session->stats); -err: API_END_RET_NOTFOUND_MAP(session, ret); +err: + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_drop -- - * WT_SESSION->drop method. + * WT_SESSION->drop method. */ static int __session_drop(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_CONFIG_ITEM cval; - WT_DECL_RET; - WT_SESSION_IMPL *session; - bool checkpoint_wait, lock_wait; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, drop, config, cfg); - - /* Disallow objects in the WiredTiger name space. */ - WT_ERR(__wt_str_name_check(session, uri)); - - WT_ERR(__wt_config_gets_def(session, cfg, "checkpoint_wait", 1, &cval)); - checkpoint_wait = cval.val != 0; - WT_ERR(__wt_config_gets_def(session, cfg, "lock_wait", 1, &cval)); - lock_wait = cval.val != 0; - - /* - * Take the checkpoint lock if there is a need to prevent the drop - * operation from failing with EBUSY due to an ongoing checkpoint. - */ - if (checkpoint_wait) { - if (lock_wait) - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - WT_WITH_TABLE_WRITE_LOCK(session, ret = - __wt_schema_drop(session, uri, cfg)))); - else - WT_WITH_CHECKPOINT_LOCK_NOWAIT(session, ret, - WT_WITH_SCHEMA_LOCK_NOWAIT(session, ret, - WT_WITH_TABLE_WRITE_LOCK_NOWAIT(session, ret, - ret = - __wt_schema_drop(session, uri, cfg)))); - } else { - if (lock_wait) - WT_WITH_SCHEMA_LOCK(session, - WT_WITH_TABLE_WRITE_LOCK(session, - ret = __wt_schema_drop(session, uri, cfg))); - else - WT_WITH_SCHEMA_LOCK_NOWAIT(session, ret, - WT_WITH_TABLE_WRITE_LOCK_NOWAIT(session, ret, - ret = __wt_schema_drop(session, uri, cfg))); - } + WT_CONFIG_ITEM cval; + WT_DECL_RET; + WT_SESSION_IMPL *session; + bool checkpoint_wait, lock_wait; + + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL(session, drop, config, cfg); + + /* Disallow objects in the WiredTiger name space. */ + WT_ERR(__wt_str_name_check(session, uri)); + + WT_ERR(__wt_config_gets_def(session, cfg, "checkpoint_wait", 1, &cval)); + checkpoint_wait = cval.val != 0; + WT_ERR(__wt_config_gets_def(session, cfg, "lock_wait", 1, &cval)); + lock_wait = cval.val != 0; + + /* + * Take the checkpoint lock if there is a need to prevent the drop operation from failing with + * EBUSY due to an ongoing checkpoint. + */ + if (checkpoint_wait) { + if (lock_wait) + WT_WITH_CHECKPOINT_LOCK( + session, WT_WITH_SCHEMA_LOCK(session, WT_WITH_TABLE_WRITE_LOCK(session, + ret = __wt_schema_drop(session, uri, cfg)))); + else + WT_WITH_CHECKPOINT_LOCK_NOWAIT( + session, ret, WT_WITH_SCHEMA_LOCK_NOWAIT( + session, ret, WT_WITH_TABLE_WRITE_LOCK_NOWAIT(session, ret, + ret = __wt_schema_drop(session, uri, cfg)))); + } else { + if (lock_wait) + WT_WITH_SCHEMA_LOCK(session, + WT_WITH_TABLE_WRITE_LOCK(session, ret = __wt_schema_drop(session, uri, cfg))); + else + WT_WITH_SCHEMA_LOCK_NOWAIT(session, ret, WT_WITH_TABLE_WRITE_LOCK_NOWAIT(session, ret, + ret = __wt_schema_drop(session, uri, cfg))); + } err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_drop_fail); - else - WT_STAT_CONN_INCR(session, session_table_drop_success); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_drop_fail); + else + WT_STAT_CONN_INCR(session, session_table_drop_success); - /* Note: drop operations cannot be unrolled (yet?). */ - API_END_RET_NOTFOUND_MAP(session, ret); + /* Note: drop operations cannot be unrolled (yet?). */ + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_drop_readonly -- - * WT_SESSION->drop method; readonly version. + * WT_SESSION->drop method; readonly version. */ static int -__session_drop_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_drop_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, drop); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, drop); - WT_STAT_CONN_INCR(session, session_table_drop_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_drop_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_import -- - * WT_SESSION->import method. + * WT_SESSION->import method. */ static int __session_import(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - char *value; + WT_DECL_RET; + WT_SESSION_IMPL *session; + char *value; - WT_UNUSED(config); + WT_UNUSED(config); - value = NULL; + value = NULL; - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, import); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, import); - WT_ERR(__wt_inmem_unsupported_op(session, NULL)); + WT_ERR(__wt_inmem_unsupported_op(session, NULL)); - if (!WT_PREFIX_MATCH(uri, "file:")) - WT_ERR(__wt_bad_object_type(session, uri)); + if (!WT_PREFIX_MATCH(uri, "file:")) + WT_ERR(__wt_bad_object_type(session, uri)); - if ((ret = __wt_metadata_search(session, uri, &value)) == 0) - WT_ERR_MSG(session, EINVAL, - "an object named \"%s\" already exists in the database", - uri); - WT_ERR_NOTFOUND_OK(ret); + if ((ret = __wt_metadata_search(session, uri, &value)) == 0) + WT_ERR_MSG(session, EINVAL, "an object named \"%s\" already exists in the database", uri); + WT_ERR_NOTFOUND_OK(ret); - WT_ERR(__wt_import(session, uri)); + WT_ERR(__wt_import(session, uri)); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_import_fail); - else - WT_STAT_CONN_INCR(session, session_table_import_success); - __wt_free(session, value); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_import_fail); + else + WT_STAT_CONN_INCR(session, session_table_import_success); + __wt_free(session, value); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_import_readonly -- - * WT_SESSION->import method; readonly version. + * WT_SESSION->import method; readonly version. */ static int -__session_import_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_import_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, import); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, import); - WT_STAT_CONN_INCR(session, session_table_import_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_import_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_join -- - * WT_SESSION->join method. + * WT_SESSION->join method. */ static int -__session_join(WT_SESSION *wt_session, WT_CURSOR *join_cursor, - WT_CURSOR *ref_cursor, const char *config) +__session_join( + WT_SESSION *wt_session, WT_CURSOR *join_cursor, WT_CURSOR *ref_cursor, const char *config) { - WT_CONFIG_ITEM cval; - WT_CURSOR *firstcg; - WT_CURSOR_INDEX *cindex; - WT_CURSOR_JOIN *cjoin; - WT_CURSOR_TABLE *ctable; - WT_DECL_RET; - WT_INDEX *idx; - WT_SESSION_IMPL *session; - WT_TABLE *table; - uint64_t count; - uint32_t bloom_bit_count, bloom_hash_count; - uint8_t flags, range; - bool nested; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, join, config, cfg); - - firstcg = NULL; - table = NULL; - nested = false; - count = 0; - - if (!WT_PREFIX_MATCH(join_cursor->uri, "join:")) - WT_ERR_MSG(session, EINVAL, "not a join cursor"); - - if (WT_PREFIX_MATCH(ref_cursor->uri, "index:")) { - cindex = (WT_CURSOR_INDEX *)ref_cursor; - idx = cindex->index; - table = cindex->table; - firstcg = cindex->cg_cursors[0]; - } else if (WT_PREFIX_MATCH(ref_cursor->uri, "table:")) { - idx = NULL; - ctable = (WT_CURSOR_TABLE *)ref_cursor; - table = ctable->table; - firstcg = ctable->cg_cursors[0]; - } else if (WT_PREFIX_MATCH(ref_cursor->uri, "join:")) { - idx = NULL; - table = ((WT_CURSOR_JOIN *)ref_cursor)->table; - nested = true; - } else - WT_ERR_MSG(session, EINVAL, - "ref_cursor must be an index, table or join cursor"); - - if (firstcg != NULL && !F_ISSET(firstcg, WT_CURSTD_KEY_SET)) - WT_ERR_MSG(session, EINVAL, - "requires reference cursor be positioned"); - cjoin = (WT_CURSOR_JOIN *)join_cursor; - if (cjoin->table != table) - WT_ERR_MSG(session, EINVAL, - "table for join cursor does not match table for " - "ref_cursor"); - if (F_ISSET(ref_cursor, WT_CURSTD_JOINED)) - WT_ERR_MSG(session, EINVAL, "cursor already used in a join"); - - /* "ge" is the default */ - range = WT_CURJOIN_END_GT | WT_CURJOIN_END_EQ; - flags = 0; - WT_ERR(__wt_config_gets(session, cfg, "compare", &cval)); - if (cval.len != 0) { - if (WT_STRING_MATCH("gt", cval.str, cval.len)) - range = WT_CURJOIN_END_GT; - else if (WT_STRING_MATCH("lt", cval.str, cval.len)) - range = WT_CURJOIN_END_LT; - else if (WT_STRING_MATCH("le", cval.str, cval.len)) - range = WT_CURJOIN_END_LE; - else if (WT_STRING_MATCH("eq", cval.str, cval.len)) - range = WT_CURJOIN_END_EQ; - else if (!WT_STRING_MATCH("ge", cval.str, cval.len)) - WT_ERR_MSG(session, EINVAL, - "compare=%.*s not supported", - (int)cval.len, cval.str); - } - WT_ERR(__wt_config_gets(session, cfg, "count", &cval)); - if (cval.len != 0) - count = (uint64_t)cval.val; - - WT_ERR(__wt_config_gets(session, cfg, "strategy", &cval)); - if (cval.len != 0) { - if (WT_STRING_MATCH("bloom", cval.str, cval.len)) - LF_SET(WT_CURJOIN_ENTRY_BLOOM); - else if (!WT_STRING_MATCH("default", cval.str, cval.len)) - WT_ERR_MSG(session, EINVAL, - "strategy=%.*s not supported", - (int)cval.len, cval.str); - } - WT_ERR(__wt_config_gets(session, cfg, "bloom_bit_count", &cval)); - if ((uint64_t)cval.val > UINT32_MAX) - WT_ERR_MSG(session, EINVAL, "bloom_bit_count: value too large"); - bloom_bit_count = (uint32_t)cval.val; - WT_ERR(__wt_config_gets(session, cfg, "bloom_hash_count", &cval)); - if ((uint64_t)cval.val > UINT32_MAX) - WT_ERR_MSG(session, EINVAL, - "bloom_hash_count: value too large"); - bloom_hash_count = (uint32_t)cval.val; - if (LF_ISSET(WT_CURJOIN_ENTRY_BLOOM) && count == 0) - WT_ERR_MSG(session, EINVAL, - "count must be nonzero when strategy=bloom"); - WT_ERR(__wt_config_gets_def( - session, cfg, "bloom_false_positives", 0, &cval)); - if (cval.val != 0) - LF_SET(WT_CURJOIN_ENTRY_FALSE_POSITIVES); - - WT_ERR(__wt_config_gets(session, cfg, "operation", &cval)); - if (cval.len != 0 && WT_STRING_MATCH("or", cval.str, cval.len)) - LF_SET(WT_CURJOIN_ENTRY_DISJUNCTION); - - if (nested && (count != 0 || range != WT_CURJOIN_END_EQ || - LF_ISSET(WT_CURJOIN_ENTRY_BLOOM))) - WT_ERR_MSG(session, EINVAL, - "joining a nested join cursor is incompatible with " - "setting \"strategy\", \"compare\" or \"count\""); - - WT_ERR(__wt_curjoin_join(session, cjoin, idx, ref_cursor, flags, - range, count, bloom_bit_count, bloom_hash_count)); - /* - * There's an implied ownership ordering that isn't - * known when the cursors are created: the join cursor - * must be closed before any of the indices. Enforce - * that here by reordering. - */ - if (TAILQ_FIRST(&session->cursors) != join_cursor) { - TAILQ_REMOVE(&session->cursors, join_cursor, q); - TAILQ_INSERT_HEAD(&session->cursors, join_cursor, q); - } - /* Disable the reference cursor for regular operations */ - F_SET(ref_cursor, WT_CURSTD_JOINED); - -err: API_END_RET_NOTFOUND_MAP(session, ret); + WT_CONFIG_ITEM cval; + WT_CURSOR *firstcg; + WT_CURSOR_INDEX *cindex; + WT_CURSOR_JOIN *cjoin; + WT_CURSOR_TABLE *ctable; + WT_DECL_RET; + WT_INDEX *idx; + WT_SESSION_IMPL *session; + WT_TABLE *table; + uint64_t count; + uint32_t bloom_bit_count, bloom_hash_count; + uint8_t flags, range; + bool nested; + + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL(session, join, config, cfg); + + firstcg = NULL; + table = NULL; + nested = false; + count = 0; + + if (!WT_PREFIX_MATCH(join_cursor->uri, "join:")) + WT_ERR_MSG(session, EINVAL, "not a join cursor"); + + if (WT_PREFIX_MATCH(ref_cursor->uri, "index:")) { + cindex = (WT_CURSOR_INDEX *)ref_cursor; + idx = cindex->index; + table = cindex->table; + firstcg = cindex->cg_cursors[0]; + } else if (WT_PREFIX_MATCH(ref_cursor->uri, "table:")) { + idx = NULL; + ctable = (WT_CURSOR_TABLE *)ref_cursor; + table = ctable->table; + firstcg = ctable->cg_cursors[0]; + } else if (WT_PREFIX_MATCH(ref_cursor->uri, "join:")) { + idx = NULL; + table = ((WT_CURSOR_JOIN *)ref_cursor)->table; + nested = true; + } else + WT_ERR_MSG(session, EINVAL, "ref_cursor must be an index, table or join cursor"); + + if (firstcg != NULL && !F_ISSET(firstcg, WT_CURSTD_KEY_SET)) + WT_ERR_MSG(session, EINVAL, "requires reference cursor be positioned"); + cjoin = (WT_CURSOR_JOIN *)join_cursor; + if (cjoin->table != table) + WT_ERR_MSG(session, EINVAL, + "table for join cursor does not match table for " + "ref_cursor"); + if (F_ISSET(ref_cursor, WT_CURSTD_JOINED)) + WT_ERR_MSG(session, EINVAL, "cursor already used in a join"); + + /* "ge" is the default */ + range = WT_CURJOIN_END_GT | WT_CURJOIN_END_EQ; + flags = 0; + WT_ERR(__wt_config_gets(session, cfg, "compare", &cval)); + if (cval.len != 0) { + if (WT_STRING_MATCH("gt", cval.str, cval.len)) + range = WT_CURJOIN_END_GT; + else if (WT_STRING_MATCH("lt", cval.str, cval.len)) + range = WT_CURJOIN_END_LT; + else if (WT_STRING_MATCH("le", cval.str, cval.len)) + range = WT_CURJOIN_END_LE; + else if (WT_STRING_MATCH("eq", cval.str, cval.len)) + range = WT_CURJOIN_END_EQ; + else if (!WT_STRING_MATCH("ge", cval.str, cval.len)) + WT_ERR_MSG(session, EINVAL, "compare=%.*s not supported", (int)cval.len, cval.str); + } + WT_ERR(__wt_config_gets(session, cfg, "count", &cval)); + if (cval.len != 0) + count = (uint64_t)cval.val; + + WT_ERR(__wt_config_gets(session, cfg, "strategy", &cval)); + if (cval.len != 0) { + if (WT_STRING_MATCH("bloom", cval.str, cval.len)) + LF_SET(WT_CURJOIN_ENTRY_BLOOM); + else if (!WT_STRING_MATCH("default", cval.str, cval.len)) + WT_ERR_MSG(session, EINVAL, "strategy=%.*s not supported", (int)cval.len, cval.str); + } + WT_ERR(__wt_config_gets(session, cfg, "bloom_bit_count", &cval)); + if ((uint64_t)cval.val > UINT32_MAX) + WT_ERR_MSG(session, EINVAL, "bloom_bit_count: value too large"); + bloom_bit_count = (uint32_t)cval.val; + WT_ERR(__wt_config_gets(session, cfg, "bloom_hash_count", &cval)); + if ((uint64_t)cval.val > UINT32_MAX) + WT_ERR_MSG(session, EINVAL, "bloom_hash_count: value too large"); + bloom_hash_count = (uint32_t)cval.val; + if (LF_ISSET(WT_CURJOIN_ENTRY_BLOOM) && count == 0) + WT_ERR_MSG(session, EINVAL, "count must be nonzero when strategy=bloom"); + WT_ERR(__wt_config_gets_def(session, cfg, "bloom_false_positives", 0, &cval)); + if (cval.val != 0) + LF_SET(WT_CURJOIN_ENTRY_FALSE_POSITIVES); + + WT_ERR(__wt_config_gets(session, cfg, "operation", &cval)); + if (cval.len != 0 && WT_STRING_MATCH("or", cval.str, cval.len)) + LF_SET(WT_CURJOIN_ENTRY_DISJUNCTION); + + if (nested && (count != 0 || range != WT_CURJOIN_END_EQ || LF_ISSET(WT_CURJOIN_ENTRY_BLOOM))) + WT_ERR_MSG(session, EINVAL, + "joining a nested join cursor is incompatible with " + "setting \"strategy\", \"compare\" or \"count\""); + + WT_ERR(__wt_curjoin_join( + session, cjoin, idx, ref_cursor, flags, range, count, bloom_bit_count, bloom_hash_count)); + /* + * There's an implied ownership ordering that isn't known when the cursors are created: the join + * cursor must be closed before any of the indices. Enforce that here by reordering. + */ + if (TAILQ_FIRST(&session->cursors) != join_cursor) { + TAILQ_REMOVE(&session->cursors, join_cursor, q); + TAILQ_INSERT_HEAD(&session->cursors, join_cursor, q); + } + /* Disable the reference cursor for regular operations */ + F_SET(ref_cursor, WT_CURSTD_JOINED); + +err: + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_salvage -- - * WT_SESSION->salvage method. + * WT_SESSION->salvage method. */ static int __session_salvage(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, salvage, config, cfg); + SESSION_API_CALL(session, salvage, config, cfg); - WT_ERR(__wt_inmem_unsupported_op(session, NULL)); + WT_ERR(__wt_inmem_unsupported_op(session, NULL)); - /* Block out checkpoints to avoid spurious EBUSY errors. */ - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - ret = __wt_schema_worker(session, uri, __wt_salvage, - NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_SALVAGE))); + /* Block out checkpoints to avoid spurious EBUSY errors. */ + WT_WITH_CHECKPOINT_LOCK( + session, WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_salvage, + NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_SALVAGE))); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_salvage_fail); - else - WT_STAT_CONN_INCR(session, session_table_salvage_success); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_salvage_fail); + else + WT_STAT_CONN_INCR(session, session_table_salvage_success); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_salvage_readonly -- - * WT_SESSION->salvage method; readonly version. + * WT_SESSION->salvage method; readonly version. */ static int -__session_salvage_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_salvage_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, salvage); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, salvage); - WT_STAT_CONN_INCR(session, session_table_salvage_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_salvage_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __wt_session_range_truncate -- - * Session handling of a range truncate. + * Session handling of a range truncate. */ int -__wt_session_range_truncate(WT_SESSION_IMPL *session, - const char *uri, WT_CURSOR *start, WT_CURSOR *stop) +__wt_session_range_truncate( + WT_SESSION_IMPL *session, const char *uri, WT_CURSOR *start, WT_CURSOR *stop) { - WT_DECL_RET; - int cmp; - bool local_start; - - local_start = false; - if (uri != NULL) { - WT_ASSERT(session, WT_PREFIX_MATCH(uri, "file:")); - /* - * A URI file truncate becomes a range truncate where we - * set a start cursor at the beginning. We already - * know the NULL stop goes to the end of the range. - */ - WT_ERR(__session_open_cursor( - (WT_SESSION *)session, uri, NULL, NULL, &start)); - local_start = true; - ret = start->next(start); - if (ret == WT_NOTFOUND) { - /* - * If there are no elements, there is nothing - * to do. - */ - ret = 0; - goto done; - } - WT_ERR(ret); - } - - /* - * Cursor truncate is only supported for some objects, check for a - * supporting compare method. - */ - if (start != NULL && start->compare == NULL) - WT_ERR(__wt_bad_object_type(session, start->uri)); - if (stop != NULL && stop->compare == NULL) - WT_ERR(__wt_bad_object_type(session, stop->uri)); - - /* - * If both cursors set, check they're correctly ordered with respect to - * each other. We have to test this before any search, the search can - * change the initial cursor position. - * - * Rather happily, the compare routine will also confirm the cursors - * reference the same object and the keys are set. - * - * The test for a NULL start comparison function isn't necessary (we - * checked it above), but it quiets clang static analysis complaints. - */ - if (start != NULL && stop != NULL && start->compare != NULL) { - WT_ERR(start->compare(start, stop, &cmp)); - if (cmp > 0) - WT_ERR_MSG(session, EINVAL, - "the start cursor position is after the stop " - "cursor position"); - } - - /* - * Truncate does not require keys actually exist so that applications - * can discard parts of the object's name space without knowing exactly - * what records currently appear in the object. For this reason, do a - * search-near, rather than a search. Additionally, we have to correct - * after calling search-near, to position the start/stop cursors on the - * next record greater than/less than the original key. If we fail to - * find a key in a search-near, there are no keys in the table. If we - * fail to move forward or backward in a range, there are no keys in - * the range. In either of those cases, we're done. - */ - if (start != NULL) - if ((ret = start->search_near(start, &cmp)) != 0 || - (cmp < 0 && (ret = start->next(start)) != 0)) { - WT_ERR_NOTFOUND_OK(ret); - goto done; - } - if (stop != NULL) - if ((ret = stop->search_near(stop, &cmp)) != 0 || - (cmp > 0 && (ret = stop->prev(stop)) != 0)) { - WT_ERR_NOTFOUND_OK(ret); - goto done; - } - - /* - * We always truncate in the forward direction because the underlying - * data structures can move through pages faster forward than backward. - * If we don't have a start cursor, create one and position it at the - * first record. - * - * If start is NULL, stop must not be NULL, but static analyzers have - * a hard time with that, test explicitly. - */ - if (start == NULL && stop != NULL) { - WT_ERR(__session_open_cursor( - (WT_SESSION *)session, stop->uri, NULL, NULL, &start)); - local_start = true; - WT_ERR(start->next(start)); - } - - /* - * If the start/stop keys cross, we're done, the range must be empty. - */ - if (stop != NULL) { - WT_ERR(start->compare(start, stop, &cmp)); - if (cmp > 0) - goto done; - } - - WT_ERR(__wt_schema_range_truncate(session, start, stop)); + WT_DECL_RET; + int cmp; + bool local_start; + + local_start = false; + if (uri != NULL) { + WT_ASSERT(session, WT_PREFIX_MATCH(uri, "file:")); + /* + * A URI file truncate becomes a range truncate where we set a start cursor at the + * beginning. We already know the NULL stop goes to the end of the range. + */ + WT_ERR(__session_open_cursor((WT_SESSION *)session, uri, NULL, NULL, &start)); + local_start = true; + ret = start->next(start); + if (ret == WT_NOTFOUND) { + /* + * If there are no elements, there is nothing to do. + */ + ret = 0; + goto done; + } + WT_ERR(ret); + } + + /* + * Cursor truncate is only supported for some objects, check for a supporting compare method. + */ + if (start != NULL && start->compare == NULL) + WT_ERR(__wt_bad_object_type(session, start->uri)); + if (stop != NULL && stop->compare == NULL) + WT_ERR(__wt_bad_object_type(session, stop->uri)); + + /* + * If both cursors set, check they're correctly ordered with respect to + * each other. We have to test this before any search, the search can + * change the initial cursor position. + * + * Rather happily, the compare routine will also confirm the cursors + * reference the same object and the keys are set. + * + * The test for a NULL start comparison function isn't necessary (we + * checked it above), but it quiets clang static analysis complaints. + */ + if (start != NULL && stop != NULL && start->compare != NULL) { + WT_ERR(start->compare(start, stop, &cmp)); + if (cmp > 0) + WT_ERR_MSG(session, EINVAL, + "the start cursor position is after the stop " + "cursor position"); + } + + /* + * Truncate does not require keys actually exist so that applications can discard parts of the + * object's name space without knowing exactly what records currently appear in the object. For + * this reason, do a search-near, rather than a search. Additionally, we have to correct after + * calling search-near, to position the start/stop cursors on the next record greater than/less + * than the original key. If we fail to find a key in a search-near, there are no keys in the + * table. If we fail to move forward or backward in a range, there are no keys in the range. In + * either of those cases, we're done. + */ + if (start != NULL) + if ((ret = start->search_near(start, &cmp)) != 0 || + (cmp < 0 && (ret = start->next(start)) != 0)) { + WT_ERR_NOTFOUND_OK(ret); + goto done; + } + if (stop != NULL) + if ((ret = stop->search_near(stop, &cmp)) != 0 || + (cmp > 0 && (ret = stop->prev(stop)) != 0)) { + WT_ERR_NOTFOUND_OK(ret); + goto done; + } + + /* + * We always truncate in the forward direction because the underlying + * data structures can move through pages faster forward than backward. + * If we don't have a start cursor, create one and position it at the + * first record. + * + * If start is NULL, stop must not be NULL, but static analyzers have + * a hard time with that, test explicitly. + */ + if (start == NULL && stop != NULL) { + WT_ERR(__session_open_cursor((WT_SESSION *)session, stop->uri, NULL, NULL, &start)); + local_start = true; + WT_ERR(start->next(start)); + } + + /* + * If the start/stop keys cross, we're done, the range must be empty. + */ + if (stop != NULL) { + WT_ERR(start->compare(start, stop, &cmp)); + if (cmp > 0) + goto done; + } + + WT_ERR(__wt_schema_range_truncate(session, start, stop)); done: err: - /* - * Close any locally-opened start cursor. - * - * Reset application cursors, they've possibly moved and the - * application cannot use them. Note that we can make it here with a - * NULL start cursor (e.g., if the truncate range is empty). - */ - if (local_start) - WT_TRET(start->close(start)); - else if (start != NULL) - WT_TRET(start->reset(start)); - if (stop != NULL) - WT_TRET(stop->reset(stop)); - return (ret); + /* + * Close any locally-opened start cursor. + * + * Reset application cursors, they've possibly moved and the + * application cannot use them. Note that we can make it here with a + * NULL start cursor (e.g., if the truncate range is empty). + */ + if (local_start) + WT_TRET(start->close(start)); + else if (start != NULL) + WT_TRET(start->reset(start)); + if (stop != NULL) + WT_TRET(stop->reset(stop)); + return (ret); } /* * __session_truncate -- - * WT_SESSION->truncate method. + * WT_SESSION->truncate method. */ static int -__session_truncate(WT_SESSION *wt_session, - const char *uri, WT_CURSOR *start, WT_CURSOR *stop, const char *config) +__session_truncate( + WT_SESSION *wt_session, const char *uri, WT_CURSOR *start, WT_CURSOR *stop, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_TXN_API_CALL(session, truncate, config, cfg); - WT_STAT_CONN_INCR(session, cursor_truncate); - - /* - * If the URI is specified, we don't need a start/stop, if start/stop - * is specified, we don't need a URI. One exception is the log URI - * which may truncate (archive) log files for a backup cursor. - * - * 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 && !WT_PREFIX_MATCH(uri, "log:") && - (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 (uri != NULL) { - /* Disallow objects in the WiredTiger name space. */ - WT_ERR(__wt_str_name_check(session, uri)); - - if (WT_PREFIX_MATCH(uri, "log:")) { - /* - * Verify the user only gave the URI prefix and not - * a specific target name after that. - */ - if (strcmp(uri, "log:") != 0) - WT_ERR_MSG(session, EINVAL, - "the truncate method should not specify any" - "target after the log: URI prefix"); - WT_ERR(__wt_log_truncate_files(session, start, false)); - } else if (WT_PREFIX_MATCH(uri, "file:")) - WT_ERR(__wt_session_range_truncate( - session, uri, start, stop)); - else - /* Wait for checkpoints to avoid EBUSY errors. */ - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - ret = __wt_schema_truncate(session, uri, cfg))); - } else - WT_ERR(__wt_session_range_truncate(session, uri, start, stop)); - -err: TXN_API_END_RETRY(session, ret, 0); - - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_truncate_fail); - else - WT_STAT_CONN_INCR(session, session_table_truncate_success); - /* - * Only map WT_NOTFOUND to ENOENT if a URI was specified. - */ - return (ret == WT_NOTFOUND && uri != NULL ? ENOENT : ret); + WT_DECL_RET; + WT_SESSION_IMPL *session; + + session = (WT_SESSION_IMPL *)wt_session; + SESSION_TXN_API_CALL(session, truncate, config, cfg); + WT_STAT_CONN_INCR(session, cursor_truncate); + + /* + * If the URI is specified, we don't need a start/stop, if start/stop + * is specified, we don't need a URI. One exception is the log URI + * which may truncate (archive) log files for a backup cursor. + * + * 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 && !WT_PREFIX_MATCH(uri, "log:") && (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 (uri != NULL) { + /* Disallow objects in the WiredTiger name space. */ + WT_ERR(__wt_str_name_check(session, uri)); + + if (WT_PREFIX_MATCH(uri, "log:")) { + /* + * Verify the user only gave the URI prefix and not a specific target name after that. + */ + if (strcmp(uri, "log:") != 0) + WT_ERR_MSG(session, EINVAL, + "the truncate method should not specify any" + "target after the log: URI prefix"); + WT_ERR(__wt_log_truncate_files(session, start, false)); + } else if (WT_PREFIX_MATCH(uri, "file:")) + WT_ERR(__wt_session_range_truncate(session, uri, start, stop)); + else + /* Wait for checkpoints to avoid EBUSY errors. */ + WT_WITH_CHECKPOINT_LOCK( + session, WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_truncate(session, uri, cfg))); + } else + WT_ERR(__wt_session_range_truncate(session, uri, start, stop)); + +err: + TXN_API_END_RETRY(session, ret, 0); + + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_truncate_fail); + else + WT_STAT_CONN_INCR(session, session_table_truncate_success); + /* + * Only map WT_NOTFOUND to ENOENT if a URI was specified. + */ + return (ret == WT_NOTFOUND && uri != NULL ? ENOENT : ret); } /* * __session_truncate_readonly -- - * WT_SESSION->truncate method; readonly version. + * WT_SESSION->truncate method; readonly version. */ static int -__session_truncate_readonly(WT_SESSION *wt_session, - const char *uri, WT_CURSOR *start, WT_CURSOR *stop, const char *config) +__session_truncate_readonly( + WT_SESSION *wt_session, const char *uri, WT_CURSOR *start, WT_CURSOR *stop, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(start); - WT_UNUSED(stop); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(start); + WT_UNUSED(stop); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, truncate); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, truncate); - WT_STAT_CONN_INCR(session, session_table_truncate_fail); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + WT_STAT_CONN_INCR(session, session_table_truncate_fail); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_upgrade -- - * WT_SESSION->upgrade method. + * WT_SESSION->upgrade method. */ static int __session_upgrade(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, upgrade, config, cfg); + SESSION_API_CALL(session, upgrade, config, cfg); - WT_ERR(__wt_inmem_unsupported_op(session, NULL)); + WT_ERR(__wt_inmem_unsupported_op(session, NULL)); - /* Block out checkpoints to avoid spurious EBUSY errors. */ - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - ret = __wt_schema_worker(session, uri, __wt_upgrade, - NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_UPGRADE))); + /* Block out checkpoints to avoid spurious EBUSY errors. */ + WT_WITH_CHECKPOINT_LOCK( + session, WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_upgrade, + NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_UPGRADE))); -err: API_END_RET_NOTFOUND_MAP(session, ret); +err: + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_upgrade_readonly -- - * WT_SESSION->upgrade method; readonly version. + * WT_SESSION->upgrade method; readonly version. */ static int -__session_upgrade_readonly( - WT_SESSION *wt_session, const char *uri, const char *config) +__session_upgrade_readonly(WT_SESSION *wt_session, const char *uri, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(uri); - WT_UNUSED(config); + WT_UNUSED(uri); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, upgrade); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, upgrade); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_verify -- - * WT_SESSION->verify method. + * 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; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, verify, config, cfg); + SESSION_API_CALL(session, verify, config, cfg); - WT_ERR(__wt_inmem_unsupported_op(session, NULL)); + WT_ERR(__wt_inmem_unsupported_op(session, NULL)); - /* Block out checkpoints to avoid spurious EBUSY errors. */ - WT_WITH_CHECKPOINT_LOCK(session, - WT_WITH_SCHEMA_LOCK(session, - ret = __wt_schema_worker(session, uri, __wt_verify, - NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_VERIFY))); + /* Block out checkpoints to avoid spurious EBUSY errors. */ + WT_WITH_CHECKPOINT_LOCK( + session, WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_worker(session, uri, __wt_verify, + NULL, cfg, WT_DHANDLE_EXCLUSIVE | WT_BTREE_VERIFY))); err: - if (ret != 0) - WT_STAT_CONN_INCR(session, session_table_verify_fail); - else - WT_STAT_CONN_INCR(session, session_table_verify_success); - API_END_RET_NOTFOUND_MAP(session, ret); + if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_verify_fail); + else + WT_STAT_CONN_INCR(session, session_table_verify_success); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_begin_transaction -- - * WT_SESSION->begin_transaction method. + * WT_SESSION->begin_transaction method. */ static int __session_begin_transaction(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; - /* - * Indicated as allowed in prepared state, even though not allowed, - * so that running transaction check below take precedence. - */ - SESSION_API_CALL_PREPARE_ALLOWED( - session, begin_transaction, config, cfg); - WT_STAT_CONN_INCR(session, txn_begin); + session = (WT_SESSION_IMPL *)wt_session; + /* + * Indicated as allowed in prepared state, even though not allowed, so that running transaction + * check below take precedence. + */ + SESSION_API_CALL_PREPARE_ALLOWED(session, begin_transaction, config, cfg); + WT_STAT_CONN_INCR(session, txn_begin); - WT_ERR(__wt_txn_context_check(session, false)); + WT_ERR(__wt_txn_context_check(session, false)); - ret = __wt_txn_begin(session, cfg); + ret = __wt_txn_begin(session, cfg); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __session_commit_transaction -- - * WT_SESSION->commit_transaction method. + * WT_SESSION->commit_transaction method. */ static int __session_commit_transaction(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - WT_TXN *txn; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_PREPARE_ALLOWED( - session, commit_transaction, config, cfg); - WT_STAT_CONN_INCR(session, txn_commit); - - txn = &session->txn; - if (F_ISSET(txn, WT_TXN_PREPARE)) { - WT_STAT_CONN_INCR(session, txn_prepare_commit); - WT_STAT_CONN_DECR(session, txn_prepare_active); - } - - WT_ERR(__wt_txn_context_check(session, true)); - - if (F_ISSET(txn, WT_TXN_ERROR) && txn->mod_count != 0) - WT_ERR_MSG(session, EINVAL, - "failed transaction requires rollback%s%s", - txn->rollback_reason == NULL ? "" : ": ", - txn->rollback_reason == NULL ? "" : txn->rollback_reason); - - if (ret == 0) - ret = __wt_txn_commit(session, cfg); - else { - WT_TRET(__wt_session_reset_cursors(session, false)); - WT_TRET(__wt_txn_rollback(session, cfg)); - } - -err: API_END_RET(session, ret); + WT_DECL_RET; + WT_SESSION_IMPL *session; + WT_TXN *txn; + + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_PREPARE_ALLOWED(session, commit_transaction, config, cfg); + WT_STAT_CONN_INCR(session, txn_commit); + + txn = &session->txn; + if (F_ISSET(txn, WT_TXN_PREPARE)) { + WT_STAT_CONN_INCR(session, txn_prepare_commit); + WT_STAT_CONN_DECR(session, txn_prepare_active); + } + + WT_ERR(__wt_txn_context_check(session, true)); + + if (F_ISSET(txn, WT_TXN_ERROR) && txn->mod_count != 0) + WT_ERR_MSG(session, EINVAL, "failed transaction requires rollback%s%s", + txn->rollback_reason == NULL ? "" : ": ", + txn->rollback_reason == NULL ? "" : txn->rollback_reason); + + if (ret == 0) + ret = __wt_txn_commit(session, cfg); + else { + WT_TRET(__wt_session_reset_cursors(session, false)); + WT_TRET(__wt_txn_rollback(session, cfg)); + } + +err: + WT_ASSERT(session, WT_SESSION_TXN_STATE(session)->id == WT_TXN_NONE); + API_END_RET(session, ret); } /* * __session_prepare_transaction -- - * WT_SESSION->prepare_transaction method. + * WT_SESSION->prepare_transaction method. */ static int __session_prepare_transaction(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - WT_TXN *txn; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL(session, prepare_transaction, config, cfg); - WT_STAT_CONN_INCR(session, txn_prepare); - WT_STAT_CONN_INCR(session, txn_prepare_active); + WT_DECL_RET; + WT_SESSION_IMPL *session; + WT_TXN *txn; - WT_ERR(__wt_txn_context_check(session, true)); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL(session, prepare_transaction, config, cfg); + WT_STAT_CONN_INCR(session, txn_prepare); + WT_STAT_CONN_INCR(session, txn_prepare_active); - /* - * A failed transaction cannot be prepared, as it cannot guarantee - * a subsequent commit. - */ - txn = &session->txn; - if (F_ISSET(txn, WT_TXN_ERROR) && txn->mod_count != 0) - WT_ERR_MSG(session, EINVAL, - "failed transaction requires rollback%s%s", - txn->rollback_reason == NULL ? "" : ": ", - txn->rollback_reason == NULL ? "" : txn->rollback_reason); + WT_ERR(__wt_txn_context_check(session, true)); - WT_ERR(__wt_txn_prepare(session, cfg)); + /* + * A failed transaction cannot be prepared, as it cannot guarantee a subsequent commit. + */ + txn = &session->txn; + if (F_ISSET(txn, WT_TXN_ERROR) && txn->mod_count != 0) + WT_ERR_MSG(session, EINVAL, "failed transaction requires rollback%s%s", + txn->rollback_reason == NULL ? "" : ": ", + txn->rollback_reason == NULL ? "" : txn->rollback_reason); -err: API_END_RET(session, ret); + WT_ERR(__wt_txn_prepare(session, cfg)); +err: + WT_ASSERT(session, WT_SESSION_TXN_STATE(session)->id == WT_TXN_NONE); + API_END_RET(session, ret); } /* * __session_prepare_transaction_readonly -- - * WT_SESSION->prepare_transaction method; readonly version. + * WT_SESSION->prepare_transaction method; readonly version. */ static int -__session_prepare_transaction_readonly( - WT_SESSION *wt_session, const char *config) +__session_prepare_transaction_readonly(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(config); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, prepare_transaction); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, prepare_transaction); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_rollback_transaction -- - * WT_SESSION->rollback_transaction method. + * WT_SESSION->rollback_transaction method. */ static int __session_rollback_transaction(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - WT_TXN *txn; + WT_DECL_RET; + WT_SESSION_IMPL *session; + WT_TXN *txn; - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_PREPARE_ALLOWED( - session, rollback_transaction, config, cfg); - WT_STAT_CONN_INCR(session, txn_rollback); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_PREPARE_ALLOWED(session, rollback_transaction, config, cfg); + WT_STAT_CONN_INCR(session, txn_rollback); - txn = &session->txn; - if (F_ISSET(txn, WT_TXN_PREPARE)) { - WT_STAT_CONN_INCR(session, txn_prepare_rollback); - WT_STAT_CONN_DECR(session, txn_prepare_active); - } + txn = &session->txn; + if (F_ISSET(txn, WT_TXN_PREPARE)) { + WT_STAT_CONN_INCR(session, txn_prepare_rollback); + WT_STAT_CONN_DECR(session, txn_prepare_active); + } - WT_ERR(__wt_txn_context_check(session, true)); + WT_ERR(__wt_txn_context_check(session, true)); - WT_TRET(__wt_session_reset_cursors(session, false)); + WT_TRET(__wt_session_reset_cursors(session, false)); - WT_TRET(__wt_txn_rollback(session, cfg)); + WT_TRET(__wt_txn_rollback(session, cfg)); -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __session_timestamp_transaction -- - * WT_SESSION->timestamp_transaction method. + * WT_SESSION->timestamp_transaction method. */ static int __session_timestamp_transaction(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; #ifdef HAVE_DIAGNOSTIC - SESSION_API_CALL_PREPARE_ALLOWED(session, - timestamp_transaction, config, cfg); + SESSION_API_CALL_PREPARE_ALLOWED(session, timestamp_transaction, config, cfg); #else - SESSION_API_CALL_PREPARE_ALLOWED(session, - timestamp_transaction, NULL, cfg); - cfg[1] = config; + SESSION_API_CALL_PREPARE_ALLOWED(session, timestamp_transaction, NULL, cfg); + cfg[1] = config; #endif - WT_TRET(__wt_txn_set_timestamp(session, cfg)); -err: API_END_RET(session, ret); + WT_TRET(__wt_txn_set_timestamp(session, cfg)); +err: + API_END_RET(session, ret); } /* * __session_query_timestamp -- - * WT_SESSION->query_timestamp method. + * WT_SESSION->query_timestamp method. */ static int -__session_query_timestamp( - WT_SESSION *wt_session, char *hex_timestamp, const char *config) +__session_query_timestamp(WT_SESSION *wt_session, char *hex_timestamp, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_PREPARE_ALLOWED(session, - query_timestamp, config, cfg); - WT_TRET(__wt_txn_query_timestamp(session, hex_timestamp, cfg, false)); -err: API_END_RET(session, ret); + WT_DECL_RET; + WT_SESSION_IMPL *session; + + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_PREPARE_ALLOWED(session, query_timestamp, config, cfg); + WT_TRET(__wt_txn_query_timestamp(session, hex_timestamp, cfg, false)); +err: + API_END_RET(session, ret); } /* * __session_transaction_pinned_range -- - * WT_SESSION->transaction_pinned_range method. + * WT_SESSION->transaction_pinned_range method. */ static int __session_transaction_pinned_range(WT_SESSION *wt_session, uint64_t *prange) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - WT_TXN_STATE *txn_state; - uint64_t pinned; + WT_DECL_RET; + WT_SESSION_IMPL *session; + WT_TXN_STATE *txn_state; + uint64_t pinned; - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF_PREPARE_NOT_ALLOWED(session, pinned_range); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF_PREPARE_NOT_ALLOWED(session, pinned_range); - txn_state = WT_SESSION_TXN_STATE(session); + txn_state = WT_SESSION_TXN_STATE(session); - /* Assign pinned to the lesser of id or snap_min */ - if (txn_state->id != WT_TXN_NONE && - WT_TXNID_LT(txn_state->id, txn_state->pinned_id)) - pinned = txn_state->id; - else - pinned = txn_state->pinned_id; + /* Assign pinned to the lesser of id or snap_min */ + if (txn_state->id != WT_TXN_NONE && WT_TXNID_LT(txn_state->id, txn_state->pinned_id)) + pinned = txn_state->id; + else + pinned = txn_state->pinned_id; - if (pinned == WT_TXN_NONE) - *prange = 0; - else - *prange = S2C(session)->txn_global.current - pinned; + if (pinned == WT_TXN_NONE) + *prange = 0; + else + *prange = S2C(session)->txn_global.current - pinned; -err: API_END_RET(session, ret); +err: + API_END_RET(session, ret); } /* * __transaction_sync_run_chk -- - * Check to decide if the transaction sync call should continue running. + * Check to decide if the transaction sync call should continue running. */ static bool __transaction_sync_run_chk(WT_SESSION_IMPL *session) { - WT_CONNECTION_IMPL *conn; + WT_CONNECTION_IMPL *conn; - conn = S2C(session); + conn = S2C(session); - return (FLD_ISSET(conn->flags, WT_CONN_SERVER_LOG)); + return (FLD_ISSET(conn->flags, WT_CONN_SERVER_LOG)); } /* * __session_transaction_sync -- - * WT_SESSION->transaction_sync method. + * WT_SESSION->transaction_sync method. */ static int __session_transaction_sync(WT_SESSION *wt_session, const char *config) { - WT_CONFIG_ITEM cval; - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - WT_LOG *log; - WT_SESSION_IMPL *session; - uint64_t remaining_usec, timeout_ms, waited_ms; - uint64_t time_start, time_stop; - - session = (WT_SESSION_IMPL *)wt_session; - /* - * Indicated as allowed in prepared state, even though not allowed, - * so that running transaction check below take precedence. - */ - SESSION_API_CALL_PREPARE_ALLOWED( - session, transaction_sync, config, cfg); - WT_STAT_CONN_INCR(session, txn_sync); - - conn = S2C(session); - WT_ERR(__wt_txn_context_check(session, false)); - - /* - * If logging is not enabled there is nothing to do. - */ - if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) - WT_ERR_MSG(session, EINVAL, "logging not enabled"); - - log = conn->log; - - /* - * If there is no background sync LSN in this session, there - * is nothing to do. - */ - if (WT_IS_INIT_LSN(&session->bg_sync_lsn)) - goto err; - - /* - * If our LSN is smaller than the current sync LSN then our - * transaction is stable. We're done. - */ - if (__wt_log_cmp(&session->bg_sync_lsn, &log->sync_lsn) <= 0) - goto err; - - /* - * Our LSN is not yet stable. Wait and check again depending on the - * timeout. - */ - WT_ERR(__wt_config_gets_def(session, - cfg, "timeout_ms", (int)WT_SESSION_BG_SYNC_MSEC, &cval)); - timeout_ms = (uint64_t)cval.val; - - if (timeout_ms == 0) - WT_ERR(ETIMEDOUT); - - /* - * Keep checking the LSNs until we find it is stable or we reach - * our timeout, or there's some other reason to quit. - */ - time_start = __wt_clock(session); - while (__wt_log_cmp(&session->bg_sync_lsn, &log->sync_lsn) > 0) { - if (!__transaction_sync_run_chk(session)) - WT_ERR(ETIMEDOUT); - - __wt_cond_signal(session, conn->log_file_cond); - time_stop = __wt_clock(session); - waited_ms = WT_CLOCKDIFF_MS(time_stop, time_start); - if (waited_ms < timeout_ms) { - remaining_usec = (timeout_ms - waited_ms) * WT_THOUSAND; - __wt_cond_wait(session, log->log_sync_cond, - remaining_usec, __transaction_sync_run_chk); - } else - WT_ERR(ETIMEDOUT); - } - -err: API_END_RET(session, ret); + WT_CONFIG_ITEM cval; + WT_CONNECTION_IMPL *conn; + WT_DECL_RET; + WT_LOG *log; + WT_SESSION_IMPL *session; + uint64_t remaining_usec, timeout_ms, waited_ms; + uint64_t time_start, time_stop; + + session = (WT_SESSION_IMPL *)wt_session; + /* + * Indicated as allowed in prepared state, even though not allowed, so that running transaction + * check below take precedence. + */ + SESSION_API_CALL_PREPARE_ALLOWED(session, transaction_sync, config, cfg); + WT_STAT_CONN_INCR(session, txn_sync); + + conn = S2C(session); + WT_ERR(__wt_txn_context_check(session, false)); + + /* + * If logging is not enabled there is nothing to do. + */ + if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) + WT_ERR_MSG(session, EINVAL, "logging not enabled"); + + log = conn->log; + + /* + * If there is no background sync LSN in this session, there is nothing to do. + */ + if (WT_IS_INIT_LSN(&session->bg_sync_lsn)) + goto err; + + /* + * If our LSN is smaller than the current sync LSN then our transaction is stable. We're done. + */ + if (__wt_log_cmp(&session->bg_sync_lsn, &log->sync_lsn) <= 0) + goto err; + + /* + * Our LSN is not yet stable. Wait and check again depending on the timeout. + */ + WT_ERR(__wt_config_gets_def(session, cfg, "timeout_ms", (int)WT_SESSION_BG_SYNC_MSEC, &cval)); + timeout_ms = (uint64_t)cval.val; + + if (timeout_ms == 0) + WT_ERR(ETIMEDOUT); + + /* + * Keep checking the LSNs until we find it is stable or we reach our timeout, or there's some + * other reason to quit. + */ + time_start = __wt_clock(session); + while (__wt_log_cmp(&session->bg_sync_lsn, &log->sync_lsn) > 0) { + if (!__transaction_sync_run_chk(session)) + WT_ERR(ETIMEDOUT); + + __wt_cond_signal(session, conn->log_file_cond); + time_stop = __wt_clock(session); + waited_ms = WT_CLOCKDIFF_MS(time_stop, time_start); + if (waited_ms < timeout_ms) { + remaining_usec = (timeout_ms - waited_ms) * WT_THOUSAND; + __wt_cond_wait(session, log->log_sync_cond, remaining_usec, __transaction_sync_run_chk); + } else + WT_ERR(ETIMEDOUT); + } + +err: + API_END_RET(session, ret); } /* * __session_transaction_sync_readonly -- - * WT_SESSION->transaction_sync method; readonly version. + * WT_SESSION->transaction_sync method; readonly version. */ static int __session_transaction_sync_readonly(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(config); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, transaction_sync); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, transaction_sync); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_checkpoint -- - * WT_SESSION->checkpoint method. + * WT_SESSION->checkpoint method. */ static int __session_checkpoint(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - - session = (WT_SESSION_IMPL *)wt_session; - - WT_STAT_CONN_INCR(session, txn_checkpoint); - /* - * Indicated as allowed in prepared state, even though not allowed, - * so that running transaction check below take precedence. - */ - SESSION_API_CALL_PREPARE_ALLOWED(session, checkpoint, config, cfg); - - WT_ERR(__wt_inmem_unsupported_op(session, NULL)); - - /* - * 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. - */ - WT_ERR(__wt_txn_context_check(session, false)); - - ret = __wt_txn_checkpoint(session, cfg, true); - - /* - * Release common session resources (for example, checkpoint may acquire - * significant reconciliation structures/memory). - */ - WT_TRET(__wt_session_release_resources(session)); - -err: API_END_RET_NOTFOUND_MAP(session, ret); + WT_DECL_RET; + WT_SESSION_IMPL *session; + + session = (WT_SESSION_IMPL *)wt_session; + + WT_STAT_CONN_INCR(session, txn_checkpoint); + /* + * Indicated as allowed in prepared state, even though not allowed, so that running transaction + * check below take precedence. + */ + SESSION_API_CALL_PREPARE_ALLOWED(session, checkpoint, config, cfg); + + WT_ERR(__wt_inmem_unsupported_op(session, NULL)); + + /* + * 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. + */ + WT_ERR(__wt_txn_context_check(session, false)); + + ret = __wt_txn_checkpoint(session, cfg, true); + + /* + * Release common session resources (for example, checkpoint may acquire significant + * reconciliation structures/memory). + */ + WT_TRET(__wt_session_release_resources(session)); + +err: + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __session_checkpoint_readonly -- - * WT_SESSION->checkpoint method; readonly version. + * WT_SESSION->checkpoint method; readonly version. */ static int __session_checkpoint_readonly(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; + WT_DECL_RET; + WT_SESSION_IMPL *session; - WT_UNUSED(config); + WT_UNUSED(config); - session = (WT_SESSION_IMPL *)wt_session; - SESSION_API_CALL_NOCONF(session, checkpoint); + session = (WT_SESSION_IMPL *)wt_session; + SESSION_API_CALL_NOCONF(session, checkpoint); - ret = __wt_session_notsup(session); -err: API_END_RET(session, ret); + ret = __wt_session_notsup(session); +err: + API_END_RET(session, ret); } /* * __session_snapshot -- - * WT_SESSION->snapshot method. + * WT_SESSION->snapshot method. */ static int __session_snapshot(WT_SESSION *wt_session, const char *config) { - WT_DECL_RET; - WT_SESSION_IMPL *session; - WT_TXN_GLOBAL *txn_global; - bool has_create, has_drop; + WT_DECL_RET; + WT_SESSION_IMPL *session; + WT_TXN_GLOBAL *txn_global; + bool has_create, has_drop; - has_create = has_drop = false; - session = (WT_SESSION_IMPL *)wt_session; - txn_global = &S2C(session)->txn_global; + has_create = has_drop = false; + session = (WT_SESSION_IMPL *)wt_session; + txn_global = &S2C(session)->txn_global; - SESSION_API_CALL(session, snapshot, config, cfg); + SESSION_API_CALL(session, snapshot, config, cfg); - WT_ERR(__wt_txn_named_snapshot_config( - session, cfg, &has_create, &has_drop)); + WT_ERR(__wt_txn_named_snapshot_config(session, cfg, &has_create, &has_drop)); - __wt_writelock(session, &txn_global->nsnap_rwlock); + __wt_writelock(session, &txn_global->nsnap_rwlock); - /* Drop any snapshots to be removed first. */ - if (has_drop) - WT_ERR(__wt_txn_named_snapshot_drop(session, cfg)); + /* Drop any snapshots to be removed first. */ + if (has_drop) + WT_ERR(__wt_txn_named_snapshot_drop(session, cfg)); - /* Start the named snapshot if requested. */ - if (has_create) - WT_ERR(__wt_txn_named_snapshot_begin(session, cfg)); + /* Start the named snapshot if requested. */ + if (has_create) + WT_ERR(__wt_txn_named_snapshot_begin(session, cfg)); -err: __wt_writeunlock(session, &txn_global->nsnap_rwlock); +err: + __wt_writeunlock(session, &txn_global->nsnap_rwlock); - API_END_RET_NOTFOUND_MAP(session, ret); + API_END_RET_NOTFOUND_MAP(session, ret); } /* * __wt_session_strerror -- - * WT_SESSION->strerror method. + * WT_SESSION->strerror method. */ const char * __wt_session_strerror(WT_SESSION *wt_session, int error) { - WT_SESSION_IMPL *session; + WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)wt_session; + session = (WT_SESSION_IMPL *)wt_session; - return (__wt_strerror(session, error, NULL, 0)); + return (__wt_strerror(session, error, NULL, 0)); } /* * __wt_session_breakpoint -- - * A place to put a breakpoint, if you need one, or call some check - * code. + * A place to put a breakpoint, if you need one, or call some check code. */ int __wt_session_breakpoint(WT_SESSION *wt_session) { - WT_UNUSED(wt_session); + WT_UNUSED(wt_session); - return (0); + return (0); } /* * __open_session -- - * Allocate a session handle. + * Allocate a session handle. */ static int -__open_session(WT_CONNECTION_IMPL *conn, - WT_EVENT_HANDLER *event_handler, const char *config, - WT_SESSION_IMPL **sessionp) +__open_session(WT_CONNECTION_IMPL *conn, WT_EVENT_HANDLER *event_handler, const char *config, + WT_SESSION_IMPL **sessionp) { - static const WT_SESSION stds = { - NULL, - NULL, - __session_close, - __session_reconfigure, - __wt_session_strerror, - __session_open_cursor, - __session_alter, - __session_create, - __session_import, - __wt_session_compact, - __session_drop, - __session_join, - __session_log_flush, - __session_log_printf, - __session_rebalance, - __session_rename, - __session_reset, - __session_salvage, - __session_truncate, - __session_upgrade, - __session_verify, - __session_begin_transaction, - __session_commit_transaction, - __session_prepare_transaction, - __session_rollback_transaction, - __session_timestamp_transaction, - __session_query_timestamp, - __session_checkpoint, - __session_snapshot, - __session_transaction_pinned_range, - __session_transaction_sync, - __wt_session_breakpoint - }, stds_readonly = { - NULL, - NULL, - __session_close, - __session_reconfigure, - __wt_session_strerror, - __session_open_cursor, - __session_alter_readonly, - __session_create_readonly, - __session_import_readonly, - __wt_session_compact_readonly, - __session_drop_readonly, - __session_join, - __session_log_flush_readonly, - __session_log_printf_readonly, - __session_rebalance_readonly, - __session_rename_readonly, - __session_reset, - __session_salvage_readonly, - __session_truncate_readonly, - __session_upgrade_readonly, - __session_verify, - __session_begin_transaction, - __session_commit_transaction, - __session_prepare_transaction_readonly, - __session_rollback_transaction, - __session_timestamp_transaction, - __session_query_timestamp, - __session_checkpoint_readonly, - __session_snapshot, - __session_transaction_pinned_range, - __session_transaction_sync_readonly, - __wt_session_breakpoint - }; - WT_DECL_RET; - WT_SESSION_IMPL *session, *session_ret; - uint32_t i; - - *sessionp = NULL; - - session = conn->default_session; - session_ret = NULL; - - __wt_spin_lock(session, &conn->api_lock); - - /* - * Make sure we don't try to open a new session after the application - * closes the connection. This is particularly intended to catch - * cases where server threads open sessions. - */ - WT_ASSERT(session, !F_ISSET(conn, WT_CONN_CLOSING)); - - /* Find the first inactive session slot. */ - for (session_ret = conn->sessions, - i = 0; i < conn->session_size; ++session_ret, ++i) - if (!session_ret->active) - break; - if (i == conn->session_size) - WT_ERR_MSG(session, WT_ERROR, - "out of sessions, configured for %" PRIu32 " (including " - "internal sessions)", - conn->session_size); - - /* - * If the active session count is increasing, update it. We don't worry - * about correcting the session count on error, as long as we don't mark - * this session as active, we'll clean it up on close. - */ - if (i >= conn->session_cnt) /* Defend against off-by-one errors. */ - conn->session_cnt = i + 1; - - session_ret->iface = - F_ISSET(conn, WT_CONN_READONLY) ? stds_readonly : stds; - session_ret->iface.connection = &conn->iface; - - session_ret->name = NULL; - session_ret->id = i; - - if (WT_SESSION_FIRST_USE(session_ret)) - __wt_random_init(&session_ret->rnd); - - __wt_event_handler_set(session_ret, - event_handler == NULL ? session->event_handler : event_handler); - - TAILQ_INIT(&session_ret->cursors); - TAILQ_INIT(&session_ret->dhandles); - - /* - * If we don't have them, allocate the cursor and dhandle hash arrays. - * Allocate the table hash array as well. - */ - if (session_ret->cursor_cache == NULL) - WT_ERR(__wt_calloc_def( - session, WT_HASH_ARRAY_SIZE, &session_ret->cursor_cache)); - if (session_ret->dhhash == NULL) - WT_ERR(__wt_calloc_def( - session, WT_HASH_ARRAY_SIZE, &session_ret->dhhash)); - - /* Initialize the dhandle hash array. */ - for (i = 0; i < WT_HASH_ARRAY_SIZE; i++) - TAILQ_INIT(&session_ret->dhhash[i]); - - /* Initialize the cursor cache hash buckets and sweep trigger. */ - for (i = 0; i < WT_HASH_ARRAY_SIZE; i++) - TAILQ_INIT(&session_ret->cursor_cache[i]); - session_ret->cursor_sweep_countdown = WT_SESSION_CURSOR_SWEEP_COUNTDOWN; - - /* Initialize transaction support: default to read-committed. */ - session_ret->isolation = WT_ISO_READ_COMMITTED; - WT_ERR(__wt_txn_init(session, session_ret)); - - /* - * The session's hazard pointer memory isn't discarded during normal - * session close because access to it isn't serialized. Allocate the - * first time we open this session. - */ - if (WT_SESSION_FIRST_USE(session_ret)) { - WT_ERR(__wt_calloc_def(session, - WT_SESSION_INITIAL_HAZARD_SLOTS, &session_ret->hazard)); - session_ret->hazard_size = WT_SESSION_INITIAL_HAZARD_SLOTS; - session_ret->hazard_inuse = 0; - session_ret->nhazard = 0; - } - - /* Cache the offset of this session's statistics bucket. */ - session_ret->stat_bucket = WT_STATS_SLOT_ID(session); - - /* Allocate the buffer for operation tracking */ - if (F_ISSET(conn, WT_CONN_OPTRACK)) { - WT_ERR(__wt_malloc( - session, WT_OPTRACK_BUFSIZE, &session_ret->optrack_buf)); - session_ret->optrackbuf_ptr = 0; - } - - __wt_stat_session_init_single(&session_ret->stats); - - /* Set the default value for session flags. */ - if (F_ISSET(conn, WT_CONN_CACHE_CURSORS)) - F_SET(session_ret, WT_SESSION_CACHE_CURSORS); - - /* - * Configuration: currently, the configuration for open_session is the - * same as session.reconfigure, so use that function. - */ - if (config != NULL) - WT_ERR( - __session_reconfigure((WT_SESSION *)session_ret, config)); - - /* - * Publish: make the entry visible to server threads. There must be a - * barrier for two reasons, to ensure structure fields are set before - * any other thread will consider the session, and to push the session - * count to ensure the eviction thread can't review too few slots. - */ - WT_PUBLISH(session_ret->active, 1); - - WT_STATIC_ASSERT(offsetof(WT_SESSION_IMPL, iface) == 0); - *sessionp = session_ret; - - WT_STAT_CONN_INCR(session, session_open); - -err: __wt_spin_unlock(session, &conn->api_lock); - return (ret); + static const WT_SESSION + stds = {NULL, NULL, __session_close, __session_reconfigure, __wt_session_strerror, + __session_open_cursor, __session_alter, __session_create, __session_import, + __wt_session_compact, __session_drop, __session_join, __session_log_flush, + __session_log_printf, __session_rebalance, __session_rename, __session_reset, + __session_salvage, __session_truncate, __session_upgrade, __session_verify, + __session_begin_transaction, __session_commit_transaction, __session_prepare_transaction, + __session_rollback_transaction, __session_timestamp_transaction, __session_query_timestamp, + __session_checkpoint, __session_snapshot, __session_transaction_pinned_range, + __session_transaction_sync, __wt_session_breakpoint}, + stds_readonly = {NULL, NULL, __session_close, __session_reconfigure, __wt_session_strerror, + __session_open_cursor, __session_alter_readonly, __session_create_readonly, + __session_import_readonly, __wt_session_compact_readonly, __session_drop_readonly, + __session_join, __session_log_flush_readonly, __session_log_printf_readonly, + __session_rebalance_readonly, __session_rename_readonly, __session_reset, + __session_salvage_readonly, __session_truncate_readonly, __session_upgrade_readonly, + __session_verify, __session_begin_transaction, __session_commit_transaction, + __session_prepare_transaction_readonly, __session_rollback_transaction, + __session_timestamp_transaction, __session_query_timestamp, __session_checkpoint_readonly, + __session_snapshot, __session_transaction_pinned_range, __session_transaction_sync_readonly, + __wt_session_breakpoint}; + WT_DECL_RET; + WT_SESSION_IMPL *session, *session_ret; + uint32_t i; + + *sessionp = NULL; + + session = conn->default_session; + session_ret = NULL; + + __wt_spin_lock(session, &conn->api_lock); + + /* + * Make sure we don't try to open a new session after the application closes the connection. + * This is particularly intended to catch cases where server threads open sessions. + */ + WT_ASSERT(session, !F_ISSET(conn, WT_CONN_CLOSING)); + + /* Find the first inactive session slot. */ + for (session_ret = conn->sessions, i = 0; i < conn->session_size; ++session_ret, ++i) + if (!session_ret->active) + break; + if (i == conn->session_size) + WT_ERR_MSG(session, WT_ERROR, "out of sessions, configured for %" PRIu32 + " (including " + "internal sessions)", + conn->session_size); + + /* + * If the active session count is increasing, update it. We don't worry about correcting the + * session count on error, as long as we don't mark this session as active, we'll clean it up on + * close. + */ + if (i >= conn->session_cnt) /* Defend against off-by-one errors. */ + conn->session_cnt = i + 1; + + session_ret->iface = F_ISSET(conn, WT_CONN_READONLY) ? stds_readonly : stds; + session_ret->iface.connection = &conn->iface; + + session_ret->name = NULL; + session_ret->id = i; + + if (WT_SESSION_FIRST_USE(session_ret)) + __wt_random_init(&session_ret->rnd); + + __wt_event_handler_set( + session_ret, event_handler == NULL ? session->event_handler : event_handler); + + TAILQ_INIT(&session_ret->cursors); + TAILQ_INIT(&session_ret->dhandles); + + /* + * If we don't have them, allocate the cursor and dhandle hash arrays. Allocate the table hash + * array as well. + */ + if (session_ret->cursor_cache == NULL) + WT_ERR(__wt_calloc_def(session, WT_HASH_ARRAY_SIZE, &session_ret->cursor_cache)); + if (session_ret->dhhash == NULL) + WT_ERR(__wt_calloc_def(session, WT_HASH_ARRAY_SIZE, &session_ret->dhhash)); + + /* Initialize the dhandle hash array. */ + for (i = 0; i < WT_HASH_ARRAY_SIZE; i++) + TAILQ_INIT(&session_ret->dhhash[i]); + + /* Initialize the cursor cache hash buckets and sweep trigger. */ + for (i = 0; i < WT_HASH_ARRAY_SIZE; i++) + TAILQ_INIT(&session_ret->cursor_cache[i]); + session_ret->cursor_sweep_countdown = WT_SESSION_CURSOR_SWEEP_COUNTDOWN; + + /* Initialize transaction support: default to read-committed. */ + session_ret->isolation = WT_ISO_READ_COMMITTED; + WT_ERR(__wt_txn_init(session, session_ret)); + + /* + * The session's hazard pointer memory isn't discarded during normal session close because + * access to it isn't serialized. Allocate the first time we open this session. + */ + if (WT_SESSION_FIRST_USE(session_ret)) { + WT_ERR(__wt_calloc_def(session, WT_SESSION_INITIAL_HAZARD_SLOTS, &session_ret->hazard)); + session_ret->hazard_size = WT_SESSION_INITIAL_HAZARD_SLOTS; + session_ret->hazard_inuse = 0; + session_ret->nhazard = 0; + } + + /* Cache the offset of this session's statistics bucket. */ + session_ret->stat_bucket = WT_STATS_SLOT_ID(session); + + /* Allocate the buffer for operation tracking */ + if (F_ISSET(conn, WT_CONN_OPTRACK)) { + WT_ERR(__wt_malloc(session, WT_OPTRACK_BUFSIZE, &session_ret->optrack_buf)); + session_ret->optrackbuf_ptr = 0; + } + + __wt_stat_session_init_single(&session_ret->stats); + + /* Set the default value for session flags. */ + if (F_ISSET(conn, WT_CONN_CACHE_CURSORS)) + F_SET(session_ret, WT_SESSION_CACHE_CURSORS); + + /* + * Configuration: currently, the configuration for open_session is the same as + * session.reconfigure, so use that function. + */ + if (config != NULL) + WT_ERR(__session_reconfigure((WT_SESSION *)session_ret, config)); + + /* + * Publish: make the entry visible to server threads. There must be a barrier for two reasons, + * to ensure structure fields are set before any other thread will consider the session, and to + * push the session count to ensure the eviction thread can't review too few slots. + */ + WT_PUBLISH(session_ret->active, 1); + + WT_STATIC_ASSERT(offsetof(WT_SESSION_IMPL, iface) == 0); + *sessionp = session_ret; + + WT_STAT_CONN_INCR(session, session_open); + +err: + __wt_spin_unlock(session, &conn->api_lock); + return (ret); } /* * __wt_open_session -- - * Allocate a session handle. + * Allocate a session handle. */ int -__wt_open_session(WT_CONNECTION_IMPL *conn, - WT_EVENT_HANDLER *event_handler, const char *config, - bool open_metadata, WT_SESSION_IMPL **sessionp) +__wt_open_session(WT_CONNECTION_IMPL *conn, WT_EVENT_HANDLER *event_handler, const char *config, + bool open_metadata, WT_SESSION_IMPL **sessionp) { - WT_DECL_RET; - WT_SESSION *wt_session; - WT_SESSION_IMPL *session; - - *sessionp = NULL; - - /* Acquire a session. */ - WT_RET(__open_session(conn, event_handler, config, &session)); - - /* - * Acquiring the metadata handle requires the schema lock; we've seen - * problems in the past where a session has acquired the schema lock - * unexpectedly, relatively late in the run, and deadlocked. Be - * defensive, get it now. The metadata file may not exist when the - * connection first creates its default session or the shared cache - * pool creates its sessions, let our caller decline this work. - */ - if (open_metadata) { - WT_ASSERT(session, !F_ISSET(session, WT_SESSION_LOCKED_SCHEMA)); - if ((ret = __wt_metadata_cursor(session, NULL)) != 0) { - wt_session = &session->iface; - WT_TRET(wt_session->close(wt_session, NULL)); - return (ret); - } - } - - *sessionp = session; - return (0); + WT_DECL_RET; + WT_SESSION *wt_session; + WT_SESSION_IMPL *session; + + *sessionp = NULL; + + /* Acquire a session. */ + WT_RET(__open_session(conn, event_handler, config, &session)); + + /* + * Acquiring the metadata handle requires the schema lock; we've seen problems in the past where + * a session has acquired the schema lock unexpectedly, relatively late in the run, and + * deadlocked. Be defensive, get it now. The metadata file may not exist when the connection + * first creates its default session or the shared cache pool creates its sessions, let our + * caller decline this work. + */ + if (open_metadata) { + WT_ASSERT(session, !F_ISSET(session, WT_SESSION_LOCKED_SCHEMA)); + if ((ret = __wt_metadata_cursor(session, NULL)) != 0) { + wt_session = &session->iface; + WT_TRET(wt_session->close(wt_session, NULL)); + return (ret); + } + } + + *sessionp = session; + return (0); } /* * __wt_open_internal_session -- - * Allocate a session for WiredTiger's use. + * Allocate a session for WiredTiger's use. */ int -__wt_open_internal_session(WT_CONNECTION_IMPL *conn, const char *name, - bool open_metadata, uint32_t session_flags, WT_SESSION_IMPL **sessionp) +__wt_open_internal_session(WT_CONNECTION_IMPL *conn, const char *name, bool open_metadata, + uint32_t session_flags, WT_SESSION_IMPL **sessionp) { - WT_SESSION_IMPL *session; + WT_SESSION_IMPL *session; - *sessionp = NULL; + *sessionp = NULL; - /* Acquire a session. */ - WT_RET(__wt_open_session(conn, NULL, NULL, open_metadata, &session)); - session->name = name; + /* Acquire a session. */ + WT_RET(__wt_open_session(conn, NULL, NULL, open_metadata, &session)); + session->name = name; - /* - * Public sessions are automatically closed during WT_CONNECTION->close. - * If the session handles for internal threads were to go on the public - * list, there would be complex ordering issues during close. Set a - * flag to avoid this: internal sessions are not closed automatically. - */ - F_SET(session, session_flags | WT_SESSION_INTERNAL); + /* + * Public sessions are automatically closed during WT_CONNECTION->close. If the session handles + * for internal threads were to go on the public list, there would be complex ordering issues + * during close. Set a flag to avoid this: internal sessions are not closed automatically. + */ + F_SET(session, session_flags | WT_SESSION_INTERNAL); - *sessionp = session; - return (0); + *sessionp = session; + return (0); } |