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 /* try a reverse compare function to verify that the database always uses the application's
42 compare function */
43
44
45 #include <db.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <memory.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51 #include <unistd.h>
52
53
54 static int
keycompare(const void * key1,unsigned int key1len,const void * key2,unsigned int key2len)55 keycompare (const void *key1, unsigned int key1len, const void *key2, unsigned int key2len) {
56 if (key1len==key2len) {
57 return memcmp(key1,key2,key1len);
58 } else if (key1len<key2len) {
59 int r = memcmp(key1,key2,key1len);
60 if (r<=0) return -1; /* If the keys are the same up to 1's length, then return -1, since key1 is shorter than key2. */
61 else return 1;
62 } else {
63 return -keycompare(key2,key2len,key1,key1len);
64 }
65 }
66
67 static int
reverse_compare(DB * db,const DBT * a,const DBT * b)68 reverse_compare (DB *db __attribute__((__unused__)), const DBT *a, const DBT*b) {
69 return -keycompare(a->data, a->size, b->data, b->size);
70 }
71
72 static void
expect(DBC * cursor,int k,int v)73 expect (DBC *cursor, int k, int v) {
74 DBT key, val;
75 int r = cursor->c_get(cursor, dbt_init_malloc(&key), dbt_init_malloc(&val), DB_NEXT);
76 CKERR(r);
77 assert(key.size == sizeof k);
78 int kk;
79 memcpy(&kk, key.data, key.size);
80 assert(val.size == sizeof v);
81 int vv;
82 memcpy(&vv, val.data, val.size);
83 if (kk != k || vv != v) printf("expect key %u got %u - %u %u\n", (uint32_t)htonl(k), (uint32_t)htonl(kk), (uint32_t)htonl(v), (uint32_t)htonl(vv));
84 assert(kk == k);
85 assert(vv == v);
86
87 toku_free(key.data);
88 toku_free(val.data);
89 }
90
91 static void
test_reverse_compare(int n)92 test_reverse_compare (int n) {
93 if (verbose) printf("test_reverse_compare:%d\n", n);
94
95 DB_TXN * const null_txn = 0;
96 const char * const fname = "reverse.compare.db";
97
98 int r;
99 int i;
100
101 toku_os_recursive_delete(TOKU_TEST_FILENAME);
102 toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
103
104 /* create the dup database file */
105 DB_ENV *env;
106 r = db_env_create(&env, 0); assert(r == 0);
107 r = env->set_default_bt_compare(env, reverse_compare);
108 CKERR(r);
109 r = env->open(env, TOKU_TEST_FILENAME, DB_CREATE+DB_PRIVATE+DB_INIT_MPOOL, 0); assert(r == 0);
110
111 DB *db;
112 r = db_create(&db, env, 0);
113 CKERR(r);
114 r = db->set_pagesize(db, 4096);
115 CKERR(r);
116 r = db->open(db, null_txn, fname, "main", DB_BTREE, DB_CREATE, 0666);
117 CKERR(r);
118
119 /* insert n unique keys {0, 1, n-1} */
120 for (i=0; i<n; i++) {
121 DBT key, val;
122 int k, v;
123 k = htonl(i);
124 dbt_init(&key, &k, sizeof k);
125 v = htonl(i);
126 dbt_init(&val, &v, sizeof v);
127 r = db->put(db, null_txn, &key, &val, 0);
128 CKERR(r);
129 }
130
131 /* reopen the database to force nonleaf buffering */
132 r = db->close(db, 0);
133 CKERR(r);
134 r = db_create(&db, env, 0);
135 CKERR(r);
136 r = db->set_pagesize(db, 4096);
137 CKERR(r);
138 r = db->open(db, null_txn, fname, "main", DB_BTREE, 0, 0666);
139 CKERR(r);
140
141 /* insert n unique keys {n, n+1, 2*n-1} */
142 for (i=n; i<2*n; i++) {
143 DBT key, val;
144 int k, v;
145 k = htonl(i);
146 dbt_init(&key, &k, sizeof k);
147 v = htonl(i);
148 dbt_init(&val, &v, sizeof v);
149 r = db->put(db, null_txn, &key, &val, 0);
150 CKERR(r);
151 }
152
153 /* verify the sort order with a cursor */
154 DBC *cursor;
155 r = db->cursor(db, null_txn, &cursor, 0);
156 CKERR(r);
157
158 //for (i=0; i<2*n; i++)
159 for (i=2*n-1; i>=0; i--)
160 expect(cursor, htonl(i), htonl(i));
161
162 r = cursor->c_close(cursor);
163 CKERR(r);
164
165 r = db->close(db, 0); CKERR(r);
166 r = env->close(env, 0); CKERR(r);
167 }
168
169 int
test_main(int argc,char * const argv[])170 test_main(int argc, char *const argv[]) {
171 parse_args(argc, argv);
172
173 int i;
174
175 for (i = 1; i <= (1<<16); i *= 2) {
176 test_reverse_compare(i);
177 }
178 return 0;
179 }
180