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