Example #1
0
/*
 * __wt_meta_track_off --
 *	Turn off metadata operation tracking, unrolling on error.
 */
int
__wt_meta_track_off(WT_SESSION_IMPL *session, int unroll)
{
	WT_BTREE *saved_btree;
	WT_DECL_RET;
	WT_META_TRACK *trk, *trk_orig;
	const char *ckpt_cfg[] = API_CONF_DEFAULTS(session, checkpoint, NULL);

	WT_ASSERT(session,
	    WT_META_TRACKING(session) && session->meta_track_nest > 0);
	if (--session->meta_track_nest != 0)
		return (0);

	trk_orig = session->meta_track;
	trk = session->meta_track_next;

	/* Turn off tracking for unroll. */
	session->meta_track_next = session->meta_track_sub = NULL;

	while (--trk >= trk_orig)
		WT_TRET(__meta_track_apply(session, trk, unroll));

	/* If the operation succeeded, checkpoint the metadata. */
	if (!unroll && ret == 0 && session->metafile != NULL) {
		saved_btree = session->btree;
		session->btree = session->metafile;
		ret = __wt_checkpoint(session, ckpt_cfg);
		session->btree = saved_btree;
	}

	return (ret);
}
Example #2
0
/*
 * __wt_meta_track_off --
 *	Turn off metadata operation tracking, unrolling on error.
 */
int
__wt_meta_track_off(WT_SESSION_IMPL *session, int need_sync, int unroll)
{
	WT_DECL_RET;
	WT_META_TRACK *trk, *trk_orig;

	WT_ASSERT(session,
	    WT_META_TRACKING(session) && session->meta_track_nest > 0);

	trk_orig = session->meta_track;
	trk = session->meta_track_next;

	/* If it was a nested transaction, there is nothing to do. */
	if (--session->meta_track_nest != 0)
		return (0);

	/* Turn off tracking for unroll. */
	session->meta_track_next = session->meta_track_sub = NULL;

	/*
	 * If there were no operations logged, return now and avoid unnecessary
	 * metadata checkpoints.  For example, this happens if attempting to
	 * create a data source that already exists (or drop one that doesn't).
	 */
	if (trk == trk_orig)
		return (0);

	while (--trk >= trk_orig)
		WT_TRET(__meta_track_apply(session, trk, unroll));

	/*
	 * Unroll operations don't need to flush the metadata.
	 *
	 * Also, if we don't have the metadata handle (e.g, we're in the
	 * process of creating the metadata), we can't sync it.
	 */
	if (unroll || ret != 0 || !need_sync || session->meta_dhandle == NULL)
		return (ret);

	/* If we're logging, make sure the metadata update was flushed. */
	if (FLD_ISSET(S2C(session)->log_flags, WT_CONN_LOG_ENABLED)) {
		if (!FLD_ISSET(S2C(session)->txn_logsync,
		    WT_LOG_DSYNC | WT_LOG_FSYNC))
			WT_WITH_DHANDLE(session, session->meta_dhandle,
			    ret = __wt_txn_checkpoint_log(session,
			    0, WT_TXN_LOG_CKPT_SYNC, NULL));
	} else {
		WT_WITH_DHANDLE(session, session->meta_dhandle,
		    ret = __wt_checkpoint(session, NULL));
		WT_RET(ret);
		WT_WITH_DHANDLE(session, session->meta_dhandle,
		    ret = __wt_checkpoint_sync(session, NULL));
	}

	return (ret);
}
Example #3
0
/*
 * __wt_meta_track_sub_off --
 *	Commit a group of operations independent of the main transaction.
 */
int
__wt_meta_track_sub_off(WT_SESSION_IMPL *session)
{
	WT_DECL_RET;
	WT_META_TRACK *trk, *trk_orig;

	if (!WT_META_TRACKING(session) || session->meta_track_sub == NULL)
		return (0);

	trk_orig = session->meta_track_sub;
	trk = session->meta_track_next;

	/* Turn off tracking for unroll. */
	session->meta_track_next = session->meta_track_sub = NULL;

	while (--trk >= trk_orig)
		WT_TRET(__meta_track_apply(session, trk));

	session->meta_track_next = trk_orig;
	return (ret);
}
Example #4
0
/*
 * __wt_meta_track_off --
 *	Turn off metadata operation tracking, unrolling on error.
 */
int
__wt_meta_track_off(WT_SESSION_IMPL *session, bool need_sync, bool unroll)
{
	WT_DECL_RET;
	WT_META_TRACK *trk, *trk_orig;
	WT_SESSION_IMPL *ckpt_session;

	WT_ASSERT(session,
	    WT_META_TRACKING(session) && session->meta_track_nest > 0);

	trk_orig = session->meta_track;
	trk = session->meta_track_next;

	/* If it was a nested transaction, there is nothing to do. */
	if (--session->meta_track_nest != 0)
		return (0);

	/* Turn off tracking for unroll. */
	session->meta_track_next = session->meta_track_sub = NULL;

	/*
	 * If there were no operations logged, return now and avoid unnecessary
	 * metadata checkpoints.  For example, this happens if attempting to
	 * create a data source that already exists (or drop one that doesn't).
	 */
	if (trk == trk_orig)
		return (0);

	if (unroll) {
		while (--trk >= trk_orig)
			WT_TRET(__meta_track_unroll(session, trk));
		/* Unroll operations don't need to flush the metadata. */
		return (ret);
	}

	/*
	 * If we don't have the metadata cursor (e.g, we're in the process of
	 * creating the metadata), we can't sync it.
	 */
	if (!need_sync || session->meta_cursor == NULL ||
	    F_ISSET(S2C(session), WT_CONN_IN_MEMORY))
		goto done;

	/* If we're logging, make sure the metadata update was flushed. */
	if (FLD_ISSET(S2C(session)->log_flags, WT_CONN_LOG_ENABLED)) {
		WT_WITH_DHANDLE(session,
		    WT_SESSION_META_DHANDLE(session),
		    ret = __wt_txn_checkpoint_log(
			session, false, WT_TXN_LOG_CKPT_SYNC, NULL));
		WT_RET(ret);
	} else {
		WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_SCHEMA));
		ckpt_session = S2C(session)->meta_ckpt_session;
		/*
		 * If this operation is part of a running transaction, that
		 * should be included in the checkpoint.
		 */
		ckpt_session->txn.id = session->txn.id;
		F_SET(ckpt_session, WT_SESSION_LOCKED_METADATA);
		WT_WITH_METADATA_LOCK(session, ret,
		    WT_WITH_DHANDLE(ckpt_session,
			WT_SESSION_META_DHANDLE(session),
			ret = __wt_checkpoint(ckpt_session, NULL)));
		F_CLR(ckpt_session, WT_SESSION_LOCKED_METADATA);
		ckpt_session->txn.id = WT_TXN_NONE;
		WT_RET(ret);
		WT_WITH_DHANDLE(session,
		    WT_SESSION_META_DHANDLE(session),
		    ret = __wt_checkpoint_sync(session, NULL));
		WT_RET(ret);
	}

done:	/* Apply any tracked operations post-commit. */
	for (; trk_orig < trk; trk_orig++)
		WT_TRET(__meta_track_apply(session, trk_orig));
	return (ret);
}
Example #5
0
/*
 * __wt_meta_track_off --
 *	Turn off metadata operation tracking, unrolling on error.
 */
int
__wt_meta_track_off(WT_SESSION_IMPL *session, bool need_sync, bool unroll)
{
	WT_DECL_RET;
	WT_META_TRACK *trk, *trk_orig;
	WT_SESSION_IMPL *ckpt_session;
	int saved_ret;
	bool did_drop;

	saved_ret = 0;

	WT_ASSERT(session,
	    WT_META_TRACKING(session) && session->meta_track_nest > 0);

	trk_orig = session->meta_track;
	trk = session->meta_track_next;

	/* If it was a nested transaction, there is nothing to do. */
	if (--session->meta_track_nest != 0)
		return (0);

	/* Turn off tracking for unroll. */
	session->meta_track_next = session->meta_track_sub = NULL;

	/*
	 * If there were no operations logged, skip unnecessary metadata
	 * checkpoints.  For example, this happens if attempting to create a
	 * data source that already exists (or drop one that doesn't).
	 */
	if (trk == trk_orig)
		goto err;

	/* Unrolling doesn't require syncing the metadata. */
	if (unroll)
		goto err;

	if (F_ISSET(session, WT_SESSION_SCHEMA_TXN)) {
		F_CLR(session, WT_SESSION_SCHEMA_TXN);
#ifdef WT_ENABLE_SCHEMA_TXN
		WT_ERR(__wt_txn_commit(session, NULL));
		__wt_errx(session, "TRACK: Commit internal schema txn");
#endif
	}

	/*
	 * If we don't have the metadata cursor (e.g, we're in the process of
	 * creating the metadata), we can't sync it.
	 */
	if (!need_sync || session->meta_cursor == NULL ||
	    F_ISSET(S2C(session), WT_CONN_IN_MEMORY))
		goto err;

	/* If we're logging, make sure the metadata update was flushed. */
	if (FLD_ISSET(S2C(session)->log_flags, WT_CONN_LOG_ENABLED))
		WT_WITH_DHANDLE(session,
		    WT_SESSION_META_DHANDLE(session),
		    ret = __wt_txn_checkpoint_log(
		    session, false, WT_TXN_LOG_CKPT_SYNC, NULL));
	else {
		WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_SCHEMA));
		ckpt_session = S2C(session)->meta_ckpt_session;
		/*
		 * If this operation is part of a running transaction, that
		 * should be included in the checkpoint.
		 */
		ckpt_session->txn.id = session->txn.id;
		WT_ASSERT(session,
		    !F_ISSET(session, WT_SESSION_LOCKED_METADATA));
		WT_WITH_DHANDLE(ckpt_session, WT_SESSION_META_DHANDLE(session),
		    WT_WITH_METADATA_LOCK(ckpt_session,
			ret = __wt_checkpoint(ckpt_session, NULL)));
		ckpt_session->txn.id = WT_TXN_NONE;
		if (ret == 0)
			WT_WITH_DHANDLE(session,
			    WT_SESSION_META_DHANDLE(session),
			    ret = __wt_checkpoint_sync(session, NULL));
	}

err:	/*
	 * Undo any tracked operations on failure.
	 * Apply any tracked operations post-commit.
	 */
	did_drop = false;
	if (unroll || ret != 0) {
		saved_ret = ret;
		ret = 0;
		while (--trk >= trk_orig) {
			did_drop = did_drop || trk->op == WT_ST_DROP_COMMIT;
			WT_TRET(__meta_track_unroll(session, trk));
		}
	} else
		for (; trk_orig < trk; trk_orig++) {
			did_drop = did_drop ||
			    trk_orig->op == WT_ST_DROP_COMMIT;
			WT_TRET(__meta_track_apply(session, trk_orig));
		}

	if (F_ISSET(session, WT_SESSION_SCHEMA_TXN)) {
		F_CLR(session, WT_SESSION_SCHEMA_TXN);
		/*
		 * We should have committed above unless we're unrolling, there
		 * was an error or the operation was a noop.
		 */
		WT_ASSERT(session, unroll || saved_ret != 0 ||
		    session->txn.mod_count == 0);
#ifdef WT_ENABLE_SCHEMA_TXN
		__wt_err(session, saved_ret,
		    "TRACK: Abort internal schema txn");
		WT_TRET(__wt_txn_rollback(session, NULL));
#endif
	}

	/*
	 * Wake up the sweep thread: particularly for the in-memory
	 * storage engine, we want to reclaim space immediately.
	 */
	if (did_drop && S2C(session)->sweep_cond != NULL)
		__wt_cond_signal(session, S2C(session)->sweep_cond);

	if (ret != 0)
		WT_PANIC_RET(session, ret,
		    "failed to apply or unroll all tracked operations");
	return (saved_ret == 0 ? 0 : saved_ret);
}