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 // Verify that analyze can be terminated when its executing time limit is reached
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <stdint.h>
31 #include <inttypes.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 #include <sys/types.h>
41 typedef unsigned long long ulonglong;
42 #include "tokudb_status.h"
43 #include "tokudb_buffer.h"
44 #include "fake_mysql.h"
45 #if __APPLE__
46 typedef unsigned long ulong;
47 #endif
48 #include "tokudb_card.h"
49
50 static int verbose = 0;
51
hton32(uint32_t n)52 static uint32_t hton32(uint32_t n) {
53 #if BYTE_ORDER == LITTLE_ENDIAN
54 return __builtin_bswap32(n);
55 #else
56 return n;
57 #endif
58 }
59
60 struct key {
61 uint32_t k0;
62 }; // __attribute__((packed));
63
64 struct val {
65 uint32_t v0;
66 }; // __attribute__((packed));
67
68 // load nrows into the db
load_db(DB_ENV * env,DB * db,uint32_t nrows)69 static void load_db(DB_ENV *env, DB *db, uint32_t nrows) {
70 DB_TXN *txn = NULL;
71 int r = env->txn_begin(env, NULL, &txn, 0);
72 assert(r == 0);
73
74 DB_LOADER *loader = NULL;
75 uint32_t db_flags[1] = { 0 };
76 uint32_t dbt_flags[1] = { 0 };
77 uint32_t loader_flags = 0;
78 r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
79 assert(r == 0);
80
81 for (uint32_t seq = 0; seq < nrows ; seq++) {
82 struct key k = { hton32(seq) };
83 struct val v = { seq };
84 DBT key = { .data = &k, .size = sizeof k };
85 DBT val = { .data = &v, .size = sizeof v };
86 r = loader->put(loader, &key, &val);
87 assert(r == 0);
88 }
89
90 r = loader->close(loader);
91 assert(r == 0);
92
93 r = txn->commit(txn, 0);
94 assert(r == 0);
95 }
96
analyze_key_compare(DB * db,const DBT * a,const DBT * b,uint level)97 static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
98 assert(level == 1);
99 assert(a->size == b->size);
100 return memcmp(a->data, b->data, a->size);
101 }
102
103 struct analyze_extra {
104 uint64_t now;
105 uint64_t limit;
106 };
107
analyze_progress(void * extra,uint64_t rows)108 static int analyze_progress(void *extra, uint64_t rows) {
109 assert(rows > 0);
110 struct analyze_extra *e = (struct analyze_extra *) extra;
111 e->now++;
112 int r;
113 if (e->limit > 0 && e->now >= e->limit)
114 r = ETIME;
115 else
116 r = 0;
117 if (verbose)
118 printf("%s %"PRIu64" %"PRIu64" r=%d\n", __FUNCTION__, e->now, e->limit, r);
119 return r;
120 }
121
test_card(DB_ENV * env,DB * db,uint64_t expect_card,uint64_t limit)122 static void test_card(DB_ENV *env, DB *db, uint64_t expect_card, uint64_t limit) {
123 int r;
124
125 DB_TXN *txn = NULL;
126 r = env->txn_begin(env, NULL, &txn, 0);
127 assert(r == 0);
128
129 uint64_t num_key_parts = 1;
130 uint64_t rec_per_key[num_key_parts];
131 for (uint64_t i = 0; i < num_key_parts; i++)
132 rec_per_key[i] = 0;
133
134 struct analyze_extra analyze_extra = { 0, limit };
135 r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, analyze_progress, &analyze_extra);
136 if (limit == 0) {
137 assert(r == 0);
138 } else {
139 assert(r == ETIME);
140 assert(analyze_extra.now == analyze_extra.limit);
141 }
142
143 assert(rec_per_key[0] == expect_card);
144
145 r = txn->commit(txn, 0);
146 assert(r == 0);
147 }
148
main(int argc,char * const argv[])149 int main(int argc, char * const argv[]) {
150 uint32_t nrows = 1000000;
151 for (int i = 1; i < argc; i++) {
152 if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
153 verbose++;
154 continue;
155 }
156 if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
157 nrows = atoi(argv[++i]);
158 continue;
159 }
160 }
161
162 int r;
163 r = system("rm -rf " __FILE__ ".testdir");
164 assert(r == 0);
165 r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
166 assert(r == 0);
167
168 DB_ENV *env = NULL;
169 r = db_env_create(&env, 0);
170 assert(r == 0);
171
172 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);
173 assert(r == 0);
174
175 // create the db
176 DB *db = NULL;
177 r = db_create(&db, env, 0);
178 assert(r == 0);
179
180 r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
181 assert(r == 0);
182
183 // load the db
184 load_db(env, db, nrows);
185
186 // test cardinality
187 test_card(env, db, 1, 0);
188 test_card(env, db, 1, 1);
189 test_card(env, db, 1, 10);
190 test_card(env, db, 1, 100);
191
192 r = db->close(db, 0);
193 assert(r == 0);
194
195 r = env->close(env, 0);
196 assert(r == 0);
197
198 return 0;
199 }
200