1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 #pragma once
40 
41 //
42 //   Functions to create unique key/value pairs, row generators, checkers, ... for each of NUM_DBS
43 //
44 
45 //   To use, during initialization:
46 //     generate_permute_tables();
47 //     r = env->set_generate_row_callback_for_put(env, put_multiple_generate);
48 //
49 
50 
51 enum {MAX_DBS=32};
52 enum {MAGIC=311};
53 
54 //   a is the bit-wise permute table.  For DB[i], permute bits as described in a[i] using 'twiddle32'
55 // inv is the inverse bit-wise permute of a[].  To get the original value from a twiddled value, twiddle32 (again) with inv[]
56 int   a[MAX_DBS][32];
57 int inv[MAX_DBS][32];
58 
59 // rotate right and left functions
UU()60 static inline uint32_t UU() rotr32(const uint32_t x, const uint32_t num) {
61     const uint32_t n = num % 32;
62     return (x >> n) | ( x << (32 - n));
63 }
UU()64 static inline uint64_t UU() rotr64(const uint64_t x, const uint64_t num) {
65     const uint64_t n = num % 64;
66     return ( x >> n ) | ( x << (64 - n));
67 }
UU()68 static inline uint32_t UU() rotl32(const uint32_t x, const uint32_t num) {
69     const uint32_t n = num % 32;
70     return (x << n) | ( x >> (32 - n));
71 }
UU()72 static inline uint64_t UU() rotl64(const uint64_t x, const uint64_t num) {
73     const uint64_t n = num % 64;
74     return ( x << n ) | ( x >> (64 - n));
75 }
76 
UU()77 static void UU() generate_permute_tables(void) {
78     int i, j, tmp;
79     for(int db=0;db<MAX_DBS;db++) {
80         for(i=0;i<32;i++) {
81             a[db][i] = i;
82         }
83         for(i=0;i<32;i++) {
84             j = random() % (i + 1);
85             tmp = a[db][j];
86             a[db][j] = a[db][i];
87             a[db][i] = tmp;
88         }
89 //        if(db < NUM_DBS){ printf("a[%d] = ", db); for(i=0;i<32;i++) { printf("%2d ", a[db][i]); } printf("\n");}
90         for(i=0;i<32;i++) {
91             inv[db][a[db][i]] = i;
92         }
93     }
94 }
95 
96 // permute bits of x based on permute table bitmap
UU()97 static uint32_t UU() twiddle32(uint32_t x, int db)
98 {
99     uint32_t b = 0;
100     for(int i=0;i<32;i++) {
101         b |= (( x >> i ) & 1) << a[db][i];
102     }
103     return b;
104 }
105 
106 // permute bits of x based on inverse permute table bitmap
UU()107 static uint32_t UU() inv_twiddle32(uint32_t x, int db)
108 {
109     uint32_t b = 0;
110     for(int i=0;i<32;i++) {
111         b |= (( x >> i ) & 1) << inv[db][i];
112     }
113     return b;
114 }
115 
116 // generate val from key, index
UU()117 static uint32_t UU() generate_val(int key, int i) {
118     return rotl32((key + MAGIC), i);
119 }
UU()120 static uint32_t UU() pkey_for_val(int key, int i) {
121     return rotr32(key, i) - MAGIC;
122 }
123 
124 // There is no handlerton in this test, so this function is a local replacement
125 // for the handlerton's generate_row_for_put().
UU()126 static int UU() put_multiple_generate(DB *dest_db, DB *src_db, DBT_ARRAY *dest_keys, DBT_ARRAY *dest_vals, const DBT *src_key, const DBT *src_val) {
127     toku_dbt_array_resize(dest_keys, 1);
128     toku_dbt_array_resize(dest_vals, 1);
129     DBT *dest_key = &dest_keys->dbts[0];
130     DBT *dest_val = &dest_vals->dbts[0];
131     (void) src_db;
132     (void) src_val;
133 
134     uint32_t which = *(uint32_t*)dest_db->app_private;
135 
136     assert(which != 0);
137     assert(dest_db != src_db);
138     {
139         assert(dest_key->flags==DB_DBT_REALLOC);
140         if (dest_key->ulen < sizeof(uint32_t)) {
141             dest_key->data = toku_xrealloc(dest_key->data, sizeof(uint32_t));
142             dest_key->ulen = sizeof(uint32_t);
143         }
144         assert(dest_val->flags==DB_DBT_REALLOC);
145         if (dest_val->ulen < sizeof(uint32_t)) {
146             dest_val->data = toku_xrealloc(dest_val->data, sizeof(uint32_t));
147             dest_val->ulen = sizeof(uint32_t);
148         }
149         uint32_t *new_key = (uint32_t *)dest_key->data;
150         uint32_t *new_val = (uint32_t *)dest_val->data;
151 
152         *new_key = twiddle32(*(uint32_t*)src_key->data, which);
153         *new_val = generate_val(*(uint32_t*)src_key->data, which);
154 
155         dest_key->size = sizeof(uint32_t);
156         dest_val->size = sizeof(uint32_t);
157         //data is already set above
158     }
159 
160 //    printf("pmg : dest_key.data = %u, dest_val.data = %u \n", *(unsigned int*)dest_key->data, *(unsigned int*)dest_val->data);
161 
162     return 0;
163 }
164 
UU()165 UU()
166 static int put_multiple_generate_switch(DB *dest_db, DB *src_db, DBT_ARRAY *dest_keys, DBT_ARRAY *dest_vals, const DBT *src_key, const DBT *src_val) {
167     toku_dbt_array_resize(dest_keys, 1);
168     toku_dbt_array_resize(dest_vals, 1);
169     DBT *dest_key = &dest_keys->dbts[0];
170     DBT *dest_val = &dest_vals->dbts[0];
171     dest_key->flags = 0;
172     dest_val->flags = 0;
173 
174     (void) src_db;
175 
176     uint32_t which = (uint32_t) (intptr_t) dest_db->app_private;
177     assert(which == 0);
178 
179     // switch the key and val
180     dbt_init(dest_key, src_val->data, src_val->size);
181     dbt_init(dest_val, src_key->data, src_key->size);
182 
183 //    printf("dest_key.data = %d\n", *(int*)dest_key->data);
184 //    printf("dest_val.data = %d\n", *(int*)dest_val->data);
185 
186     return 0;
187 }
188 
UU()189 static int UU() uint_cmp(const void *ap, const void *bp) {
190     unsigned int an = *(unsigned int *)ap;
191     unsigned int bn = *(unsigned int *)bp;
192     if (an < bn)
193         return -1;
194     if (an > bn)
195         return +1;
196     return 0;
197 }
198 
199 float last_progress = 0.0;
UU()200 static int UU() poll_print(void *extra, float progress) {
201     if ( verbose ) {
202         if ( last_progress + 0.01 < progress ) {
203             printf("  progress : %3.0f%%\n", progress * 100.0);
204             last_progress = progress;
205         }
206     }
207     (void) extra;
208     return 0;
209 }
210 
211 enum {MAX_CLIENTS=10};
UU()212 static inline UU() uint32_t key_to_put(int iter, int offset)
213 {
214     return (uint32_t)(((iter+1) * MAX_CLIENTS) + offset);
215 }
216 
UU()217 static int UU() generate_initial_table(DB *db, DB_TXN *txn, uint32_t rows)
218 {
219     struct timeval start, now;
220     if ( verbose ) {
221         printf("generate_initial_table\n");
222         gettimeofday(&start,0);
223     }
224     int r = 0;
225     DBT key, val;
226     uint32_t k, v, i;
227     // create keys of stride MAX_CLIENTS
228     for (i=0; i<rows; i++)
229     {
230         k = key_to_put(i, 0);
231         v = generate_val(k, 0);
232         dbt_init(&key, &k, sizeof(k));
233         dbt_init(&val, &v, sizeof(v));
234         r = db->put(db, txn, &key, &val, 0);
235         if ( r != 0 ) break;
236     }
237     if ( verbose ) {
238         gettimeofday(&now,0);
239         int duration = (int)(now.tv_sec - start.tv_sec);
240         if ( duration > 0 )
241             printf("generate_initial_table : %u rows in %d sec = %d rows/sec\n", rows, duration, rows/duration);
242     }
243 
244     return r;
245 }
246