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