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