/* * __wt_open_session -- * Allocate a session handle. The internal parameter is used for sessions * opened by WiredTiger for its own use. */ int __wt_open_session(WT_CONNECTION_IMPL *conn, int internal, WT_EVENT_HANDLER *event_handler, const char *config, WT_SESSION_IMPL **sessionp) { static WT_SESSION stds = { NULL, __session_close, __session_reconfigure, __session_open_cursor, __session_create, __session_compact, __session_drop, __session_rename, __session_salvage, __session_truncate, __session_upgrade, __session_verify, __session_begin_transaction, __session_commit_transaction, __session_rollback_transaction, __session_checkpoint, __session_msg_printf }; WT_DECL_RET; WT_SESSION_IMPL *session, *session_ret; uint32_t i; session = conn->default_session; session_ret = NULL; __wt_spin_lock(session, &conn->api_lock); /* 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, "only configured to support %d thread contexts", 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->id = i; session_ret->iface = stds; session_ret->iface.connection = &conn->iface; WT_ERR(__wt_cond_alloc(session, "session", 0, &session_ret->cond)); __wt_event_handler_set(session_ret, event_handler == NULL ? session->event_handler : event_handler); TAILQ_INIT(&session_ret->cursors); TAILQ_INIT(&session_ret->btrees); /* Initialize transaction support. */ WT_ERR(__wt_txn_init(session_ret)); /* * The session's hazard reference memory isn't discarded during normal * session close because access to it isn't serialized. Allocate the * first time we open this session. */ if (session_ret->hazard == NULL) WT_ERR(__wt_calloc(session, conn->hazard_max, sizeof(WT_HAZARD), &session_ret->hazard)); /* * Set an initial size for the hazard array. It will be grown as * required up to hazard_max. The hazard_size is reset on close, since * __wt_hazard_close ensures the array is cleared - so it is safe to * reset the starting size on each open. */ session_ret->hazard_size = WT_HAZARD_INCR; /* * 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. */ if (internal) F_SET(session_ret, WT_SESSION_INTERNAL); /* * 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); STATIC_ASSERT(offsetof(WT_SESSION_IMPL, iface) == 0); *sessionp = session_ret; err: __wt_spin_unlock(session, &conn->api_lock); return (ret); }
/* * wiredtiger_open -- * Main library entry point: open a new connection to a WiredTiger * database. */ int wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler, const char *config, WT_CONNECTION **wt_connp) { static WT_CONNECTION stdc = { __conn_close, __conn_reconfigure, __conn_get_home, __conn_is_new, __conn_open_session, __conn_load_extension, __conn_add_data_source, __conn_add_collator, __conn_add_compressor, __conn_add_extractor }; static struct { const char *name; uint32_t flag; } *ft, directio_types[] = { { "data", WT_DIRECTIO_DATA }, { "log", WT_DIRECTIO_LOG }, { NULL, 0 } }; WT_CONFIG subconfig; WT_CONFIG_ITEM cval, skey, sval; WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_ITEM *cbuf, expath, exconfig; WT_SESSION_IMPL *session; const char *cfg[] = { __wt_confdfl_wiredtiger_open, config, NULL, NULL, NULL }; int exist; *wt_connp = NULL; session = NULL; cbuf = NULL; WT_CLEAR(expath); WT_CLEAR(exconfig); WT_RET(__wt_library_init()); WT_RET(__wt_calloc_def(NULL, 1, &conn)); conn->iface = stdc; /* * Immediately link the structure into the connection structure list: * the only thing ever looked at on that list is the database name, * and a NULL value is fine. */ __wt_spin_lock(NULL, &__wt_process.spinlock); TAILQ_INSERT_TAIL(&__wt_process.connqh, conn, q); __wt_spin_unlock(NULL, &__wt_process.spinlock); session = conn->default_session = &conn->dummy_session; session->iface.connection = &conn->iface; session->name = "wiredtiger_open"; __wt_event_handler_set(session, event_handler); /* Remaining basic initialization of the connection structure. */ WT_ERR(__wt_connection_init(conn)); /* Check the configuration strings. */ WT_ERR(__wt_config_check( session, __wt_confchk_wiredtiger_open, config, 0)); /* Get the database home. */ WT_ERR(__conn_home(session, home, cfg)); /* Make sure no other thread of control already owns this database. */ WT_ERR(__conn_single(session, cfg)); /* Read the database-home configuration file. */ WT_ERR(__conn_config_file(session, cfg, &cbuf)); /* Read the environment variable configuration. */ WT_ERR(__conn_config_env(session, cfg)); WT_ERR(__wt_config_gets(session, cfg, "hazard_max", &cval)); conn->hazard_max = (uint32_t)cval.val; WT_ERR(__wt_config_gets(session, cfg, "session_max", &cval)); conn->session_size = (uint32_t)cval.val + WT_NUM_INTERNAL_SESSIONS; WT_ERR(__wt_config_gets(session, cfg, "lsm_merge", &cval)); if (cval.val) F_SET(conn, WT_CONN_LSM_MERGE); WT_ERR(__wt_config_gets(session, cfg, "sync", &cval)); if (cval.val) F_SET(conn, WT_CONN_SYNC); WT_ERR(__wt_config_gets(session, cfg, "transactional", &cval)); if (cval.val) F_SET(conn, WT_CONN_TRANSACTIONAL); /* Configure verbose flags. */ WT_ERR(__conn_verbose_config(session, cfg)); WT_ERR(__wt_conn_cache_pool_config(session, cfg)); WT_ERR(__wt_config_gets(session, cfg, "logging", &cval)); if (cval.val != 0) WT_ERR(__wt_open( session, WT_LOG_FILENAME, 1, 0, 0, &conn->log_fh)); /* Configure direct I/O and buffer alignment. */ WT_ERR(__wt_config_gets(session, cfg, "buffer_alignment", &cval)); if (cval.val == -1) conn->buffer_alignment = WT_BUFFER_ALIGNMENT_DEFAULT; else conn->buffer_alignment = (size_t)cval.val; #ifndef HAVE_POSIX_MEMALIGN if (conn->buffer_alignment != 0) WT_ERR_MSG(session, EINVAL, "buffer_alignment requires posix_memalign"); #endif /* * Configuration: direct_io, mmap, statistics. */ WT_ERR(__wt_config_gets(session, cfg, "direct_io", &cval)); for (ft = directio_types; ft->name != NULL; ft++) { ret = __wt_config_subgets(session, &cval, ft->name, &sval); if (ret == 0) { if (sval.val) FLD_SET(conn->direct_io, ft->flag); } else if (ret != WT_NOTFOUND) goto err; } WT_ERR(__wt_config_gets(session, cfg, "mmap", &cval)); conn->mmap = cval.val == 0 ? 0 : 1; WT_ERR(__wt_config_gets(session, cfg, "statistics", &cval)); conn->statistics = cval.val == 0 ? 0 : 1; /* Load any extensions referenced in the config. */ WT_ERR(__wt_config_gets(session, cfg, "extensions", &cval)); WT_ERR(__wt_config_subinit(session, &subconfig, &cval)); while ((ret = __wt_config_next(&subconfig, &skey, &sval)) == 0) { WT_ERR(__wt_buf_fmt( session, &expath, "%.*s", (int)skey.len, skey.str)); if (sval.len > 0) WT_ERR(__wt_buf_fmt(session, &exconfig, "entry=%.*s\n", (int)sval.len, sval.str)); WT_ERR(conn->iface.load_extension(&conn->iface, expath.data, (sval.len > 0) ? exconfig.data : NULL)); } WT_ERR_NOTFOUND_OK(ret); /* * Open the connection; if that fails, the connection handle has been * destroyed by the time the open function returns. */ if ((ret = __wt_connection_open(conn, cfg)) != 0) { conn = NULL; WT_ERR(ret); } /* Open the default session. */ WT_ERR(__wt_open_session(conn, 1, NULL, NULL, &conn->default_session)); session = conn->default_session; /* * Check on the turtle and metadata files, creating them if necessary * (which avoids application threads racing to create the metadata file * later). */ WT_ERR(__wt_meta_turtle_init(session, &exist)); if (!exist) { /* * We're single-threaded, but acquire the schema lock * regardless: the lower level code checks that it is * appropriately synchronized. */ WT_WITH_SCHEMA_LOCK(session, ret = __wt_schema_create(session, WT_METADATA_URI, NULL)); WT_ERR(ret); } WT_ERR(__wt_metadata_open(session)); /* If there's a hot-backup file, load it. */ WT_ERR(__wt_metadata_load_backup(session)); /* * XXX LSM initialization. * This is structured so that it could be moved to an extension. */ WT_ERR(__wt_lsm_init(&conn->iface, NULL)); STATIC_ASSERT(offsetof(WT_CONNECTION_IMPL, iface) == 0); *wt_connp = &conn->iface; /* * Destroying the connection on error will destroy our session handle, * cleanup using the session handle first, then discard the connection. */ err: if (cbuf != NULL) __wt_buf_free(session, cbuf); __wt_buf_free(session, &expath); __wt_buf_free(session, &exconfig); if (ret != 0 && conn != NULL) WT_TRET(__wt_connection_destroy(conn)); /* Let the server threads proceed. */ if (ret == 0) conn->connection_initialized = 1; return (ret); }
/* * wiredtiger_config_validate -- * Validate a configuration string. */ int wiredtiger_config_validate(WT_SESSION *wt_session, WT_EVENT_HANDLER *handler, const char *name, const char *config) { WT_CONNECTION_IMPL *conn, dummy_conn; WT_SESSION_IMPL *session; const WT_CONFIG_ENTRY *ep, **epp; session = (WT_SESSION_IMPL *)wt_session; /* * It's a logic error to specify both a session and an event handler. */ if (session != NULL && handler != NULL) WT_RET_MSG(session, EINVAL, "wiredtiger_config_validate error handler ignored when " "a session also specified"); /* * If we're not given a session, but we do have an event handler, build * a fake session/connection pair and configure the event handler. */ conn = NULL; if (session == NULL && handler != NULL) { WT_CLEAR(dummy_conn); conn = &dummy_conn; session = conn->default_session = &conn->dummy_session; session->iface.connection = &conn->iface; session->name = "wiredtiger_config_validate"; __wt_event_handler_set(session, handler); } if (session != NULL) conn = S2C(session); if (name == NULL) WT_RET_MSG(session, EINVAL, "no name specified"); if (config == NULL) WT_RET_MSG(session, EINVAL, "no configuration specified"); /* * If we don't have a real connection, look for a matching name in the * static list, otherwise look in the configuration list (which has any * configuration information the application has added). */ if (session == NULL || conn == NULL || conn->config_entries == NULL) ep = __wt_conn_config_match(name); else { ep = NULL; for (epp = conn->config_entries; *epp != NULL && (*epp)->method != NULL; ++epp) if (strcmp((*epp)->method, name) == 0) { ep = *epp; break; } } if (ep == NULL) WT_RET_MSG(session, EINVAL, "unknown or unsupported configuration API: %s", name); return (__wt_config_check(session, ep, config, 0)); }