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