1 /*-
2  * Public Domain 2014-2018 MongoDB, Inc.
3  * Public Domain 2008-2014 WiredTiger, Inc.
4  *
5  * This is free and unencumbered software released into the public domain.
6  *
7  * Anyone is free to copy, modify, publish, use, compile, sell, or
8  * distribute this software, either in source code form or as a compiled
9  * binary, for any purpose, commercial or non-commercial, and by any
10  * means.
11  *
12  * In jurisdictions that recognize copyright laws, the author or authors
13  * of this software dedicate any and all copyright interest in the
14  * software to the public domain. We make this dedication for the benefit
15  * of the public at large and to the detriment of our heirs and
16  * successors. We intend this dedication to be an overt act of
17  * relinquishment in perpetuity of all present and future rights to this
18  * software under copyright law.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26  * OTHER DEALINGS IN THE SOFTWARE.
27  */
28 
29 #include "format.h"
30 
31 #ifndef MAX
32 #define	MAX(a, b)	(((a) > (b)) ? (a) : (b))
33 #endif
34 
35 void
key_init(void)36 key_init(void)
37 {
38 	size_t i;
39 	uint32_t max;
40 
41 	/*
42 	 * The key is a variable length item with a leading 10-digit value.
43 	 * Since we have to be able re-construct it from the record number
44 	 * (when doing row lookups), we pre-load a set of random lengths in
45 	 * a lookup table, and then use the record number to choose one of
46 	 * the pre-loaded lengths.
47 	 *
48 	 * Fill in the random key lengths.
49 	 *
50 	 * Focus on relatively small items, admitting the possibility of larger
51 	 * items. Pick a size close to the minimum most of the time, only create
52 	 * a larger item 1 in 20 times.
53 	 */
54 	for (i = 0;
55 	    i < sizeof(g.key_rand_len) / sizeof(g.key_rand_len[0]); ++i) {
56 		max = g.c_key_max;
57 		if (i % 20 != 0 && max > g.c_key_min + 20)
58 			max = g.c_key_min + 20;
59 		g.key_rand_len[i] = mmrand(NULL, g.c_key_min, max);
60 	}
61 }
62 
63 void
key_gen_init(WT_ITEM * key)64 key_gen_init(WT_ITEM *key)
65 {
66 	size_t i, len;
67 	char *p;
68 
69 	len = MAX(KILOBYTE(100), g.c_key_max);
70 	p = dmalloc(len);
71 	for (i = 0; i < len; ++i)
72 		p[i] = "abcdefghijklmnopqrstuvwxyz"[i % 26];
73 
74 	key->mem = p;
75 	key->memsize = len;
76 	key->data = key->mem;
77 	key->size = 0;
78 }
79 
80 void
key_gen_teardown(WT_ITEM * key)81 key_gen_teardown(WT_ITEM *key)
82 {
83 	free(key->mem);
84 	memset(key, 0, sizeof(*key));
85 }
86 
87 static void
key_gen_common(WT_ITEM * key,uint64_t keyno,const char * const suffix)88 key_gen_common(WT_ITEM *key, uint64_t keyno, const char * const suffix)
89 {
90 	int len;
91 	char *p;
92 
93 	p = key->mem;
94 
95 	/*
96 	 * The key always starts with a 10-digit string (the specified row)
97 	 * followed by two digits, a random number between 1 and 15 if it's
98 	 * an insert, otherwise 00.
99 	 */
100 	u64_to_string_zf(keyno, key->mem, 11);
101 	p[10] = '.';
102 	p[11] = suffix[0];
103 	p[12] = suffix[1];
104 	len = 13;
105 
106 	/*
107 	 * In a column-store, the key is only used for Berkeley DB inserts,
108 	 * and so it doesn't need a random length.
109 	 */
110 	if (g.type == ROW) {
111 		p[len] = '/';
112 
113 		/*
114 		 * Because we're doing table lookup for key sizes, we weren't
115 		 * able to set really big keys sizes in the table, the table
116 		 * isn't big enough to keep our hash from selecting too many
117 		 * big keys and blowing out the cache. Handle that here, use a
118 		 * really big key 1 in 2500 times.
119 		 */
120 		len = keyno % 2500 == 0 && g.c_key_max < KILOBYTE(80) ?
121 		    KILOBYTE(80) :
122 		    (int)g.key_rand_len[keyno % WT_ELEMENTS(g.key_rand_len)];
123 	}
124 
125 	key->data = key->mem;
126 	key->size = (size_t)len;
127 }
128 
129 void
key_gen(WT_ITEM * key,uint64_t keyno)130 key_gen(WT_ITEM *key, uint64_t keyno)
131 {
132 	key_gen_common(key, keyno, "00");
133 }
134 
135 void
key_gen_insert(WT_RAND_STATE * rnd,WT_ITEM * key,uint64_t keyno)136 key_gen_insert(WT_RAND_STATE *rnd, WT_ITEM *key, uint64_t keyno)
137 {
138 	static const char * const suffix[15] = {
139 	    "01", "02", "03", "04", "05",
140 	    "06", "07", "08", "09", "10",
141 	    "11", "12", "13", "14", "15"
142 	};
143 
144 	key_gen_common(key, keyno, suffix[mmrand(rnd, 0, 14)]);
145 }
146 
147 static char	*val_base;		/* Base/original value */
148 static uint32_t  val_dup_data_len;	/* Length of duplicate data items */
149 static uint32_t  val_len;		/* Length of data items */
150 
151 static inline uint32_t
value_len(WT_RAND_STATE * rnd,uint64_t keyno,uint32_t min,uint32_t max)152 value_len(WT_RAND_STATE *rnd, uint64_t keyno, uint32_t min, uint32_t max)
153 {
154 	/*
155 	 * Focus on relatively small items, admitting the possibility of larger
156 	 * items. Pick a size close to the minimum most of the time, only create
157 	 * a larger item 1 in 20 times, and a really big item 1 in somewhere
158 	 * around 2500 items.
159 	 */
160 	if (keyno % 2500 == 0 && max < KILOBYTE(80)) {
161 		min = KILOBYTE(80);
162 		max = KILOBYTE(100);
163 	} else if (keyno % 20 != 0 && max > min + 20)
164 		max = min + 20;
165 	return (mmrand(rnd, min, max));
166 }
167 
168 void
val_init(void)169 val_init(void)
170 {
171 	size_t i;
172 
173 	/*
174 	 * Set initial buffer contents to recognizable text.
175 	 *
176 	 * Add a few extra bytes in order to guarantee we can always offset
177 	 * into the buffer by a few extra bytes, used to generate different
178 	 * data for column-store run-length encoded files.
179 	 */
180 	val_len = MAX(KILOBYTE(100), g.c_value_max) + 20;
181 	val_base = dmalloc(val_len);
182 	for (i = 0; i < val_len; ++i)
183 		val_base[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % 26];
184 
185 	val_dup_data_len = value_len(NULL,
186 	    (uint64_t)mmrand(NULL, 1, 20), g.c_value_min, g.c_value_max);
187 }
188 
189 void
val_teardown(void)190 val_teardown(void)
191 {
192 	free(val_base);
193 	val_base = NULL;
194 	val_dup_data_len = val_len = 0;
195 }
196 
197 void
val_gen_init(WT_ITEM * value)198 val_gen_init(WT_ITEM *value)
199 {
200 	value->mem = dmalloc(val_len);
201 	value->memsize = val_len;
202 	value->data = value->mem;
203 	value->size = 0;
204 }
205 
206 void
val_gen_teardown(WT_ITEM * value)207 val_gen_teardown(WT_ITEM *value)
208 {
209 	free(value->mem);
210 	memset(value, 0, sizeof(*value));
211 }
212 
213 void
val_gen(WT_RAND_STATE * rnd,WT_ITEM * value,uint64_t keyno)214 val_gen(WT_RAND_STATE *rnd, WT_ITEM *value, uint64_t keyno)
215 {
216 	char *p;
217 
218 	p = value->mem;
219 	value->data = value->mem;
220 
221 	/*
222 	 * Fixed-length records: take the low N bits from the last digit of
223 	 * the record number.
224 	 */
225 	if (g.type == FIX) {
226 		switch (g.c_bitcnt) {
227 		case 8: p[0] = (char)mmrand(rnd, 1, 0xff); break;
228 		case 7: p[0] = (char)mmrand(rnd, 1, 0x7f); break;
229 		case 6: p[0] = (char)mmrand(rnd, 1, 0x3f); break;
230 		case 5: p[0] = (char)mmrand(rnd, 1, 0x1f); break;
231 		case 4: p[0] = (char)mmrand(rnd, 1, 0x0f); break;
232 		case 3: p[0] = (char)mmrand(rnd, 1, 0x07); break;
233 		case 2: p[0] = (char)mmrand(rnd, 1, 0x03); break;
234 		case 1: p[0] = 1; break;
235 		}
236 		value->size = 1;
237 		return;
238 	}
239 
240 	/*
241 	 * WiredTiger doesn't store zero-length data items in row-store files,
242 	 * test that by inserting a zero-length data item every so often.
243 	 */
244 	if (keyno % 63 == 0) {
245 		p[0] = '\0';
246 		value->size = 0;
247 		return;
248 	}
249 
250 	/*
251 	 * Data items have unique leading numbers by default and random lengths;
252 	 * variable-length column-stores use a duplicate data value to test RLE.
253 	 */
254 	if (g.type == VAR && mmrand(rnd, 1, 100) < g.c_repeat_data_pct) {
255 		value->size = val_dup_data_len;
256 		memcpy(p, val_base, value->size);
257 		(void)strcpy(p, "DUPLICATEV");
258 		p[10] = '/';
259 	} else {
260 		value->size =
261 		    value_len(rnd, keyno, g.c_value_min, g.c_value_max);
262 		memcpy(p, val_base, value->size);
263 		u64_to_string_zf(keyno, p, 11);
264 		p[10] = '/';
265 	}
266 }
267 
268 void
track(const char * tag,uint64_t cnt,TINFO * tinfo)269 track(const char *tag, uint64_t cnt, TINFO *tinfo)
270 {
271 	static size_t lastlen = 0;
272 	size_t len;
273 	char msg[128];
274 
275 	if (g.c_quiet || tag == NULL)
276 		return;
277 
278 	if (tinfo == NULL && cnt == 0)
279 		testutil_check(__wt_snprintf_len_set(
280 		    msg, sizeof(msg), &len, "%4d: %s", g.run_cnt, tag));
281 	else if (tinfo == NULL)
282 		testutil_check(__wt_snprintf_len_set(
283 		    msg, sizeof(msg), &len,
284 		    "%4d: %s: %" PRIu64, g.run_cnt, tag, cnt));
285 	else
286 		testutil_check(__wt_snprintf_len_set(
287 		    msg, sizeof(msg), &len,
288 		    "%4d: %s: "
289 		    "search %" PRIu64 "%s, "
290 		    "insert %" PRIu64 "%s, "
291 		    "update %" PRIu64 "%s, "
292 		    "remove %" PRIu64 "%s",
293 		    g.run_cnt, tag,
294 		    tinfo->search > M(9) ? tinfo->search / M(1) : tinfo->search,
295 		    tinfo->search > M(9) ? "M" : "",
296 		    tinfo->insert > M(9) ? tinfo->insert / M(1) : tinfo->insert,
297 		    tinfo->insert > M(9) ? "M" : "",
298 		    tinfo->update > M(9) ? tinfo->update / M(1) : tinfo->update,
299 		    tinfo->update > M(9) ? "M" : "",
300 		    tinfo->remove > M(9) ? tinfo->remove / M(1) : tinfo->remove,
301 		    tinfo->remove > M(9) ? "M" : ""));
302 
303 	if (lastlen > len) {
304 		memset(msg + len, ' ', (size_t)(lastlen - len));
305 		msg[lastlen] = '\0';
306 	}
307 	lastlen = len;
308 
309 	if (printf("%s\r", msg) < 0)
310 		testutil_die(EIO, "printf");
311 	if (fflush(stdout) == EOF)
312 		testutil_die(errno, "fflush");
313 }
314 
315 /*
316  * path_setup --
317  *	Build the standard paths and shell commands we use.
318  */
319 void
path_setup(const char * home)320 path_setup(const char *home)
321 {
322 	size_t len;
323 
324 	/* Home directory. */
325 	g.home = dstrdup(home == NULL ? "RUNDIR" : home);
326 
327 	/* Log file. */
328 	len = strlen(g.home) + strlen("log") + 2;
329 	g.home_log = dmalloc(len);
330 	testutil_check(__wt_snprintf(g.home_log, len, "%s/%s", g.home, "log"));
331 
332 	/* RNG log file. */
333 	len = strlen(g.home) + strlen("rand") + 2;
334 	g.home_rand = dmalloc(len);
335 	testutil_check(__wt_snprintf(
336 	    g.home_rand, len, "%s/%s", g.home, "rand"));
337 
338 	/* Run file. */
339 	len = strlen(g.home) + strlen("CONFIG") + 2;
340 	g.home_config = dmalloc(len);
341 	testutil_check(__wt_snprintf(
342 	    g.home_config, len, "%s/%s", g.home, "CONFIG"));
343 
344 	/* Statistics file. */
345 	len = strlen(g.home) + strlen("stats") + 2;
346 	g.home_stats = dmalloc(len);
347 	testutil_check(__wt_snprintf(
348 	    g.home_stats, len, "%s/%s", g.home, "stats"));
349 
350 	/* BDB directory. */
351 	len = strlen(g.home) + strlen("bdb") + 2;
352 	g.home_bdb = dmalloc(len);
353 	testutil_check(__wt_snprintf(g.home_bdb, len, "%s/%s", g.home, "bdb"));
354 
355 	/*
356 	 * Home directory initialize command: create the directory if it doesn't
357 	 * exist, else remove everything except the RNG log file, create the KVS
358 	 * subdirectory.
359 	 *
360 	 * Redirect the "cd" command to /dev/null so chatty cd implementations
361 	 * don't add the new working directory to our output.
362 	 */
363 #undef	CMD
364 #ifdef _WIN32
365 #define	CMD  "del /q rand.copy & " \
366 	     "(IF EXIST %s\\rand copy /y %s\\rand rand.copy) & "	\
367 	     "(IF EXIST %s rd /s /q %s) & mkdir %s & "			\
368 	     "(IF EXIST rand.copy copy rand.copy %s\\rand) & " \
369 	     "cd %s & mkdir KVS"
370 	len = strlen(g.home) * 7 + strlen(CMD) + 1;
371 	g.home_init = dmalloc(len);
372 	testutil_check(__wt_snprintf(g.home_init, len, CMD,
373 	    g.home, g.home, g.home, g.home, g.home, g.home, g.home));
374 #else
375 #define	CMD	"test -e %s || mkdir %s; "				\
376 		"cd %s > /dev/null && rm -rf `ls | sed /rand/d`; "	\
377 		"mkdir KVS"
378 	len = strlen(g.home) * 3 + strlen(CMD) + 1;
379 	g.home_init = dmalloc(len);
380 	testutil_check(__wt_snprintf(
381 	    g.home_init, len, CMD, g.home, g.home, g.home));
382 #endif
383 
384 	/* Primary backup directory. */
385 	len = strlen(g.home) + strlen("BACKUP") + 2;
386 	g.home_backup = dmalloc(len);
387 	testutil_check(__wt_snprintf(
388 	    g.home_backup, len, "%s/%s", g.home, "BACKUP"));
389 
390 	/*
391 	 * Backup directory initialize command, remove and re-create the primary
392 	 * backup directory, plus a copy we maintain for recovery testing.
393 	 */
394 #undef	CMD
395 #ifdef _WIN32
396 #define	CMD	"rd /s /q %s\\%s %s\\%s & mkdir %s\\%s %s\\%s"
397 #else
398 #define	CMD	"rm -rf %s/%s %s/%s && mkdir %s/%s %s/%s"
399 #endif
400 	len = strlen(g.home) * 4 +
401 	    strlen("BACKUP") * 2 + strlen("BACKUP_COPY") * 2 + strlen(CMD) + 1;
402 	g.home_backup_init = dmalloc(len);
403 	testutil_check(__wt_snprintf(g.home_backup_init, len, CMD,
404 	    g.home, "BACKUP", g.home, "BACKUP_COPY",
405 	    g.home, "BACKUP", g.home, "BACKUP_COPY"));
406 
407 	/*
408 	 * Salvage command, save the interesting files so we can replay the
409 	 * salvage command as necessary.
410 	 *
411 	 * Redirect the "cd" command to /dev/null so chatty cd implementations
412 	 * don't add the new working directory to our output.
413 	 */
414 #undef	CMD
415 #ifdef _WIN32
416 #define	CMD								\
417 	"cd %s && "							\
418 	"rd /q /s slvg.copy & mkdir slvg.copy && "			\
419 	"copy WiredTiger* slvg.copy\\ >:nul && copy wt* slvg.copy\\ >:nul"
420 #else
421 #define	CMD								\
422 	"cd %s > /dev/null && "						\
423 	"rm -rf slvg.copy && mkdir slvg.copy && "			\
424 	"cp WiredTiger* wt* slvg.copy/"
425 #endif
426 	len = strlen(g.home) + strlen(CMD) + 1;
427 	g.home_salvage_copy = dmalloc(len);
428 	testutil_check(__wt_snprintf(g.home_salvage_copy, len, CMD, g.home));
429 }
430 
431 /*
432  * rng --
433  *	Return a random number.
434  */
435 uint32_t
rng(WT_RAND_STATE * rnd)436 rng(WT_RAND_STATE *rnd)
437 {
438 	u_long ulv;
439 	uint32_t v;
440 	char *endptr, buf[64];
441 
442 	/*
443 	 * Threaded operations have their own RNG information, otherwise we
444 	 * use the default.
445 	 */
446 	if (rnd == NULL)
447 		rnd = &g.rnd;
448 
449 	/*
450 	 * We can reproduce a single-threaded run based on the random numbers
451 	 * used in the initial run, plus the configuration files.
452 	 *
453 	 * Check g.replay and g.rand_log_stop: multithreaded runs log/replay
454 	 * until they get to the operations phase, then turn off log/replay,
455 	 * threaded operation order can't be replayed.
456 	 */
457 	if (g.rand_log_stop)
458 		return (__wt_random(rnd));
459 
460 	if (g.replay) {
461 		if (fgets(buf, sizeof(buf), g.randfp) == NULL) {
462 			if (feof(g.randfp)) {
463 				fprintf(stderr,
464 				    "\n" "end of random number log reached\n");
465 				exit(EXIT_SUCCESS);
466 			}
467 			testutil_die(errno, "random number log");
468 		}
469 
470 		errno = 0;
471 		ulv = strtoul(buf, &endptr, 10);
472 		testutil_assert(errno == 0 && endptr[0] == '\n');
473 		testutil_assert(ulv <= UINT32_MAX);
474 		return ((uint32_t)ulv);
475 	}
476 
477 	v = __wt_random(rnd);
478 
479 	/* Save and flush the random number so we're up-to-date on error. */
480 	(void)fprintf(g.randfp, "%" PRIu32 "\n", v);
481 	(void)fflush(g.randfp);
482 
483 	return (v);
484 }
485 
486 /*
487  * fclose_and_clear --
488  *	Close a file and clear the handle so we don't close twice.
489  */
490 void
fclose_and_clear(FILE ** fpp)491 fclose_and_clear(FILE **fpp)
492 {
493 	FILE *fp;
494 
495 	if ((fp = *fpp) == NULL)
496 		return;
497 	*fpp = NULL;
498 	if (fclose(fp) != 0)
499 		testutil_die(errno, "fclose");
500 	return;
501 }
502 
503 /*
504  * checkpoint --
505  *	Periodically take a checkpoint
506  */
507 WT_THREAD_RET
checkpoint(void * arg)508 checkpoint(void *arg)
509 {
510 	WT_CONNECTION *conn;
511 	WT_DECL_RET;
512 	WT_SESSION *session;
513 	u_int secs;
514 	const char *ckpt_config;
515 	char config_buf[64];
516 	bool backup_locked;
517 
518 	(void)arg;
519 	conn = g.wts_conn;
520 	testutil_check(conn->open_session(conn, NULL, NULL, &session));
521 
522 	for (secs = mmrand(NULL, 1, 10); !g.workers_finished;) {
523 		if (secs > 0) {
524 			__wt_sleep(1, 0);
525 			--secs;
526 			continue;
527 		}
528 
529 		/*
530 		 * LSM and data-sources don't support named checkpoints. Also,
531 		 * don't attempt named checkpoints during a hot backup. It's
532 		 * OK to create named checkpoints during a hot backup, but we
533 		 * can't delete them, so repeating an already existing named
534 		 * checkpoint will fail when we can't drop the previous one.
535 		 */
536 		ckpt_config = NULL;
537 		backup_locked = false;
538 		if (!DATASOURCE("helium") && !DATASOURCE("kvsbdb") &&
539 		    !DATASOURCE("lsm"))
540 			switch (mmrand(NULL, 1, 20)) {
541 			case 1:
542 				/*
543 				 * 5% create a named snapshot. Rotate between a
544 				 * few names to test multiple named snapshots in
545 				 * the system.
546 				 */
547 				ret = pthread_rwlock_trywrlock(&g.backup_lock);
548 				if (ret == 0) {
549 					backup_locked = true;
550 					testutil_check(__wt_snprintf(
551 					    config_buf, sizeof(config_buf),
552 					    "name=mine.%" PRIu32,
553 					    mmrand(NULL, 1, 4)));
554 					ckpt_config = config_buf;
555 				} else if (ret != EBUSY)
556 					testutil_check(ret);
557 				break;
558 			case 2:
559 				/*
560 				 * 5% drop all named snapshots.
561 				 */
562 				ret = pthread_rwlock_trywrlock(&g.backup_lock);
563 				if (ret == 0) {
564 					backup_locked = true;
565 					ckpt_config = "drop=(all)";
566 				} else if (ret != EBUSY)
567 					testutil_check(ret);
568 				break;
569 			}
570 
571 		testutil_check(session->checkpoint(session, ckpt_config));
572 
573 		if (backup_locked)
574 			testutil_check(pthread_rwlock_unlock(&g.backup_lock));
575 
576 		secs = mmrand(NULL, 5, 40);
577 	}
578 
579 	testutil_check(session->close(session, NULL));
580 	return (WT_THREAD_RET_VALUE);
581 }
582 
583 /*
584  * timestamp --
585  *	Periodically update the oldest timestamp.
586  */
587 WT_THREAD_RET
timestamp(void * arg)588 timestamp(void *arg)
589 {
590 	WT_CONNECTION *conn;
591 	WT_DECL_RET;
592 	WT_SESSION *session;
593 	char buf[64];
594 	bool done;
595 
596 	(void)(arg);
597 	conn = g.wts_conn;
598 
599 	testutil_check(conn->open_session(conn, NULL, NULL, &session));
600 
601 	testutil_check(
602 	    __wt_snprintf(buf, sizeof(buf), "%s", "oldest_timestamp="));
603 
604 	/* Update the oldest timestamp at least once every 15 seconds. */
605 	done = false;
606 	do {
607 		/*
608 		 * Do a final bump of the oldest timestamp as part of shutting
609 		 * down the worker threads, otherwise recent operations can
610 		 * prevent verify from running.
611 		 */
612 		if (g.workers_finished)
613 			done = true;
614 		else
615 			random_sleep(&g.rnd, 15);
616 
617 		/*
618 		 * Lock out transaction timestamp operations. The lock acts as a
619 		 * barrier ensuring we've checked if the workers have finished,
620 		 * we don't want that line reordered.
621 		 */
622 		testutil_check(pthread_rwlock_wrlock(&g.ts_lock));
623 
624 		ret = conn->query_timestamp(conn,
625 		    buf + strlen("oldest_timestamp="), "get=all_committed");
626 		testutil_assert(ret == 0 || ret == WT_NOTFOUND);
627 		if (ret == 0)
628 			testutil_check(conn->set_timestamp(conn, buf));
629 
630 		testutil_check(pthread_rwlock_unlock(&g.ts_lock));
631 	} while (!done);
632 
633 	testutil_check(session->close(session, NULL));
634 	return (WT_THREAD_RET_VALUE);
635 }
636 
637 /*
638  * alter --
639  *	Periodically alter a table's metadata.
640  */
641 WT_THREAD_RET
alter(void * arg)642 alter(void *arg)
643 {
644 	WT_CONNECTION *conn;
645 	WT_DECL_RET;
646 	WT_SESSION *session;
647 	u_int period;
648 	char buf[32];
649 	bool access_value;
650 
651 	(void)(arg);
652 	conn = g.wts_conn;
653 
654 	/*
655 	 * Only alter the access pattern hint.  If we alter the cache resident
656 	 * setting we may end up with a setting that fills cache and doesn't
657 	 * allow it to be evicted.
658 	 */
659 	access_value = false;
660 
661 	/* Open a session */
662 	testutil_check(conn->open_session(conn, NULL, NULL, &session));
663 
664 	while (!g.workers_finished) {
665 		period = mmrand(NULL, 1, 10);
666 
667 		testutil_check(__wt_snprintf(buf, sizeof(buf),
668 		    "access_pattern_hint=%s",
669 		    access_value ? "random" : "none"));
670 		access_value = !access_value;
671 		/*
672 		 * Alter can return EBUSY if concurrent with other operations.
673 		 */
674 		while ((ret = session->alter(session, g.uri, buf)) != 0 &&
675 		    ret != EBUSY)
676 			testutil_die(ret, "session.alter");
677 		while (period > 0 && !g.workers_finished) {
678 			--period;
679 			__wt_sleep(1, 0);
680 		}
681 	}
682 
683 	testutil_check(session->close(session, NULL));
684 	return (WT_THREAD_RET_VALUE);
685 }
686 
687 /*
688  * print_item_data --
689  *	Display a single data/size pair, with a tag.
690  */
691 void
print_item_data(const char * tag,const uint8_t * data,size_t size)692 print_item_data(const char *tag, const uint8_t *data, size_t size)
693 {
694 	static const char hex[] = "0123456789abcdef";
695 	u_char ch;
696 
697 	fprintf(stderr, "\t%s {", tag);
698 	if (g.type == FIX)
699 		fprintf(stderr, "0x%02x", data[0]);
700 	else
701 		for (; size > 0; --size, ++data) {
702 			ch = data[0];
703 			if (__wt_isprint(ch))
704 				fprintf(stderr, "%c", (int)ch);
705 			else
706 				fprintf(stderr, "%x%x",
707 				    (u_int)hex[(data[0] & 0xf0) >> 4],
708 				    (u_int)hex[data[0] & 0x0f]);
709 		}
710 	fprintf(stderr, "}\n");
711 }
712 
713 /*
714  * print_item --
715  *	Display a single data/size pair, with a tag.
716  */
717 void
print_item(const char * tag,WT_ITEM * item)718 print_item(const char *tag, WT_ITEM *item)
719 {
720 	print_item_data(tag, item->data, item->size);
721 }
722