static void initiateSnowFlake (SnowScreen *ss, SnowFlake *sf) { /* TODO: possibly place snowflakes based on FOV, instead of a cube. */ //int boxing = starGetScreenBoxing (ss->s->display); float init; // speed of star sf->xs = mmrand(-50000, 50000, 5000); sf->ys = mmrand(-50000, 50000, 5000); sf->zs = mmrand(000, 200, 2000); //TODO: possibly place stars based on FOV, instead of a cube. sf->x = ss->s->width * .5 + starGetStarOffsetX (ss->s->display); // X Offset sf->y = ss->s->height * .5 + starGetStarOffsetY (ss->s->display); // Y Offset sf->z = mmrand(000, 0.1, 5000); init = mmrand(0,100, 1); //init = distance to center of the screen sf->x += init * sf->xs; sf->y += init * sf->ys; /* switch (snowGetSnowDirection (ss->s->display)) { case SnowDirectionTopToBottom: sf->x = mmRand (-boxing, ss->s->width + boxing, 1); sf->xs = mmRand (-1, 1, 500); sf->y = mmRand (-300, 0, 1); sf->ys = mmRand (1, 3, 1); break; case SnowDirectionBottomToTop: sf->x = mmRand (-boxing, ss->s->width + boxing, 1); sf->xs = mmRand (-1, 1, 500); sf->y = mmRand (ss->s->height, ss->s->height + 300, 1); sf->ys = -mmRand (1, 3, 1); break; case SnowDirectionRightToLeft: sf->x = mmRand (ss->s->width, ss->s->width + 300, 1); sf->xs = -mmRand (1, 3, 1); sf->y = mmRand (-boxing, ss->s->height + boxing, 1); sf->ys = mmRand (-1, 1, 500); break; case SnowDirectionLeftToRight: sf->x = mmRand (-300, 0, 1); sf->xs = mmRand (1, 3, 1); sf->y = mmRand (-boxing, ss->s->height + boxing, 1); sf->ys = mmRand (-1, 1, 500); break; default: break; } sf->z = mmRand (-snowGetScreenDepth (ss->s->display), 0.1, 5000); sf->zs = mmRand (-1000, 1000, 500000); sf->ra = mmRand (-1000, 1000, 50); sf->rs = mmRand (-1000, 1000, 1000);*/ }
void val_gen(WT_RAND_STATE *rnd, WT_ITEM *value, uint64_t keyno) { char *p; p = value->mem; value->data = value->mem; /* * Fixed-length records: take the low N bits from the last digit of * the record number. */ if (g.type == FIX) { switch (g.c_bitcnt) { case 8: p[0] = (char)mmrand(rnd, 1, 0xff); break; case 7: p[0] = (char)mmrand(rnd, 1, 0x7f); break; case 6: p[0] = (char)mmrand(rnd, 1, 0x3f); break; case 5: p[0] = (char)mmrand(rnd, 1, 0x1f); break; case 4: p[0] = (char)mmrand(rnd, 1, 0x0f); break; case 3: p[0] = (char)mmrand(rnd, 1, 0x07); break; case 2: p[0] = (char)mmrand(rnd, 1, 0x03); break; case 1: p[0] = 1; break; } value->size = 1; return; } /* * WiredTiger doesn't store zero-length data items in row-store files, * test that by inserting a zero-length data item every so often. */ if (keyno % 63 == 0) { p[0] = '\0'; value->size = 0; return; } /* * Start the data with a 10-digit number. * * For row and non-repeated variable-length column-stores, change the * leading number to ensure every data item is unique. For repeated * variable-length column-stores (that is, to test run-length encoding), * use the same data value all the time. */ if ((g.type == ROW || g.type == VAR) && g.c_repeat_data_pct != 0 && mmrand(rnd, 1, 100) < g.c_repeat_data_pct) { (void)strcpy(p, "DUPLICATEV"); p[10] = '/'; value->size = val_dup_data_len; } else { (void)sprintf(p, "%010" PRIu64, keyno); p[10] = '/'; value->size = value_len(rnd, keyno, g.c_value_min, g.c_value_max); } }
void val_gen_setup(WT_RAND_STATE *rnd, WT_ITEM *value) { size_t i, len; char *p; memset(value, 0, sizeof(WT_ITEM)); /* * Set initial buffer contents to recognizable text. * * Add a few extra bytes in order to guarantee we can always offset * into the buffer by a few extra bytes, used to generate different * data for column-store run-length encoded files. */ len = MAX(KILOBYTE(100), g.c_value_max) + 20; p = dmalloc(len); for (i = 0; i < len; ++i) p[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % 26]; value->mem = p; value->memsize = len; value->data = value->mem; value->size = 0; val_dup_data_len = value_len(rnd, (uint64_t)mmrand(rnd, 1, 20), g.c_value_min, g.c_value_max); }
void key_len_setup(void) { size_t i; uint32_t max; /* * The key is a variable length item with a leading 10-digit value. * Since we have to be able re-construct it from the record number * (when doing row lookups), we pre-load a set of random lengths in * a lookup table, and then use the record number to choose one of * the pre-loaded lengths. * * Fill in the random key lengths. * * Focus on relatively small items, admitting the possibility of larger * items. Pick a size close to the minimum most of the time, only create * a larger item 1 in 20 times. */ for (i = 0; i < sizeof(g.key_rand_len) / sizeof(g.key_rand_len[0]); ++i) { max = g.c_key_max; if (i % 20 != 0 && max > g.c_key_min + 20) max = g.c_key_min + 20; g.key_rand_len[i] = mmrand(NULL, g.c_key_min, max); } }
void val_gen(WT_RAND_STATE *rnd, WT_ITEM *value, uint64_t keyno) { char *p; p = value->mem; value->data = value->mem; /* * Fixed-length records: take the low N bits from the last digit of * the record number. */ if (g.type == FIX) { switch (g.c_bitcnt) { case 8: p[0] = (char)mmrand(rnd, 1, 0xff); break; case 7: p[0] = (char)mmrand(rnd, 1, 0x7f); break; case 6: p[0] = (char)mmrand(rnd, 1, 0x3f); break; case 5: p[0] = (char)mmrand(rnd, 1, 0x1f); break; case 4: p[0] = (char)mmrand(rnd, 1, 0x0f); break; case 3: p[0] = (char)mmrand(rnd, 1, 0x07); break; case 2: p[0] = (char)mmrand(rnd, 1, 0x03); break; case 1: p[0] = 1; break; } value->size = 1; return; } /* * WiredTiger doesn't store zero-length data items in row-store files, * test that by inserting a zero-length data item every so often. */ if (keyno % 63 == 0) { p[0] = '\0'; value->size = 0; return; } /* * Data items have unique leading numbers by default and random lengths; * variable-length column-stores use a duplicate data value to test RLE. */ if (g.type == VAR && mmrand(rnd, 1, 100) < g.c_repeat_data_pct) { (void)strcpy(p, "DUPLICATEV"); p[10] = '/'; value->size = val_dup_data_len; } else { u64_to_string_zf(keyno, p, 11); p[10] = '/'; value->size = value_len(rnd, keyno, g.c_value_min, g.c_value_max); } }
void key_gen_insert(WT_RAND_STATE *rnd, WT_ITEM *key, uint64_t keyno) { static const char * const suffix[15] = { "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15" }; key_gen_common(key, keyno, suffix[mmrand(rnd, 1, 15) - 1]); }
/* * compaction -- * Periodically do a compaction operation. */ WT_THREAD_RET compact(void *arg) { WT_CONNECTION *conn; WT_DECL_RET; WT_SESSION *session; u_int period; (void)(arg); /* Compaction isn't supported for all data sources. */ if (DATASOURCE("helium") || DATASOURCE("kvsbdb")) return (WT_THREAD_RET_VALUE); /* Open a session. */ conn = g.wts_conn; testutil_check(conn->open_session(conn, NULL, NULL, &session)); /* * Perform compaction at somewhere under 15 seconds (so we get at * least one done), and then at 23 second intervals. */ for (period = mmrand(NULL, 1, 15);; period = 23) { /* Sleep for short periods so we don't make the run wait. */ while (period > 0 && !g.workers_finished) { --period; __wt_sleep(1, 0); } if (g.workers_finished) break; /* * Compact can return EBUSY if concurrent with alter or if there * is eviction pressure, or we collide with checkpoints. * * Compact returns ETIMEDOUT if the compaction doesn't finish in * in some number of seconds. We don't configure a timeout and * occasionally exceed the default of 1200 seconds. */ ret = session->compact(session, g.uri, NULL); if (ret != 0 && ret != EBUSY && ret != ETIMEDOUT && ret != WT_ROLLBACK) testutil_die(ret, "session.compact"); } testutil_check(session->close(session, NULL)); return (WT_THREAD_RET_VALUE); }
static inline uint32_t value_len(WT_RAND_STATE *rnd, uint64_t keyno, uint32_t min, uint32_t max) { /* * Focus on relatively small items, admitting the possibility of larger * items. Pick a size close to the minimum most of the time, only create * a larger item 1 in 20 times, and a really big item 1 in somewhere * around 2500 items. */ if (keyno % 2500 == 0 && max < KILOBYTE(80)) { min = KILOBYTE(80); max = KILOBYTE(100); } else if (keyno % 20 != 0 && max > min + 20) max = min + 20; return (mmrand(rnd, min, max)); }
/* * 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; int ret; conn = g.wts_conn; /* Set up the default key buffer. */ key_gen_setup(&keybuf); /* Open a session and cursor pair. */ if ((ret = conn->open_session( conn, NULL, ops_session_config(NULL), &session)) != 0) die(ret, "connection.open_session"); if ((ret = session->open_cursor( session, g.uri, NULL, NULL, &cursor)) != 0) die(ret, "session.open_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; if ((ret = read_row(cursor, &key, cnt)) != 0) die(ret, "read_scan"); } if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); free(keybuf); }
/* * ops_session_config -- * Return the current session configuration. */ static const char * ops_session_config(uint64_t *rnd) { u_int v; /* * The only current session configuration is the isolation level. */ if ((v = g.c_isolation_flag) == ISOLATION_RANDOM) v = mmrand(rnd, 2, 4); switch (v) { case ISOLATION_READ_UNCOMMITTED: return ("isolation=read-uncommitted"); case ISOLATION_READ_COMMITTED: return ("isolation=read-committed"); case ISOLATION_SNAPSHOT: default: return ("isolation=snapshot"); } }
/* * compaction -- * Periodically do a compaction operation. */ void * compact(void *arg) { WT_CONNECTION *conn; WT_SESSION *session; u_int period; int ret; (void)(arg); /* Compaction isn't supported for all data sources. */ if (DATASOURCE("helium") || DATASOURCE("kvsbdb")) return (NULL); /* Open a session. */ conn = g.wts_conn; testutil_check(conn->open_session(conn, NULL, NULL, &session)); /* * Perform compaction at somewhere under 15 seconds (so we get at * least one done), and then at 23 second intervals. */ for (period = mmrand(NULL, 1, 15);; period = 23) { /* 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; if ((ret = session->compact( session, g.uri, NULL)) != 0 && ret != WT_ROLLBACK) testutil_die(ret, "session.compact"); } testutil_check(session->close(session, NULL)); return (NULL); }
/* * alter -- * Periodically alter a table's metadata. */ void * alter(void *arg) { WT_CONNECTION *conn; WT_SESSION *session; u_int period; bool access_value; char buf[32]; (void)(arg); conn = g.wts_conn; /* * Only alter the access pattern hint. If we alter the cache resident * setting we may end up with a setting that fills cache and doesn't * allow it to be evicted. */ access_value = false; /* Open a session */ testutil_check(conn->open_session(conn, NULL, NULL, &session)); while (!g.workers_finished) { period = mmrand(NULL, 1, 10); snprintf(buf, sizeof(buf), "access_pattern_hint=%s", access_value ? "random" : "none"); access_value = !access_value; if (session->alter(session, g.uri, buf) != 0) break; while (period > 0 && !g.workers_finished) { --period; sleep(1); } } testutil_check(session->close(session, NULL)); return (NULL); }
static void initiateSnowFlake (SnowScreen *ss, SnowFlake *sf) { /* TODO: possibly place snowflakes based on FOV, instead of a cube. */ int boxing = firefliesGetScreenBoxing (ss->s->display); sf->x = mmrand(-boxing, ss->s->width + boxing, 1); sf->y = mmrand(-boxing, ss->s->height + boxing, 1); sf->z = mmrand(-firefliesGetScreenDepth (ss->s->display), 0.1, 5000); sf->lifespan = mmrand(50,1000, 100); sf->age = 0.0; // speed of firefly int i = 0; for (i = 0; i < 4; i++) { sf->xs[i] = mmrand(-3000, 3000, 1000); sf->ys[i] = mmrand(-3000, 3000, 1000); sf->zs[i] = mmrand(-1000, 1000, 500000); } }
/* * 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); }
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, session_op; uint32_t op; uint8_t *keybuf, *valbuf; u_int np; int ckpt_available, dir, insert, intxn, notfound, readonly, ret; char *ckpt_config, ckpt_name[64]; tinfo = arg; /* Initialize the per-thread random number generator. */ __wt_random_init(&tinfo->rnd); conn = g.wts_conn; keybuf = valbuf = NULL; readonly = 0; /* -Wconditional-uninitialized */ /* 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; 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)) { if ((ret = session->commit_transaction( session, NULL)) != 0) die(ret, "session.commit_transaction"); ++tinfo->commit; intxn = 0; } /* Open up a new session and cursors. */ if (tinfo->ops == session_op || session == NULL || cursor == NULL) { if (session != NULL && (ret = session->close(session, NULL)) != 0) die(ret, "session.close"); if ((ret = conn->open_session(conn, NULL, ops_session_config(&tinfo->rnd), &session)) != 0) die(ret, "connection.open_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) { if ((ret = session->open_cursor(session, g.uri, NULL, ckpt_name, &cursor)) != 0) die(ret, "session.open_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. */ if ((ret = session->open_cursor(session, g.uri, NULL, "overwrite", &cursor)) != 0) die(ret, "session.open_cursor"); if ((g.type == FIX || g.type == VAR) && (ret = session->open_cursor(session, g.uri, NULL, "append", &cursor_insert)) != 0) die(ret, "session.open_cursor"); /* 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 && (ret = pthread_rwlock_wrlock(&g.backup_lock)) != 0) die(ret, "pthread_rwlock_wrlock: backup lock"); if ((ret = session->checkpoint(session, ckpt_config)) != 0) die(ret, "session.checkpoint%s%s", ckpt_config == NULL ? "" : ": ", ckpt_config == NULL ? "" : ckpt_config); if (ckpt_config != NULL && (ret = pthread_rwlock_unlock(&g.backup_lock)) != 0) die(ret, "pthread_rwlock_wrlock: 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); } /* * 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) { if ((ret = session->begin_transaction(session, NULL)) != 0) die(ret, "session.begin_transaction"); 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, ¬found)) goto deadlock; break; case FIX: case VAR: if (col_remove(cursor, &key, keyno, ¬found)) 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; if ((ret = cursor_insert->reset(cursor_insert)) != 0) die(ret, "cursor.reset"); 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)) 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, 8); ++np) { if (notfound) break; if (nextprev(cursor, dir, ¬found)) goto deadlock; } } /* Read to confirm the operation. */ ++tinfo->search; if (read_row(cursor, &key, keyno)) goto deadlock; /* Reset the cursor: there is no reason to keep pages pinned. */ if ((ret = cursor->reset(cursor)) != 0) die(ret, "cursor.reset"); /* * 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% */ if ((ret = session->commit_transaction( session, NULL)) != 0) die(ret, "session.commit_transaction"); ++tinfo->commit; intxn = 0; break; case 5: /* 10% */ if (0) { deadlock: ++tinfo->deadlock; } if ((ret = session->rollback_transaction( session, NULL)) != 0) die(ret, "session.rollback_transaction"); ++tinfo->rollback; intxn = 0; break; default: break; } } if (session != NULL && (ret = session->close(session, NULL)) != 0) die(ret, "session.close"); free(keybuf); free(valbuf); tinfo->state = TINFO_COMPLETE; return (NULL); }
/* * 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. */ if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_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 */ if ((ret = pthread_rwlock_wrlock(&g.backup_lock)) != 0) die(ret, "pthread_rwlock_wrlock: backup lock"); /* Re-create the backup directory. */ if ((ret = system(g.home_backup_init)) != 0) die(ret, "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) die(ret, "session.open_cursor: backup"); while ((ret = backup_cursor->next(backup_cursor)) == 0) { if ((ret = backup_cursor->get_key(backup_cursor, &key)) != 0) die(ret, "cursor.get_key"); copy_file(key); } if ((ret = backup_cursor->close(backup_cursor)) != 0) die(ret, "cursor.close"); if ((ret = pthread_rwlock_unlock(&g.backup_lock)) != 0) die(ret, "pthread_rwlock_unlock: backup lock"); check_copy(); } if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); return (NULL); }
/* * corrupt -- * Corrupt the file in a random way. */ static int corrupt(void) { FILE *fp; struct stat sb; size_t len, nw; wt_off_t offset; int fd, ret; char buf[8 * 1024], copycmd[2 * 1024]; /* * If it's a single Btree file (not LSM), open the file, and corrupt * roughly 2% of the file at a random spot, including the beginning * of the file and overlapping the end. * * It's a little tricky: if the data source is a file, we're looking * for "wt", if the data source is a table, we're looking for "wt.wt". */ (void)snprintf(buf, sizeof(buf), "%s/%s", g.home, WT_NAME); if ((fd = open(buf, O_RDWR)) != -1) { #ifdef _WIN32 (void)snprintf(copycmd, sizeof(copycmd), "copy %s\\%s %s\\slvg.copy\\%s.corrupted", g.home, WT_NAME, g.home, WT_NAME); #else (void)snprintf(copycmd, sizeof(copycmd), "cp %s/%s %s/slvg.copy/%s.corrupted", g.home, WT_NAME, g.home, WT_NAME); #endif goto found; } (void)snprintf(buf, sizeof(buf), "%s/%s.wt", g.home, WT_NAME); if ((fd = open(buf, O_RDWR)) != -1) { #ifdef _WIN32 (void)snprintf(copycmd, sizeof(copycmd), "copy %s\\%s.wt %s\\slvg.copy\\%s.wt.corrupted", g.home, WT_NAME, g.home, WT_NAME); #else (void)snprintf(copycmd, sizeof(copycmd), "cp %s/%s.wt %s/slvg.copy/%s.wt.corrupted", g.home, WT_NAME, g.home, WT_NAME); #endif goto found; } return (0); found: if (fstat(fd, &sb) == -1) die(errno, "salvage-corrupt: fstat"); offset = mmrand(NULL, 0, (u_int)sb.st_size); len = (size_t)(20 + (sb.st_size / 100) * 2); (void)snprintf(buf, sizeof(buf), "%s/slvg.corrupt", g.home); if ((fp = fopen(buf, "w")) == NULL) die(errno, "salvage-corrupt: open: %s", buf); (void)fprintf(fp, "salvage-corrupt: offset %" PRIuMAX ", length " SIZET_FMT "\n", (uintmax_t)offset, len); fclose_and_clear(&fp); if (lseek(fd, offset, SEEK_SET) == -1) die(errno, "salvage-corrupt: lseek"); memset(buf, 'z', sizeof(buf)); for (; len > 0; len -= nw) { nw = (size_t)(len > sizeof(buf) ? sizeof(buf) : len); if (write(fd, buf, nw) == -1) die(errno, "salvage-corrupt: write"); } if (close(fd) == -1) die(errno, "salvage-corrupt: close"); /* * Save a copy of the corrupted file so we can replay the salvage step * as necessary. */ if ((ret = system(copycmd)) != 0) die(ret, "salvage corrupt copy step failed"); return (1); }
void key_gen_insert(WT_RAND_STATE *rnd, WT_ITEM *key, uint64_t keyno) { key_gen_common(key, keyno, (int)mmrand(rnd, 1, 15)); }