1/* 2 * $Id: b_workload.h,v 1.9 2008/04/14 02:21:47 david Exp $ 3 */ 4 5/* 6 * Macros to help with initializing/assigning key dbts 7 */ 8 9#define KBUF_LEN 12 10#define INIT_KEY(key, config) do { \ 11 memset(&key, 0, sizeof(key)); \ 12 if (config->orderedkeys) { \ 13 key.size = sizeof (u_int32_t); \ 14 } else if (config->ksize != 0) { \ 15 DB_BENCH_ASSERT( \ 16 (key.data = malloc(key.size = config->ksize)) != NULL); \ 17 } else { \ 18 key.data = kbuf; \ 19 key.size = 10; \ 20 } \ 21 } while (0) 22 23#define GET_KEY_NEXT(key, config, kbuf, i) do { \ 24 size_t tmp_int; \ 25 if (config->orderedkeys) { \ 26 /* Will be sorted on little-endian system. */ \ 27 tmp_int = i; \ 28 M_32_SWAP(tmp_int); \ 29 key.data = &tmp_int; \ 30 } else if (config->ksize == 0) { \ 31 /* \ 32 * This will produce duplicate keys. \ 33 * That is not such a big deal, since we are \ 34 * using the same seed to srand each time, \ 35 * the scenario is reproducible. \ 36 */ \ 37 (void)snprintf(kbuf, sizeof(kbuf), "%10d", rand()); \ 38 } else { \ 39 /* TODO: Not sure of the best approach here. */ \ 40 (void)snprintf(key.data, config->ksize, "%10lu", (u_long)i); \ 41 } \ 42 } while (0) 43 44/* Taken from dbinc/db_swap.h */ 45#undef M_32_SWAP 46#define M_32_SWAP(a) { \ 47 u_int32_t _tmp; \ 48 _tmp = (u_int32_t)a; \ 49 ((u_int8_t *)&a)[0] = ((u_int8_t *)&_tmp)[3]; \ 50 ((u_int8_t *)&a)[1] = ((u_int8_t *)&_tmp)[2]; \ 51 ((u_int8_t *)&a)[2] = ((u_int8_t *)&_tmp)[1]; \ 52 ((u_int8_t *)&a)[3] = ((u_int8_t *)&_tmp)[0]; \ 53} 54 55/* 56 * A singly linked list, that maintains a pointer 57 * to the start and the end of the queue. 58 * Should be possible to use a STAILQ, but this seemed easier 59 */ 60typedef struct bench_qentry { 61 char data[KBUF_LEN]; 62 struct bench_qentry *next; 63}bench_qentry; 64typedef struct bench_q { 65 struct bench_qentry *head; 66 struct bench_qentry *tail; 67} bench_q; 68#define BENCH_Q_TAIL_INSERT(queue, buf) do { \ 69 struct bench_qentry *entry; \ 70 DB_BENCH_ASSERT( \ 71 (entry = malloc(sizeof(struct bench_qentry))) != NULL); \ 72 memcpy(entry->data, buf, sizeof(entry->data)); \ 73 if (queue.head == NULL) \ 74 queue.head = queue.tail = entry; \ 75 else { \ 76 queue.tail->next = entry; \ 77 queue.tail = entry; \ 78 } \ 79} while (0) 80 81#define BENCH_Q_POP(queue, buf) do { \ 82 struct bench_qentry *popped = queue.head; \ 83 if (popped == NULL) \ 84 break; \ 85 if (queue.head->next == NULL) \ 86 queue.head = queue.tail = NULL; \ 87 else \ 88 queue.head = queue.head->next; \ 89 memcpy(buf, popped->data, sizeof(buf)); \ 90 free(popped); \ 91} while (0) 92 93/* 94 * Retrieve the head of the queue, save the data into user 95 * buffer, and push the item back onto the end of the list. 96 * Same functionality as pop/insert, but saves a malloc/free 97 */ 98#define BENCH_Q_POP_PUSH(queue, buf) do { \ 99 struct bench_qentry *popped = queue.head; \ 100 if (popped == NULL) \ 101 break; \ 102 if (queue.head->next == NULL) \ 103 queue.head = queue.tail = NULL; \ 104 else \ 105 queue.head = queue.head->next; \ 106 memcpy(buf, popped->data, sizeof(buf)); \ 107 if (queue.head == NULL) \ 108 queue.head = queue.tail = popped; \ 109 else { \ 110 queue.tail->next = popped; \ 111 queue.tail = popped; \ 112 } \ 113} while (0) 114 115typedef enum { 116 T_PUT, 117 T_GET, 118 T_DELETE, 119 T_PUT_GET, 120 T_PUT_DELETE, 121 T_PUT_GET_DELETE, 122 T_GET_DELETE, 123 T_MIXED 124} test_type; 125 126typedef struct 127{ 128 size_t ksize; 129 size_t dsize; 130 size_t orderedkeys; 131 size_t num_dups; 132 size_t pagesz; 133 size_t cachesz; 134 size_t pcount; 135 size_t gcount; 136 size_t cursor_del; 137 size_t verbose; 138 test_type workload; 139 size_t seed; 140 size_t presize; 141 DBTYPE type; 142 char *ts; 143 char *message; 144 /* Fields used to store timing information */ 145 db_timespec put_time; 146 db_timespec get_time; 147 db_timespec del_time; 148 db_timespec tot_time; 149} CONFIG; 150