Пример #1
0
static int
kvs_session_verify(WT_DATA_SOURCE *wtds,
    WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config)
{
	DATA_SOURCE *ds;
	DB *db;
	WT_EXTENSION_API *wt_api;
	int ret = 0;
	const char *name;

	(void)config;				/* Unused parameters */

	ds = (DATA_SOURCE *)wtds;
	wt_api = ds->wt_api;
						/* Get the object name */
	if ((ret = uri2name(wt_api, session, uri, &name)) != 0)
		return (ret);

	if ((ret = single_thread(wtds, session, &ds->rwlock)) != 0)
		return (ret);

	if ((ret = db_create(&db, ds->dbenv, 0)) != 0)
		ESET(wt_api,
		    session, WT_ERROR, "db_create: %s", db_strerror(ret));
	else if ((ret = db->verify(db, name, NULL, NULL, 0)) != 0)
		ESET(wt_api, session, WT_ERROR,
		    "Db.verify: %s: %s", uri, db_strerror(ret));
	/* db handle is dead */

	ETRET(unlock(wt_api, session, &ds->rwlock));
	return (ret);
}
Пример #2
0
/*
 * wiredtiger_extension_terminate --
 *	Shutdown the KVS connector code.
 */
int
wiredtiger_extension_terminate(WT_CONNECTION *connection)
{
	DATA_SOURCE *p;
	int ret, tret;

	(void)connection;			/* Unused parameters */

	ret = writelock(NULL, &global_lock);

	/* Start a flush on any open objects. */
	for (p = data_source_head; p != NULL; p = p->next)
		if ((tret = kvs_commit(p->kvs)) != 0)
			ESET(NULL, WT_ERROR,
			    "kvs_commit: %s: %s", p->uri, kvs_strerror(tret));

	/* Complain if any of the objects are in use. */
	for (p = data_source_head; p != NULL; p = p->next)
		if (p->open_cursors != 0)
			ESET(NULL, WT_ERROR,
			    "%s: has open cursors during close", p->uri);

	/* Close and discard the remaining objects. */
	while ((p = data_source_head) != NULL) {
		if ((tret = kvs_close(p->kvs)) != 0)
			ESET(NULL, WT_ERROR,
			    "kvs_close: %s: %s", p->uri, kvs_strerror(tret));
		data_source_head = p->next;
		free(p->uri);
		ETRET(lock_destroy(NULL, &p->lock));
		free(p);
	}

	ETRET(unlock(NULL, &global_lock));
	ETRET(lock_destroy(NULL, &global_lock));

	wt_ext = NULL;

	return (ret);
}
Пример #3
0
/*
 * drop_data_source --
 *	Drop a data source from our list, closing any underlying KVS handle.
 */
static int
drop_data_source(WT_SESSION *session, const char *uri)
{
	DATA_SOURCE *p, **ref;
	int ret;

	if ((ret = writelock(session, &global_lock)) != 0)
		return (ret);

	/* Search our list of objects for a match. */
	for (ref = &data_source_head; (p = *ref) != NULL; p = p->next)
		if (strcmp(p->uri, uri) == 0)
			break;

	/*
	 * If we don't find the URI in our object list, we're done.
	 * If the object is in use (it has open cursors), we can't drop it.
	 * Otherwise, drop it.
	 */
	if (p == NULL || p->open_cursors != 0) {
		if (p != NULL)
			ret = EBUSY;
	} else {
		if ((ret = kvs_close(p->kvs)) != 0)
			ESET(session, WT_ERROR,
			    "kvs_close: %s: %s", uri, kvs_strerror(ret));
		*ref = p->next;

		free(p->uri);
		ETRET(lock_destroy(session, &p->lock));
		free(p);
	}

	ETRET(unlock(session, &global_lock));
	return (ret);
}
Пример #4
0
/*
 * kvs_recno_alloc --
 *	Allocate a new record number.
 */
static INLINE int
kvs_recno_alloc(WT_CURSOR *wt_cursor)
{
	struct kvs_record *r;
	CURSOR *cursor;
	WT_SESSION *session;
	int ret;

	cursor = (CURSOR *)wt_cursor;
	session = cursor->session;
	r = &cursor->record;

	/* Lock the data-source. */
	if ((ret = writelock(session, &cursor->data_source->lock)) != 0)
		return (ret);

	/*
	 * If not yet tracking the maximum record number, read the last record
	 * from the object and figure it out.
	 *
	 * XXX
	 * There is still a race here.  If another thread of control performs a
	 * WT_CURSOR::insert of an explicit record number (that is, the other
	 * cursor isn't configured for "append"), we could race.  If we figure
	 * out the last record in the data-source is 37, then the other thread
	 * explicitly writes record 37, things will go badly.  I don't want to
	 * lock the data-source on every update, so I'm leaving this until we
	 * write the transactional code, because that's going to change all of
	 * the locking in here.
	 */
	if (cursor->data_source->append_recno == 0) {
		if ((ret = kvs_last(cursor->data_source->kvs,
		    &cursor->record, (unsigned long)0, (unsigned long)0)) != 0)
			goto err;

		if ((ret = wt_ext->struct_unpack(wt_ext, session,
		    r->key, sizeof(r->key),
		    "r", &cursor->data_source->append_recno)) != 0)
			goto err;
	}

	wt_cursor->recno = ++cursor->data_source->append_recno;

err:	ETRET(unlock(session, &cursor->data_source->lock));
	return (ret);
}
Пример #5
0
/*
 * kvs_session_truncate --
 *	WT_SESSION::truncate method.
 */
static int
kvs_session_truncate(WT_DATA_SOURCE *dsrc,
    WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config)
{
	DATA_SOURCE *p;
	int ret, tret;

	(void)dsrc;				/* Unused parameters */

	/*
	 * Truncate should work even if the object is not yet opened: if we
	 * don't find it, open it.   We loop because we could theoretically
	 * race with other threads creating/deleting the object.
	 */
	for (;;) {
		if ((ret = writelock(session, &global_lock)) != 0)
			return (ret);

		/* Search our list of objects for a match. */
		for (p = data_source_head; p != NULL; p = p->next)
			if (strcmp(p->uri, uri) == 0)
				break;

		/* If we don't find the object, open it. */
		if (p == NULL) {
			if ((ret = unlock(session, &global_lock)) != 0)
				return (ret);
			if ((ret = open_data_source(session, uri, config)) != 0)
				return (ret);
			continue;
		}
		if (p->open_cursors == 0) {
			if ((tret = kvs_truncate(p->kvs)) != 0)
				ESET(NULL, WT_ERROR,
				    "kvs_truncate: %s: %s",
				    p->uri, kvs_strerror(tret));
		} else
			ret = EBUSY;
		ETRET(unlock(session, &global_lock));
		return (ret);
	}
	/* NOTREACHED */
}
Пример #6
0
static int
kvs_terminate(WT_DATA_SOURCE *wtds, WT_SESSION *session)
{
	DB_ENV *dbenv;
	DATA_SOURCE *ds;
	WT_EXTENSION_API *wt_api;
	int ret = 0;

	ds = (DATA_SOURCE *)wtds;
	wt_api = ds->wt_api;
	dbenv = ds->dbenv;

	if (dbenv != NULL && (ret = dbenv->close(dbenv, 0)) != 0)
		ESET(wt_api,
		    session, WT_ERROR, "DbEnv.close: %s", db_strerror(ret));

	ETRET(lock_destroy(wt_api, session, &ds->rwlock));

	return (ret);
}
Пример #7
0
static int
kvs_session_truncate(WT_DATA_SOURCE *wtds,
    WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config)
{
	DATA_SOURCE *ds;
	DB *db;
	WT_EXTENSION_API *wt_api;
	int tret, ret = 0;
	const char *name;

	(void)config;				/* Unused parameters */

	ds = (DATA_SOURCE *)wtds;
	wt_api = ds->wt_api;
						/* Get the object name */
	if ((ret = uri2name(wt_api, session, uri, &name)) != 0)
		return (ret);

	if ((ret = single_thread(wtds, session, &ds->rwlock)) != 0)
		return (ret);

	if ((ret = db_create(&db, ds->dbenv, 0)) != 0)
		ESET(wt_api,
		    session, WT_ERROR, "db_create: %s", db_strerror(ret));
	else {
		if ((ret = db->open(db,
		    NULL, name, NULL, DB_UNKNOWN, DB_TRUNCATE, 0)) != 0)
			ESET(wt_api, session, WT_ERROR,
			    "Db.open: %s", db_strerror(ret));
		if ((tret = db->close(db, 0)) != 0)
			ESET(wt_api, session, WT_ERROR,
			    "Db.close: %s", db_strerror(tret));
	}

	ETRET(unlock(wt_api, session, &ds->rwlock));
	return (ret);
}
Пример #8
0
static int
kvs_session_open_cursor(WT_DATA_SOURCE *wtds, WT_SESSION *session,
    const char *uri, WT_CONFIG_ARG *config, WT_CURSOR **new_cursor)
{
	CURSOR_SOURCE *cursor;
	DATA_SOURCE *ds;
	DB *db;
	WT_CONFIG_ITEM v;
	WT_EXTENSION_API *wt_api;
	int locked, ret;
	const char *name;

	ds = (DATA_SOURCE *)wtds;
	wt_api = ds->wt_api;
	locked = 0;
						/* Get the object name */
	if ((ret = uri2name(wt_api, session, uri, &name)) != 0)
		return (ret);
						/* Allocate the cursor */
	if ((cursor = calloc(1, sizeof(CURSOR_SOURCE))) == NULL)
		return (os_errno());
	cursor->ds = (DATA_SOURCE *)wtds;
	cursor->wt_api = wt_api;
						/* Parse configuration */
	if ((ret = wt_api->config_get(
	    wt_api, session, config, "append", &v)) != 0) {
		ESET(wt_api, session, ret,
		    "append configuration: %s",
		    wt_api->strerror(wt_api, session, ret));
		goto err;
	}
	cursor->config_append = v.val != 0;

	if ((ret = wt_api->config_get(
	    wt_api, session, config, "overwrite", &v)) != 0) {
		ESET(wt_api, session, ret,
		    "overwrite configuration: %s",
		    wt_api->strerror(wt_api, session, ret));
		goto err;
	}
	cursor->config_overwrite = v.val != 0;

	if ((ret = wt_api->config_get(
	    wt_api, session, config, "key_format", &v)) != 0) {
		ESET(wt_api, session, ret,
		    "key_format configuration: %s",
		    wt_api->strerror(wt_api, session, ret));
		goto err;
	}
	cursor->config_recno = v.len == 1 && v.str[0] == 'r';

	if ((ret = wt_api->config_get(
	    wt_api, session, config, "value_format", &v)) != 0) {
		ESET(wt_api, session, ret,
		    "value_format configuration: %s",
		    wt_api->strerror(wt_api, session, ret));
		goto err;
	}
	cursor->config_bitfield =
	    v.len == 2 && isdigit((u_char)v.str[0]) && v.str[1] == 't';

	if ((ret = writelock(wt_api, session, &ds->rwlock)) != 0)
		goto err;
	locked = 1;
				/* Open the Berkeley DB cursor */
	if ((ret = db_create(&cursor->db, ds->dbenv, 0)) != 0) {
		ESET(wt_api,
		    session, WT_ERROR, "db_create: %s", db_strerror(ret));
		goto err;
	}
	db = cursor->db;
	if ((ret = db->open(db, NULL, name, NULL,
	    cursor->config_recno ? DB_RECNO : DB_BTREE, DB_CREATE, 0)) != 0) {
		ESET(wt_api,
		    session, WT_ERROR, "Db.open: %s", db_strerror(ret));
		goto err;
	}
	if ((ret = db->cursor(db, NULL, &cursor->dbc, 0)) != 0) {
		ESET(wt_api,
		    session, WT_ERROR, "Db.cursor: %s", db_strerror(ret));
		goto err;
	}

				/* Initialize the methods */
	cursor->wtcursor.next = kvs_cursor_next;
	cursor->wtcursor.prev = kvs_cursor_prev;
	cursor->wtcursor.reset = kvs_cursor_reset;
	cursor->wtcursor.search = kvs_cursor_search;
	cursor->wtcursor.search_near = kvs_cursor_search_near;
	cursor->wtcursor.insert = kvs_cursor_insert;
	cursor->wtcursor.update = kvs_cursor_update;
	cursor->wtcursor.remove = kvs_cursor_remove;
	cursor->wtcursor.close = kvs_cursor_close;

	*new_cursor = (WT_CURSOR *)cursor;

	++ds->open_cursors;

	if (0) {
err:		free(cursor);
	}

	if (locked)
		ETRET(unlock(wt_api, session, &ds->rwlock));
	return (ret);
}
Пример #9
0
/*
 * open_data_source --
 *	Open a new data source and insert it into the list.
 */
static int
open_data_source(WT_SESSION *session, const char *uri, WT_CONFIG_ARG *config)
{
	struct kvs_config kvs_config;
	DATA_SOURCE *data_source, *p;
	int ds_lockinit, flags, locked, ret;
	char **devices, *emsg;

	devices = NULL;
	emsg = NULL;
	ds_lockinit = locked = ret = 0;

	/*
	 * The first time we open a cursor on an object, allocate an underlying
	 * data source object.
	 */
	if ((data_source =
	    (DATA_SOURCE *)calloc(1, sizeof(DATA_SOURCE))) == NULL)
		return (os_errno());
	if ((data_source->uri = strdup(uri)) == NULL)
		goto err;
	if ((ret = lock_init(session, &data_source->lock)) != 0)
		goto err;
	ds_lockinit = 1;

	/* Read the configuration. */
	if ((ret = kvs_config_read(
	    session, config, &devices, &kvs_config, &flags)) != 0)
		goto err;

	/* We require a list of devices underlying the URI. */
	if (devices[0] == NULL) {
		ESET(
		    session, EINVAL, "WT_SESSION.create: no devices specified");
		goto err;
	}

	/*
	 * kvs_open isn't re-entrant: lock things down while we make sure we
	 * don't have more than a single handle at a time.
	 */
	if ((ret = writelock(session, &global_lock)) != 0)
		goto err;
	locked = 1;

	/*
	 * Check for a match: if we find one, we raced, but we return success,
	 * someone else did the work.
	 */
	for (p = data_source_head; p != NULL; p = p->next)
		if (strcmp(p->uri, uri) == 0)
			goto err;

	/* Open the KVS handle. */
	if ((data_source->kvs =
	    kvs_open(devices, &kvs_config, flags)) == NULL) {
		emsg = kvs_create_path_string(devices);
		ESET(session, WT_ERROR,
		    "WT_SESSION.create: kvs_open: %s: %s",
		    emsg == NULL ? devices[0] : emsg, kvs_strerror(os_errno()));
		goto err;
	}

	/* Insert the new entry at the head of the list. */
	data_source->next = data_source_head;
	data_source_head = data_source;
	data_source = NULL;

err:	if (locked)
		ETRET(unlock(session, &global_lock));

	if (data_source != NULL) {
		if (data_source->uri != NULL)
			free(data_source->uri);
		if (ds_lockinit)
			ETRET(lock_destroy(session, &data_source->lock));
		free(data_source);
	}
	free(devices);
	free(emsg);
	return (ret);
}