Ejemplo n.º 1
0
void
wts_rebalance(void)
{
	WT_CONNECTION *conn;
	WT_SESSION *session;
	char cmd[1024];

	if (g.c_rebalance == 0)
		return;

	track("rebalance", 0ULL, NULL);

	/* Dump the current object. */
	testutil_check(__wt_snprintf(cmd, sizeof(cmd),
	    ".." DIR_DELIM_STR ".." DIR_DELIM_STR "wt"
	    " -h %s dump -f %s/rebalance.orig %s",
	    g.home, g.home, g.uri));
	testutil_checkfmt(system(cmd), "command failed: %s", cmd);

	/* Rebalance, then verify the object. */
	wts_reopen();
	conn = g.wts_conn;
	testutil_check(conn->open_session(conn, NULL, NULL, &session));
	if (g.logging != 0)
		(void)g.wt_api->msg_printf(g.wt_api, session,
		    "=============== rebalance start ===============");

	testutil_checkfmt(
	    session->rebalance(session, g.uri, NULL), "%s", g.uri);

	if (g.logging != 0)
		(void)g.wt_api->msg_printf(g.wt_api, session,
		    "=============== rebalance stop ===============");
	testutil_check(session->close(session, NULL));

	wts_verify("post-rebalance verify");
	wts_close();

	testutil_check(__wt_snprintf(cmd, sizeof(cmd),
	    ".." DIR_DELIM_STR ".." DIR_DELIM_STR "wt"
	    " -h %s dump -f %s/rebalance.new %s",
	    g.home, g.home, g.uri));
	testutil_checkfmt(system(cmd), "command failed: %s", cmd);

	/* Compare the old/new versions of the object. */
#ifdef _WIN32
	testutil_check(__wt_snprintf(cmd, sizeof(cmd),
	    "fc /b %s\\rebalance.orig %s\\rebalance.new > NUL",
	    g.home, g.home));
#else
	testutil_check(__wt_snprintf(cmd, sizeof(cmd),
	    "cmp %s/rebalance.orig %s/rebalance.new > /dev/null",
	    g.home, g.home));
#endif
	testutil_checkfmt(system(cmd), "command failed: %s", cmd);
}
Ejemplo n.º 2
0
Archivo: main.c Proyecto: mikety/mongo
static inline void
check(uint32_t hw, uint32_t sw, size_t len, const char *msg)
{
	testutil_checkfmt(hw == sw ? 0 : 1,
	    "%s checksum mismatch of %" WT_SIZET_FMT " bytes: %#08x != %#08x\n",
	    msg, len, hw, sw);
}
Ejemplo n.º 3
0
/*
 * check_copy --
 *	Confirm the backup worked.
 */
static void
check_copy(void)
{
	WT_CONNECTION *conn;
	WT_SESSION *session;

	wts_open(g.home_backup, 0, &conn);

	testutil_checkfmt(
	    conn->open_session(conn, NULL, NULL, &session),
	    "%s", g.home_backup);

	testutil_checkfmt(
	    session->verify(session, g.uri, NULL),
	    "%s: %s", g.home_backup, g.uri);

	testutil_checkfmt(conn->close(conn, NULL), "%s", g.home_backup);
}
Ejemplo n.º 4
0
Archivo: main.c Proyecto: ajdavis/mongo
static void
check_str(uint64_t i, char *str, bool mod)
{
	char str2[] = "0000000000000000";

	rand_str(i, str2);
	if (mod)
		str2[0] = 'A';
	testutil_checkfmt(strcmp(str, str2),
	    "strcmp failed, got %s, expected %s", str, str2);
}
Ejemplo n.º 5
0
/*
 * copy_file --
 *	Copy a single file into the backup directory.
 */
static void
copy_file(const char *name)
{
	size_t len;
	char *cmd;

	len = strlen(g.home) + strlen(g.home_backup) + strlen(name) * 2 + 20;
	cmd = dmalloc(len);
	(void)snprintf(cmd, len,
	    "cp %s/%s %s/%s", g.home, name, g.home_backup, name);
	testutil_checkfmt(system(cmd), "backup copy: %s", cmd);
	free(cmd);

	len = strlen(g.home) + strlen(g.home_backup2) + strlen(name) * 2 + 20;
	cmd = dmalloc(len);
	(void)snprintf(cmd, len,
	    "cp %s/%s %s/%s", g.home, name, g.home_backup2, name);
	testutil_checkfmt(system(cmd), "backup copy: %s", cmd);
	free(cmd);
}
/*
 * wts_read_scan --
 *	Read and verify all elements in a file.
 */
void
wts_read_scan(void)
{
    WT_CONNECTION *conn;
    WT_CURSOR *cursor;
    WT_ITEM key;
    WT_SESSION *session;
    uint64_t cnt, last_cnt;
    uint8_t *keybuf;

    conn = g.wts_conn;

    /* Set up the default key buffer. */
    key_gen_setup(&keybuf);

    /* Open a session and cursor pair. */
    testutil_check(conn->open_session(
                       conn, NULL, ops_session_config(NULL), &session));
    testutil_check(session->open_cursor(
                       session, g.uri, NULL, NULL, &cursor));

    /* Check a random subset of the records using the key. */
    for (last_cnt = cnt = 0; cnt < g.key_cnt;) {
        cnt += mmrand(NULL, 1, 17);
        if (cnt > g.rows)
            cnt = g.rows;
        if (cnt - last_cnt > 1000) {
            track("read row scan", cnt, NULL);
            last_cnt = cnt;
        }

        key.data = keybuf;
        testutil_checkfmt(
            read_row(cursor, &key, cnt, 0), "%s", "read_scan");
    }

    testutil_check(session->close(session, NULL));

    free(keybuf);
}
Ejemplo n.º 7
0
/*
 * backup --
 *	Periodically do a backup and verify it.
 */
void *
backup(void *arg)
{
	WT_CONNECTION *conn;
	WT_CURSOR *backup_cursor;
	WT_SESSION *session;
	u_int period;
	int ret;
	const char *key;

	(void)(arg);

	conn = g.wts_conn;

	/* Backups aren't supported for non-standard data sources. */
	if (DATASOURCE("helium") || DATASOURCE("kvsbdb"))
		return (NULL);

	/* Open a session. */
	testutil_check(conn->open_session(conn, NULL, NULL, &session));

	/*
	 * Perform a backup at somewhere under 10 seconds (so we get at
	 * least one done), and then at 45 second intervals.
	 */
	for (period = mmrand(NULL, 1, 10);; period = 45) {
		/* Sleep for short periods so we don't make the run wait. */
		while (period > 0 && !g.workers_finished) {
			--period;
			sleep(1);
		}
		if (g.workers_finished)
			break;

		/* Lock out named checkpoints */
		testutil_check(pthread_rwlock_wrlock(&g.backup_lock));

		/* Re-create the backup directory. */
		testutil_checkfmt(
		    system(g.home_backup_init),
		    "%s", "backup directory creation failed");

		/*
		 * open_cursor can return EBUSY if a metadata operation is
		 * currently happening - retry in that case.
		 */
		while ((ret = session->open_cursor(session,
		    "backup:", NULL, NULL, &backup_cursor)) == EBUSY)
			sleep(1);
		if (ret != 0)
			testutil_die(ret, "session.open_cursor: backup");

		while ((ret = backup_cursor->next(backup_cursor)) == 0) {
			testutil_check(
			    backup_cursor->get_key(backup_cursor, &key));
			copy_file(key);
		}

		testutil_check(backup_cursor->close(backup_cursor));
		testutil_check(pthread_rwlock_unlock(&g.backup_lock));

		check_copy();
	}

	testutil_check(session->close(session, NULL));

	return (NULL);
}
static void *
ops(void *arg)
{
    TINFO *tinfo;
    WT_CONNECTION *conn;
    WT_CURSOR *cursor, *cursor_insert;
    WT_SESSION *session;
    WT_ITEM key, value;
    uint64_t keyno, ckpt_op, reset_op, session_op;
    uint32_t op;
    uint8_t *keybuf, *valbuf;
    u_int np;
    int ckpt_available, dir, insert, intxn, notfound, readonly;
    char *ckpt_config, ckpt_name[64];

    tinfo = arg;

    conn = g.wts_conn;
    keybuf = valbuf = NULL;
    readonly = 0;			/* -Wconditional-uninitialized */

    /* Initialize the per-thread random number generator. */
    __wt_random_init(&tinfo->rnd);

    /* Set up the default key and value buffers. */
    key_gen_setup(&keybuf);
    val_gen_setup(&tinfo->rnd, &valbuf);

    /* Set the first operation where we'll create sessions and cursors. */
    session_op = 0;
    session = NULL;
    cursor = cursor_insert = NULL;

    /* Set the first operation where we'll perform checkpoint operations. */
    ckpt_op = g.c_checkpoints ? mmrand(&tinfo->rnd, 100, 10000) : 0;
    ckpt_available = 0;

    /* Set the first operation where we'll reset the session. */
    reset_op = mmrand(&tinfo->rnd, 100, 10000);

    for (intxn = 0; !tinfo->quit; ++tinfo->ops) {
        /*
         * We can't checkpoint or swap sessions/cursors while in a
         * transaction, resolve any running transaction.
         */
        if (intxn &&
                (tinfo->ops == ckpt_op || tinfo->ops == session_op)) {
            testutil_check(
                session->commit_transaction(session, NULL));
            ++tinfo->commit;
            intxn = 0;
        }

        /* Open up a new session and cursors. */
        if (tinfo->ops == session_op ||
                session == NULL || cursor == NULL) {
            if (session != NULL)
                testutil_check(session->close(session, NULL));

            testutil_check(conn->open_session(conn, NULL,
                                              ops_session_config(&tinfo->rnd), &session));

            /*
             * 10% of the time, perform some read-only operations
             * from a checkpoint.
             *
             * Skip that if we single-threaded and doing checks
             * against a Berkeley DB database, because that won't
             * work because the Berkeley DB database records won't
             * match the checkpoint.  Also skip if we are using
             * LSM, because it doesn't support reads from
             * checkpoints.
             */
            if (!SINGLETHREADED && !DATASOURCE("lsm") &&
                    ckpt_available && mmrand(&tinfo->rnd, 1, 10) == 1) {
                testutil_check(session->open_cursor(session,
                                                    g.uri, NULL, ckpt_name, &cursor));

                /* Pick the next session/cursor close/open. */
                session_op += 250;

                /* Checkpoints are read-only. */
                readonly = 1;
            } else {
                /*
                 * Open two cursors: one for overwriting and one
                 * for append (if it's a column-store).
                 *
                 * The reason is when testing with existing
                 * records, we don't track if a record was
                 * deleted or not, which means we must use
                 * cursor->insert with overwriting configured.
                 * But, in column-store files where we're
                 * testing with new, appended records, we don't
                 * want to have to specify the record number,
                 * which requires an append configuration.
                 */
                testutil_check(session->open_cursor(session,
                                                    g.uri, NULL, "overwrite", &cursor));
                if (g.type == FIX || g.type == VAR)
                    testutil_check(session->open_cursor(
                                       session, g.uri,
                                       NULL, "append", &cursor_insert));

                /* Pick the next session/cursor close/open. */
                session_op += mmrand(&tinfo->rnd, 100, 5000);

                /* Updates supported. */
                readonly = 0;
            }
        }

        /* Checkpoint the database. */
        if (tinfo->ops == ckpt_op && g.c_checkpoints) {
            /*
             * LSM and data-sources don't support named checkpoints,
             * and we can't drop a named checkpoint while there's a
             * cursor open on it, otherwise 20% of the time name the
             * checkpoint.
             */
            if (DATASOURCE("helium") || DATASOURCE("kvsbdb") ||
                    DATASOURCE("lsm") ||
                    readonly || mmrand(&tinfo->rnd, 1, 5) == 1)
                ckpt_config = NULL;
            else {
                (void)snprintf(ckpt_name, sizeof(ckpt_name),
                               "name=thread-%d", tinfo->id);
                ckpt_config = ckpt_name;
            }

            /* Named checkpoints lock out backups */
            if (ckpt_config != NULL)
                testutil_check(
                    pthread_rwlock_wrlock(&g.backup_lock));

            testutil_checkfmt(
                session->checkpoint(session, ckpt_config),
                "%s", ckpt_config == NULL ? "" : ckpt_config);

            if (ckpt_config != NULL)
                testutil_check(
                    pthread_rwlock_unlock(&g.backup_lock));

            /* Rephrase the checkpoint name for cursor open. */
            if (ckpt_config == NULL)
                strcpy(ckpt_name,
                       "checkpoint=WiredTigerCheckpoint");
            else
                (void)snprintf(ckpt_name, sizeof(ckpt_name),
                               "checkpoint=thread-%d", tinfo->id);
            ckpt_available = 1;

            /* Pick the next checkpoint operation. */
            ckpt_op += mmrand(&tinfo->rnd, 5000, 20000);
        }

        /*
         * Reset the session every now and then, just to make sure that
         * operation gets tested. Note the test is not for equality, we
         * have to do the reset outside of a transaction.
         */
        if (tinfo->ops > reset_op && !intxn) {
            testutil_check(session->reset(session));

            /* Pick the next reset operation. */
            reset_op += mmrand(&tinfo->rnd, 20000, 50000);
        }

        /*
         * If we're not single-threaded and we're not in a transaction,
         * start a transaction 20% of the time.
         */
        if (!SINGLETHREADED &&
                !intxn && mmrand(&tinfo->rnd, 1, 10) >= 8) {
            testutil_check(
                session->begin_transaction(session, NULL));
            intxn = 1;
        }

        insert = notfound = 0;

        keyno = mmrand(&tinfo->rnd, 1, (u_int)g.rows);
        key.data = keybuf;
        value.data = valbuf;

        /*
         * Perform some number of operations: the percentage of deletes,
         * inserts and writes are specified, reads are the rest.  The
         * percentages don't have to add up to 100, a high percentage
         * of deletes will mean fewer inserts and writes.  Modifications
         * are always followed by a read to confirm it worked.
         */
        op = readonly ? UINT32_MAX : mmrand(&tinfo->rnd, 1, 100);
        if (op < g.c_delete_pct) {
            ++tinfo->remove;
            switch (g.type) {
            case ROW:
                /*
                 * If deleting a non-existent record, the cursor
                 * won't be positioned, and so can't do a next.
                 */
                if (row_remove(cursor, &key, keyno, &notfound))
                    goto deadlock;
                break;
            case FIX:
            case VAR:
                if (col_remove(cursor, &key, keyno, &notfound))
                    goto deadlock;
                break;
            }
        } else if (op < g.c_delete_pct + g.c_insert_pct) {
            ++tinfo->insert;
            switch (g.type) {
            case ROW:
                if (row_insert(
                            tinfo, cursor, &key, &value, keyno))
                    goto deadlock;
                insert = 1;
                break;
            case FIX:
            case VAR:
                /*
                 * We can only append so many new records, if
                 * we've reached that limit, update a record
                 * instead of doing an insert.
                 */
                if (g.append_cnt >= g.append_max)
                    goto skip_insert;

                /* Insert, then reset the insert cursor. */
                if (col_insert(tinfo,
                               cursor_insert, &key, &value, &keyno))
                    goto deadlock;
                testutil_check(
                    cursor_insert->reset(cursor_insert));

                insert = 1;
                break;
            }
        } else if (
            op < g.c_delete_pct + g.c_insert_pct + g.c_write_pct) {
            ++tinfo->update;
            switch (g.type) {
            case ROW:
                if (row_update(
                            tinfo, cursor, &key, &value, keyno))
                    goto deadlock;
                break;
            case FIX:
            case VAR:
skip_insert:
                if (col_update(tinfo,
                               cursor, &key, &value, keyno))
                    goto deadlock;
                break;
            }
        } else {
            ++tinfo->search;
            if (read_row(cursor, &key, keyno, 0))
                if (intxn)
                    goto deadlock;
            continue;
        }

        /*
         * The cursor is positioned if we did any operation other than
         * insert, do a small number of next/prev cursor operations in
         * a random direction.
         */
        if (!insert) {
            dir = (int)mmrand(&tinfo->rnd, 0, 1);
            for (np = 0; np < mmrand(&tinfo->rnd, 1, 100); ++np) {
                if (notfound)
                    break;
                if (nextprev(cursor, dir, &notfound))
                    goto deadlock;
            }
        }

        /* Read to confirm the operation. */
        ++tinfo->search;
        if (read_row(cursor, &key, keyno, 0))
            goto deadlock;

        /* Reset the cursor: there is no reason to keep pages pinned. */
        testutil_check(cursor->reset(cursor));

        /*
         * If we're in the transaction, commit 40% of the time and
         * rollback 10% of the time.
         */
        if (intxn)
            switch (mmrand(&tinfo->rnd, 1, 10)) {
            case 1:
            case 2:
            case 3:
            case 4:		/* 40% */
                testutil_check(session->commit_transaction(
                                   session, NULL));
                ++tinfo->commit;
                intxn = 0;
                break;
            case 5:					/* 10% */
                if (0) {
deadlock:
                    ++tinfo->deadlock;
                }
                testutil_check(session->rollback_transaction(
                                   session, NULL));
                ++tinfo->rollback;
                intxn = 0;
                break;
            default:
                break;
            }
    }

    if (session != NULL)
        testutil_check(session->close(session, NULL));

    free(keybuf);
    free(valbuf);

    tinfo->state = TINFO_COMPLETE;
    return (NULL);
}
Ejemplo n.º 9
0
/*
 * backup --
 *	Periodically do a backup and verify it.
 */
void *
backup(void *arg)
{
	WT_CONNECTION *conn;
	WT_CURSOR *backup_cursor;
	WT_DECL_RET;
	WT_SESSION *session;
	u_int incremental, period;
	bool full;
	const char *config, *key;

	(void)(arg);

	conn = g.wts_conn;

	/* Backups aren't supported for non-standard data sources. */
	if (DATASOURCE("helium") || DATASOURCE("kvsbdb"))
		return (NULL);

	/* Open a session. */
	testutil_check(conn->open_session(conn, NULL, NULL, &session));

	/*
	 * Perform a full backup at somewhere under 10 seconds (that way there's
	 * at least one), then at larger intervals, optionally do incremental
	 * backups between full backups.
	 */
	incremental = 0;
	for (period = mmrand(NULL, 1, 10);; period = mmrand(NULL, 20, 45)) {
		/* Sleep for short periods so we don't make the run wait. */
		while (period > 0 && !g.workers_finished) {
			--period;
			sleep(1);
		}

		/*
		 * We can't drop named checkpoints while there's a backup in
		 * progress, serialize backups with named checkpoints. Wait
		 * for the checkpoint to complete, otherwise backups might be
		 * starved out.
		 */
		testutil_check(pthread_rwlock_wrlock(&g.backup_lock));
		if (g.workers_finished) {
			testutil_check(pthread_rwlock_unlock(&g.backup_lock));
			break;
		}

		if (incremental) {
			config = "target=(\"log:\")";
			full = false;
		} else {
			/* Re-create the backup directory. */
			testutil_checkfmt(
			    system(g.home_backup_init),
			    "%s", "backup directory creation failed");

			config = NULL;
			full = true;
		}

		/*
		 * open_cursor can return EBUSY if concurrent with a metadata
		 * operation, retry in that case.
		 */
		while ((ret = session->open_cursor(
		    session, "backup:", NULL, config, &backup_cursor)) == EBUSY)
			__wt_yield();
		if (ret != 0)
			testutil_die(ret, "session.open_cursor: backup");

		while ((ret = backup_cursor->next(backup_cursor)) == 0) {
			testutil_check(
			    backup_cursor->get_key(backup_cursor, &key));
			copy_file(session, key);
		}
		if (ret != WT_NOTFOUND)
			testutil_die(ret, "backup-cursor");

		/* After an incremental backup, truncate the log files. */
		if (incremental)
			testutil_check(session->truncate(
			    session, "log:", backup_cursor, NULL, NULL));

		testutil_check(backup_cursor->close(backup_cursor));
		testutil_check(pthread_rwlock_unlock(&g.backup_lock));

		/*
		 * If automatic log archival isn't configured, optionally do
		 * incremental backups after each full backup. If we're not
		 * doing any more incrementals, verify the backup (we can't
		 * verify intermediate states, once we perform recovery on the
		 * backup database, we can't do any more incremental backups).
		 */
		if (full)
			incremental =
			    g.c_logging_archive ? 1 : mmrand(NULL, 1, 5);
		if (--incremental == 0)
			check_copy();
	}

	if (incremental != 0)
		check_copy();

	testutil_check(session->close(session, NULL));

	return (NULL);
}