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 #include "test.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43
44 #include <unistd.h>
45 #include <memory.h>
46 #include <sys/stat.h>
47 #include <db.h>
48
49 typedef struct {
50 int64_t left;
51 int64_t right;
52 int64_t last;
53 int found;
54 int direction;
55 int error_to_expect;
56 } cont_extra;
57
58 static int
getf_continue(DBT const * key,DBT const * val,void * context)59 getf_continue(DBT const* key, DBT const* val, void* context) {
60 assert(key); // prob wrong?
61 assert(val); // prob wrong? make ifs if this fails
62 cont_extra *CAST_FROM_VOIDP(c, context);
63
64 assert(c->found >= 0);
65 assert(c->found < 3);
66 c->found++;
67 assert(key->size == 8);
68 assert(val->size == 8);
69 int64_t k = *(int64_t*)key->data;
70 int64_t v = *(int64_t*)val->data;
71 assert(k==v);
72 assert(k==c->last+c->direction);
73 c->last = k;
74 if (c->error_to_expect) {
75 assert(c->left <= k);
76 assert(k <= c->right);
77 }
78 if (c->found < 3) {
79 return TOKUDB_CURSOR_CONTINUE;
80 } else {
81 return 0;
82 }
83 }
84
85 static void
test_restrict(int64_t n,int offset,int error_to_expect)86 test_restrict (int64_t n, int offset, int error_to_expect) {
87 assert(n > 30);
88 DB_TXN * const null_txn = 0;
89 int r;
90
91
92 toku_os_recursive_delete(TOKU_TEST_FILENAME);
93 r=toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO); assert(r==0);
94
95 /* create the dup database file */
96 DB_ENV *env;
97 r = db_env_create(&env, 0); assert(r == 0);
98 r=env->set_default_bt_compare(env, int64_dbt_cmp); CKERR(r);
99 r = env->open(env, TOKU_TEST_FILENAME, DB_CREATE+DB_PRIVATE+DB_INIT_MPOOL, 0); assert(r == 0);
100
101 DB *db;
102 r = db_create(&db, env, 0);
103 assert(r == 0);
104 r = db->set_flags(db, 0);
105 assert(r == 0);
106 r = db->open(db, null_txn, "restrict.db", NULL, DB_BTREE, DB_CREATE, 0666);
107 assert(r == 0);
108
109 int64_t keys[n];
110 int64_t i;
111 for (i=0; i<n; i++) {
112 keys[i] = i;
113 }
114
115 DBT key, val;
116 for (i=0; i<n; i++) {
117 r = db->put(db, null_txn, dbt_init(&key, &keys[i], sizeof keys[i]), dbt_init(&val, &i, sizeof i), 0);
118 assert(r == 0);
119 }
120
121 DBC* cursor;
122
123 r = db->cursor(db, NULL, &cursor, 0);
124 CKERR(r);
125
126 DBT dbt_left, dbt_right;
127 int64_t int_left, int_right;
128 int_left = n / 3 + offset;
129 int_right = 2 * n / 3 + offset;
130
131 dbt_init(&dbt_left, &keys[int_left], sizeof keys[int_left]);
132 dbt_init(&dbt_right, &keys[int_right], sizeof keys[int_right]);
133
134 r = cursor->c_set_bounds(
135 cursor,
136 &dbt_left,
137 &dbt_right,
138 true,
139 error_to_expect);
140 CKERR(r);
141
142
143 for (i=0; i<n; i++) {
144 r = cursor->c_get(cursor, dbt_init(&key, &keys[i], sizeof keys[i]), dbt_init(&val, NULL, 0), DB_SET);
145 if (i < int_left || i > int_right) {
146 CKERR2(r, error_to_expect);
147 } else {
148 CKERR(r);
149 assert(val.size == 8);
150 assert(*(int64_t*)val.data == i);
151 }
152 }
153 // Forwards
154
155 r = cursor->c_get(cursor, dbt_init(&key, &keys[int_left], sizeof keys[int_left]), dbt_init(&val, NULL, 0), DB_SET);
156 CKERR(r);
157 assert(val.size == 8);
158 assert(*(int64_t*)val.data == int_left);
159
160 for (i=int_left+1; i < n; i++) {
161 r = cursor->c_get(cursor, dbt_init(&key, NULL, 0), dbt_init(&val, NULL, 0), DB_NEXT);
162 if (i >= int_left && i <= int_right) {
163 CKERR(r);
164 assert(key.size == 8);
165 assert(*(int64_t*)key.data == i);
166 assert(val.size == 8);
167 assert(*(int64_t*)val.data == i);
168 } else {
169 CKERR2(r, error_to_expect);
170 break;
171 }
172 }
173
174 r = cursor->c_get(cursor, dbt_init(&key, &keys[int_right], sizeof keys[int_right]), dbt_init(&val, NULL, 0), DB_SET);
175 CKERR(r);
176 assert(val.size == 8);
177 assert(*(int64_t*)val.data == int_right);
178
179 for (i=int_right-1; i >= 0; i--) {
180 r = cursor->c_get(cursor, dbt_init(&key, NULL, 0), dbt_init(&val, NULL, 0), DB_PREV);
181 if (i >= int_left && i <= int_right) {
182 CKERR(r);
183 assert(key.size == 8);
184 assert(*(int64_t*)key.data == i);
185 assert(val.size == 8);
186 assert(*(int64_t*)val.data == i);
187 } else {
188 CKERR2(r, error_to_expect);
189 break;
190 }
191 }
192
193 // Forwards
194
195 r = cursor->c_get(cursor, dbt_init(&key, &keys[int_left], sizeof keys[int_left]), dbt_init(&val, NULL, 0), DB_SET);
196 CKERR(r);
197 assert(val.size == 8);
198 assert(*(int64_t*)val.data == int_left);
199
200 cont_extra c;
201 c.left = int_left;
202 c.right = int_right;
203 c.error_to_expect = error_to_expect;
204 c.direction = 1;
205 c.last = int_left;
206 for (i=int_left+1; i < n; i+=3) {
207 c.found = 0;
208
209 r = cursor->c_getf_next(cursor, 0, getf_continue, &c);
210 if (i >= int_left && i <= int_right) {
211 CKERR(r);
212 if (!error_to_expect) {
213 assert(c.found == 3);
214 assert(c.last == i+2);
215 } else if (i+2 >= int_left && i+2 <= int_right) {
216 assert(c.found == 3);
217 assert(c.last == i+2);
218 } else if (i+1 >= int_left && i+1 <= int_right) {
219 assert(c.found == 2);
220 assert(c.last == i+1);
221 r = cursor->c_get(cursor, dbt_init(&key, NULL, 0), dbt_init(&val, NULL, 0), DB_CURRENT);
222 CKERR2(r, error_to_expect);
223 break;
224 } else {
225 assert(c.found == 1);
226 assert(c.last == i);
227 r = cursor->c_get(cursor, dbt_init(&key, NULL, 0), dbt_init(&val, NULL, 0), DB_CURRENT);
228 CKERR2(r, error_to_expect);
229 break;
230 }
231 } else {
232 if (error_to_expect == 0) {
233 assert(c.found == 3);
234 assert(c.last == i+2);
235 } else {
236 assert(c.found == 0);
237 assert(c.last == i-1);
238 }
239 CKERR2(r, error_to_expect);
240 break;
241 }
242 }
243
244 r = cursor->c_get(cursor, dbt_init(&key, &keys[int_right], sizeof keys[int_right]), dbt_init(&val, NULL, 0), DB_SET);
245 CKERR(r);
246 assert(val.size == 8);
247 assert(*(int64_t*)val.data == int_right);
248
249 c.direction = -1;
250 c.last = int_right;
251 for (i=int_right-1; i >= 0; i -= 3) {
252 c.found = 0;
253
254 r = cursor->c_getf_prev(cursor, 0, getf_continue, &c);
255 if (i >= int_left && i <= int_right) {
256 CKERR(r);
257 if (!error_to_expect) {
258 assert(c.found == 3);
259 assert(c.last == i-2);
260 } else if (i-2 >= int_left && i-2 <= int_right) {
261 assert(c.found == 3);
262 assert(c.last == i-2);
263 } else if (i-1 >= int_left && i-1 <= int_right) {
264 assert(c.found == 2);
265 assert(c.last == i-1);
266 r = cursor->c_get(cursor, dbt_init(&key, NULL, 0), dbt_init(&val, NULL, 0), DB_CURRENT);
267 CKERR2(r, error_to_expect);
268 break;
269 } else {
270 assert(c.found == 1);
271 assert(c.last == i);
272 r = cursor->c_get(cursor, dbt_init(&key, NULL, 0), dbt_init(&val, NULL, 0), DB_CURRENT);
273 CKERR2(r, error_to_expect);
274 break;
275 }
276 } else {
277 if (error_to_expect == 0) {
278 assert(c.found == 3);
279 assert(c.last == i-2);
280 } else {
281 assert(c.found == 0);
282 assert(c.last == i+1);
283 }
284 CKERR2(r, error_to_expect);
285 break;
286 }
287 }
288
289 r = cursor->c_close(cursor); CKERR(r);
290 r = db->close(db, 0); CKERR(r);
291 r = env->close(env, 0); CKERR(r);
292 }
293
294 int
test_main(int argc,char * const argv[])295 test_main(int argc, char *const argv[]) {
296 parse_args(argc, argv);
297 for (int i = 3*64; i < 3*1024; i *= 2) {
298 for (int offset = -2; offset <= 2; offset++) {
299 test_restrict(i, offset, DB_NOTFOUND);
300 test_restrict(i, offset, TOKUDB_OUT_OF_RANGE);
301 test_restrict(i, offset, 0);
302 }
303 }
304 return 0;
305 }
306