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