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