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