Files
mongo/test/format/util.c
Keith Bostic 7574a296e8 We weren't getting repeatable runs, clean up random number handling:
there was a static value being used for value generation, replace it
with the key-number, rewind the random number file for each run, don't
remove __rand on SIGINT (that way if you kill your debugger, you don't
lose the run).

--HG--
extra : rebase_source : 14c7012e45a859cfdf0de0f22d53a6c4d443db12
2011-08-30 10:44:09 +00:00

209 lines
5.2 KiB
C

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2008-2011 WiredTiger, Inc.
* All rights reserved.
*/
#include "format.h"
void
key_gen(void *keyp, uint32_t *sizep, uint64_t keyno, int insert)
{
int len;
/*
* The key always starts with a 10-digit string (the specified cnt)
* followed by two digits, a random number between 1 and 15 if it's
* an insert, otherwise 00.
*/
len = insert ?
sprintf(g.key_gen_buf, "%010" PRIu64 ".%02d", keyno,
(int)MMRAND(1, 15)) :
sprintf(g.key_gen_buf, "%010" PRIu64 ".00", keyno);
g.key_gen_buf[len] = '/';
*(void **)keyp = g.key_gen_buf;
*sizep = g.key_rand_len[keyno %
(sizeof(g.key_rand_len) / sizeof(g.key_rand_len[0]))];
}
void
key_gen_setup(void)
{
size_t i;
/*
* 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.
*/
if (g.key_gen_buf != NULL) {
free(g.key_gen_buf);
g.key_gen_buf = NULL;
}
for (i = 0; i < sizeof(g.key_rand_len) / sizeof(g.key_rand_len[0]); ++i)
g.key_rand_len[i] = (uint16_t)MMRAND(g.c_key_min, g.c_key_max);
if ((g.key_gen_buf = malloc(g.c_key_max)) == NULL)
die("malloc", errno);
for (i = 0; i < g.c_key_max; ++i)
g.key_gen_buf[i] = "abcdefghijklmnopqrstuvwxyz"[i % 26];
}
void
value_gen(void *valuep, uint32_t *sizep, uint64_t keyno)
{
static size_t blen = 0;
static const char *dup_data = "duplicate data item";
static u_char *buf = NULL;
size_t i;
/*
* Set initial buffer contents to reconizable 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.
*/
if (blen < g.c_value_max + 10) {
if (buf != NULL) {
free(buf);
buf = NULL;
}
blen = g.c_value_max + 10;
if ((buf = malloc(blen)) == NULL)
die("malloc", errno);
for (i = 0; i < blen; ++i)
buf[i] = (u_char)"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % 26];
}
/*
* Fixed-length records: take the low N bits from the last digit of
* the record number.
*/
if (g.c_file_type == FIX) {
switch (g.c_bitcnt) {
case 8: buf[0] = MMRAND(1, 0xff); break;
case 7: buf[0] = MMRAND(1, 0x7f); break;
case 6: buf[0] = MMRAND(1, 0x3f); break;
case 5: buf[0] = MMRAND(1, 0x1f); break;
case 4: buf[0] = MMRAND(1, 0x0f); break;
case 3: buf[0] = MMRAND(1, 0x07); break;
case 2: buf[0] = MMRAND(1, 0x03); break;
case 1: buf[0] = 1; break;
}
*(void **)valuep = buf;
*sizep = 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) {
*(void **)valuep = buf;
*sizep = 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.c_file_type == VAR &&
g.c_repeat_data_pct != 0 &&
(u_int)wts_rand() % 100 > g.c_repeat_data_pct) {
*(void **)valuep = (void *)dup_data;
*sizep = (uint32_t)strlen(dup_data);
return;
}
snprintf((char *)buf, blen, "%010" PRIu64, keyno);
buf[10] = '/';
*(void **)valuep = buf;
*sizep = MMRAND(g.c_value_min, g.c_value_max);
}
void
track(const char *s, uint64_t i)
{
static int lastlen = 0;
int len;
char msg[128];
if (!g.track || s == NULL)
return;
if (i == 0)
len = snprintf(msg, sizeof(msg), "%4d: %s",
g.run_cnt, s);
else
len = snprintf(msg, sizeof(msg), "%4d: %s %" PRIu64,
g.run_cnt, s, i);
if (lastlen > len) {
memset(msg + len, ' ', (size_t)(lastlen - len));
msg[lastlen] = '\0';
}
lastlen = len;
(void)printf("%s\r", msg);
(void)fflush(stdout);
}
/*
* wts_rand --
* Return a random number.
*/
uint32_t
wts_rand(void)
{
char buf[64];
uint32_t r;
/*
* We can entirely reproduce a run based on the random numbers used
* in the initial run, plus the configuration files. It would be
* nice to just log the initial RNG seed, rather than logging every
* random number generated, but we can't -- Berkeley DB calls rand()
* internally, and so that messes up the pattern of random numbers
* (and WT might call rand() in the future, who knows?)
*/
if (g.rand_log == NULL) {
if ((g.rand_log =
fopen("__rand", g.replay ? "r" : "w")) == NULL)
die("__rand", errno);
if (!g.replay) {
srand((u_int)(0xdeadbeef ^ (u_int)time(NULL)));
(void)setvbuf(g.rand_log, NULL, _IOLBF, 0);
}
}
if (g.replay) {
if (fgets(buf, sizeof(buf), g.rand_log) == NULL) {
if (feof(g.rand_log)) {
fprintf(stderr,
"end of random number log reached, "
"exiting\n");
exit(EXIT_SUCCESS);
}
die("random number log", errno);
}
r = (uint32_t)strtoul(buf, NULL, 10);
} else {
r = (uint32_t)rand();
fprintf(g.rand_log, "%" PRIu32 "\n", r);
}
return (r);
}