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 identical 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 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
94 // only compare the first level of the key
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(level == 1);
97 assert(a->size == b->size);
98 assert(a->size == sizeof (struct key));
99 return memcmp(a->data, b->data, sizeof (uint32_t));
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 = txn->commit(txn, 0);
118 assert(r == 0);
119 }
120
main(int argc,char * const argv[])121 int main(int argc, char * const argv[]) {
122 uint64_t nrows = 1000000;
123 for (int i = 1; i < argc; i++) {
124 if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
125 nrows = atoll(argv[++i]);
126 continue;
127 }
128 }
129
130 int r;
131 r = system("rm -rf " __FILE__ ".testdir");
132 assert(r == 0);
133 r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
134 assert(r == 0);
135
136 DB_ENV *env = NULL;
137 r = db_env_create(&env, 0);
138 assert(r == 0);
139
140 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);
141 assert(r == 0);
142
143 // create the db
144 DB *db = NULL;
145 r = db_create(&db, env, 0);
146 assert(r == 0);
147
148 r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
149 assert(r == 0);
150
151 // load the db
152 load_db(env, db, nrows);
153
154 // test cardinality
155 test_card(env, db, nrows);
156
157 r = db->close(db, 0);
158 assert(r == 0);
159
160 r = env->close(env, 0);
161 assert(r == 0);
162
163 return 0;
164 }
165