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 TokuDB
6
7
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9
10 TokuDBis 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 TokuDB 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 TokuDB. If not, see <http://www.gnu.org/licenses/>.
21
22 ======= */
23
24 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
25
26 // Test cardinality algorithm on a 2 level key where the first level is random in a space of size maxrand
27 // and the second level is unique.
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <memory.h>
33 #include <assert.h>
34 #include <errno.h>
35 #include <db.h>
36 #if __linux__
37 #include <endian.h>
38 #endif
39 #include <sys/stat.h>
40 typedef unsigned long long ulonglong;
41 #include "tokudb_status.h"
42 #include "tokudb_buffer.h"
43 #include "fake_mysql.h"
44 #if __APPLE__
45 typedef unsigned long ulong;
46 #endif
47 #include "tokudb_card.h"
48
hton32(uint32_t n)49 static uint32_t hton32(uint32_t n) {
50 #if BYTE_ORDER == LITTLE_ENDIAN
51 return __builtin_bswap32(n);
52 #else
53 return n;
54 #endif
55 }
56
57 struct key {
58 uint32_t r;
59 uint32_t seq;
60 }; // __attribute__((packed));
61
62 struct val {
63 uint32_t v0;
64 }; // __attribute__((packed));
65
66 // load nrows into the db
load_db(DB_ENV * env,DB * db,uint32_t nrows,uint32_t maxrand)67 static void load_db(DB_ENV *env, DB *db, uint32_t nrows, uint32_t maxrand) {
68 DB_TXN *txn = NULL;
69 int r = env->txn_begin(env, NULL, &txn, 0);
70 assert(r == 0);
71
72 DB_LOADER *loader = NULL;
73 uint32_t db_flags[1] = { 0 };
74 uint32_t dbt_flags[1] = { 0 };
75 uint32_t loader_flags = 0;
76 r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
77 assert(r == 0);
78
79 for (uint32_t seq = 0; seq < nrows ; seq++) {
80 struct key k = { hton32(random() % maxrand), hton32(seq) };
81 struct val v = { seq };
82 DBT key = { .data = &k, .size = sizeof k };
83 DBT val = { .data = &v, .size = sizeof v };
84 r = loader->put(loader, &key, &val);
85 assert(r == 0);
86 }
87
88 r = loader->close(loader);
89 assert(r == 0);
90
91 r = txn->commit(txn, 0);
92 assert(r == 0);
93 }
94
analyze_key_compare(DB * db,const DBT * a,const DBT * b,uint level)95 static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
96 assert(a->size == b->size);
97 switch (level) {
98 default:
99 assert(0);
100 case 1:
101 return memcmp(a->data, b->data, sizeof (uint32_t));
102 case 2:
103 assert(a->size == sizeof (struct key));
104 return memcmp(a->data, b->data, sizeof (struct key));
105 }
106 }
107
test_card(DB_ENV * env,DB * db,uint64_t expect[])108 static void test_card(DB_ENV *env, DB *db, uint64_t expect[]) {
109 int r;
110
111 DB_TXN *txn = NULL;
112 r = env->txn_begin(env, NULL, &txn, 0);
113 assert(r == 0);
114
115 uint64_t num_key_parts = 2;
116 uint64_t rec_per_key[num_key_parts];
117
118 r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, NULL, NULL);
119 assert(r == 0);
120
121 assert(rec_per_key[0] == expect[0]);
122 assert(rec_per_key[1] == expect[1]);
123
124 r = txn->commit(txn, 0);
125 assert(r == 0);
126 }
127
main(int argc,char * const argv[])128 int main(int argc, char * const argv[]) {
129 uint64_t nrows = 1000000;
130 uint32_t maxrand = 10;
131 for (int i = 1; i < argc; i++) {
132 if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
133 nrows = atoll(argv[++i]);
134 continue;
135 }
136 if (strcmp(argv[i], "--maxrand") == 0 && i+1 < argc) {
137 maxrand = atoi(argv[++i]);
138 continue;
139 }
140 }
141
142 int r;
143 r = system("rm -rf " __FILE__ ".testdir");
144 assert(r == 0);
145 r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
146 assert(r == 0);
147
148 DB_ENV *env = NULL;
149 r = db_env_create(&env, 0);
150 assert(r == 0);
151
152 r = env->open(env, __FILE__ ".testdir", DB_INIT_MPOOL + DB_INIT_LOG + DB_INIT_LOCK + DB_INIT_TXN + DB_PRIVATE + DB_CREATE, S_IRWXU+S_IRWXG+S_IRWXO);
153 assert(r == 0);
154
155 // create the db
156 DB *db = NULL;
157 r = db_create(&db, env, 0);
158 assert(r == 0);
159
160 r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
161 assert(r == 0);
162
163 // load the db
164 load_db(env, db, nrows, maxrand);
165
166 uint64_t expect[2] = { nrows/maxrand, 1 };
167 test_card(env, db, expect);
168
169 r = db->close(db, 0);
170 assert(r == 0);
171
172 r = env->close(env, 0);
173 assert(r == 0);
174
175 return 0;
176 }
177