summaryrefslogtreecommitdiffstats
path: root/storage/tokudb/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:07:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:07:14 +0000
commita175314c3e5827eb193872241446f2f8f5c9d33c (patch)
treecd3d60ca99ae00829c52a6ca79150a5b6e62528b /storage/tokudb/tests
parentInitial commit. (diff)
downloadmariadb-10.5-upstream.tar.xz
mariadb-10.5-upstream.zip
Adding upstream version 1:10.5.12.upstream/1%10.5.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/tokudb/tests')
-rw-r--r--storage/tokudb/tests/Makefile53
-rw-r--r--storage/tokudb/tests/card_1.cc169
-rw-r--r--storage/tokudb/tests/card_etime.cc199
-rw-r--r--storage/tokudb/tests/card_inf.cc164
-rw-r--r--storage/tokudb/tests/card_inf_1.cc170
-rw-r--r--storage/tokudb/tests/card_random_1.cc176
-rw-r--r--storage/tokudb/tests/card_test.cc204
-rw-r--r--storage/tokudb/tests/card_test_alter.cc621
-rw-r--r--storage/tokudb/tests/card_test_key_info.cc146
-rw-r--r--storage/tokudb/tests/fake_mysql.h50
-rw-r--r--storage/tokudb/tests/math_test_int.cc272
-rw-r--r--storage/tokudb/tests/math_test_uint.cc187
-rw-r--r--storage/tokudb/tests/max_test.cc47
-rw-r--r--storage/tokudb/tests/sint_test.cc53
-rw-r--r--storage/tokudb/tests/tokudb_buffer_test.cc234
-rw-r--r--storage/tokudb/tests/uint_test.cc54
-rw-r--r--storage/tokudb/tests/vlq_test.cc88
-rw-r--r--storage/tokudb/tests/vlq_test_uint32.cc99
-rw-r--r--storage/tokudb/tests/vlq_test_uint64.cc110
19 files changed, 3096 insertions, 0 deletions
diff --git a/storage/tokudb/tests/Makefile b/storage/tokudb/tests/Makefile
new file mode 100644
index 00000000..47e2027e
--- /dev/null
+++ b/storage/tokudb/tests/Makefile
@@ -0,0 +1,53 @@
+SRCS = $(wildcard *.cc)
+TARGETS = $(patsubst %.cc,%,$(SRCS))
+CHECKS = $(patsubst %,%.check,$(TARGETS))
+CPPFLAGS = -I.. -D__STDC_FORMAT_MACROS
+CXXFLAGS = -g -Wall -Wextra -Wno-missing-field-initializers -Wshadow
+ifdef USE_OPENMP
+CPPFLAGS += -DUSE_OPENMP
+CXXFLAGS += -fopenmp
+endif
+
+FRACTALTREE_BASE_DIR = ../ft-index
+FRACTALTREE_INSTALL_DIR = $(FRACTALTREE_BASE_DIR)/install.debug
+VALGRIND = valgrind -q --leak-check=full --show-reachable=yes --suppressions=$(FRACTALTREE_BASE_DIR)/ft/valgrind.suppressions --soname-synonyms=somalloc=*tokuportability*
+
+ifeq ($(GCOV),1)
+CXXFLAGS += -fprofile-arcs -ftest-coverage
+else
+CXXFLAGS += -O3
+endif
+
+all: $(TARGETS)
+
+clean:
+ rm -rf $(TARGETS) *.gcov *.gcno *.gcda *.testdir *.dSYM
+
+%.check: %
+ LD_LIBRARY_PATH=$(FRACTALTREE_INSTALL_DIR)/lib $(VALGRIND) ./$<
+
+card.check: $(patsubst %.cc,%.check,$(wildcard card*.cc))
+ true
+
+ifndef USE_OPENMP
+# unravel vlq_test_uint64 8 times
+vlq_test_uint64_%.check:
+ LD_LIBRARY_PATH=$(FRACTALTREE_INSTALL_DIR)/lib $(VALGRIND) ./vlq_test_uint64 $(patsubst vlq_test_uint64_%.check,%,$@) 8
+vlq_test_uint64.check: $(foreach i,0 1 2 3 4 5 6 7,vlq_test_uint64_$(i).check)
+ true
+endif
+
+vlq.check: $(patsubst %.cc,%.check,$(wildcard vlq*.cc))
+ true
+
+max_test.check: max_test
+ $(VALGRIND) ./$< 1 2
+
+check: $(CHECKS)
+ true
+
+%: %.cc
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o $@ $<
+
+card_%: card_%.cc
+ $(CXX) $(CPPFLAGS) $(CXXFLAGS) -g -o $@ $< -I.. -I$(FRACTALTREE_INSTALL_DIR)/include -L$(FRACTALTREE_INSTALL_DIR)/lib -ltokufractaltree -ltokuportability
diff --git a/storage/tokudb/tests/card_1.cc b/storage/tokudb/tests/card_1.cc
new file mode 100644
index 00000000..8c6934e0
--- /dev/null
+++ b/storage/tokudb/tests/card_1.cc
@@ -0,0 +1,169 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// Test cardinality algorithm on a single level unique key
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <memory.h>
+#include <assert.h>
+#include <errno.h>
+#include <db.h>
+#if __linux__
+#include <endian.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+typedef unsigned long long ulonglong;
+#include "tokudb_status.h"
+#include "tokudb_buffer.h"
+
+#include "fake_mysql.h"
+
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include "tokudb_card.h"
+
+static uint32_t hton32(uint32_t n) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return __builtin_bswap32(n);
+#else
+ return n;
+#endif
+}
+
+struct key {
+ uint32_t k0;
+}; // __attribute__((packed));
+
+struct val {
+ uint32_t v0;
+}; // __attribute__((packed));
+
+// load nrows into the db
+static void load_db(DB_ENV *env, DB *db, uint32_t nrows) {
+ DB_TXN *txn = NULL;
+ int r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ DB_LOADER *loader = NULL;
+ uint32_t db_flags[1] = { 0 };
+ uint32_t dbt_flags[1] = { 0 };
+ uint32_t loader_flags = 0;
+ r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
+ assert(r == 0);
+
+ for (uint32_t seq = 0; seq < nrows ; seq++) {
+ struct key k = { hton32(seq) };
+ struct val v = { seq };
+ DBT key = { .data = &k, .size = sizeof k };
+ DBT val = { .data = &v, .size = sizeof v };
+ r = loader->put(loader, &key, &val);
+ assert(r == 0);
+ }
+
+ r = loader->close(loader);
+ assert(r == 0);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
+ assert(level == 1);
+ assert(a->size == b->size);
+ return memcmp(a->data, b->data, a->size);
+}
+
+static void test_card(DB_ENV *env, DB *db, uint64_t expect_card) {
+ int r;
+
+ DB_TXN *txn = NULL;
+ r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ uint64_t num_key_parts = 1;
+ uint64_t rec_per_key[num_key_parts];
+
+ r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, NULL, NULL);
+ assert(r == 0);
+
+ assert(rec_per_key[0] == expect_card);
+
+ r = tokudb::analyze_card(db, txn, true, num_key_parts, rec_per_key, analyze_key_compare, NULL, NULL);
+ assert(r == 0);
+
+ assert(rec_per_key[0] == expect_card);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char * const argv[]) {
+ uint32_t nrows = 1000000;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
+ nrows = atoi(argv[++i]);
+ continue;
+ }
+ }
+
+ int r;
+ r = system("rm -rf " __FILE__ ".testdir");
+ assert(r == 0);
+ r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ DB_ENV *env = NULL;
+ r = db_env_create(&env, 0);
+ assert(r == 0);
+
+ 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);
+ assert(r == 0);
+
+ // create the db
+ DB *db = NULL;
+ r = db_create(&db, env, 0);
+ assert(r == 0);
+
+ r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ // load the db
+ load_db(env, db, nrows);
+
+ // test cardinality
+ test_card(env, db, 1);
+
+ r = db->close(db, 0);
+ assert(r == 0);
+
+ r = env->close(env, 0);
+ assert(r == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_etime.cc b/storage/tokudb/tests/card_etime.cc
new file mode 100644
index 00000000..11cff5cb
--- /dev/null
+++ b/storage/tokudb/tests/card_etime.cc
@@ -0,0 +1,199 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// Verify that analyze can be terminated when its executing time limit is reached
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <memory.h>
+#include <assert.h>
+#include <errno.h>
+#include <db.h>
+#if __linux__
+#include <endian.h>
+#endif
+#include <sys/stat.h>
+#include <sys/types.h>
+typedef unsigned long long ulonglong;
+#include "tokudb_status.h"
+#include "tokudb_buffer.h"
+#include "fake_mysql.h"
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include "tokudb_card.h"
+
+static int verbose = 0;
+
+static uint32_t hton32(uint32_t n) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return __builtin_bswap32(n);
+#else
+ return n;
+#endif
+}
+
+struct key {
+ uint32_t k0;
+}; // __attribute__((packed));
+
+struct val {
+ uint32_t v0;
+}; // __attribute__((packed));
+
+// load nrows into the db
+static void load_db(DB_ENV *env, DB *db, uint32_t nrows) {
+ DB_TXN *txn = NULL;
+ int r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ DB_LOADER *loader = NULL;
+ uint32_t db_flags[1] = { 0 };
+ uint32_t dbt_flags[1] = { 0 };
+ uint32_t loader_flags = 0;
+ r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
+ assert(r == 0);
+
+ for (uint32_t seq = 0; seq < nrows ; seq++) {
+ struct key k = { hton32(seq) };
+ struct val v = { seq };
+ DBT key = { .data = &k, .size = sizeof k };
+ DBT val = { .data = &v, .size = sizeof v };
+ r = loader->put(loader, &key, &val);
+ assert(r == 0);
+ }
+
+ r = loader->close(loader);
+ assert(r == 0);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
+ assert(level == 1);
+ assert(a->size == b->size);
+ return memcmp(a->data, b->data, a->size);
+}
+
+struct analyze_extra {
+ uint64_t now;
+ uint64_t limit;
+};
+
+static int analyze_progress(void *extra, uint64_t rows) {
+ assert(rows > 0);
+ struct analyze_extra *e = (struct analyze_extra *) extra;
+ e->now++;
+ int r;
+ if (e->limit > 0 && e->now >= e->limit)
+ r = ETIME;
+ else
+ r = 0;
+ if (verbose)
+ printf("%s %"PRIu64" %"PRIu64" r=%d\n", __FUNCTION__, e->now, e->limit, r);
+ return r;
+}
+
+static void test_card(DB_ENV *env, DB *db, uint64_t expect_card, uint64_t limit) {
+ int r;
+
+ DB_TXN *txn = NULL;
+ r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ uint64_t num_key_parts = 1;
+ uint64_t rec_per_key[num_key_parts];
+ for (uint64_t i = 0; i < num_key_parts; i++)
+ rec_per_key[i] = 0;
+
+ struct analyze_extra analyze_extra = { 0, limit };
+ r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, analyze_progress, &analyze_extra);
+ if (limit == 0) {
+ assert(r == 0);
+ } else {
+ assert(r == ETIME);
+ assert(analyze_extra.now == analyze_extra.limit);
+ }
+
+ assert(rec_per_key[0] == expect_card);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char * const argv[]) {
+ uint32_t nrows = 1000000;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) {
+ verbose++;
+ continue;
+ }
+ if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
+ nrows = atoi(argv[++i]);
+ continue;
+ }
+ }
+
+ int r;
+ r = system("rm -rf " __FILE__ ".testdir");
+ assert(r == 0);
+ r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ DB_ENV *env = NULL;
+ r = db_env_create(&env, 0);
+ assert(r == 0);
+
+ 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);
+ assert(r == 0);
+
+ // create the db
+ DB *db = NULL;
+ r = db_create(&db, env, 0);
+ assert(r == 0);
+
+ r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ // load the db
+ load_db(env, db, nrows);
+
+ // test cardinality
+ test_card(env, db, 1, 0);
+ test_card(env, db, 1, 1);
+ test_card(env, db, 1, 10);
+ test_card(env, db, 1, 100);
+
+ r = db->close(db, 0);
+ assert(r == 0);
+
+ r = env->close(env, 0);
+ assert(r == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_inf.cc b/storage/tokudb/tests/card_inf.cc
new file mode 100644
index 00000000..fda51f9a
--- /dev/null
+++ b/storage/tokudb/tests/card_inf.cc
@@ -0,0 +1,164 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// Test cardinality algorithm on a single level identical key
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <memory.h>
+#include <assert.h>
+#include <errno.h>
+#include <db.h>
+#if __linux__
+#include <endian.h>
+#endif
+#include <sys/stat.h>
+typedef unsigned long long ulonglong;
+#include "tokudb_status.h"
+#include "tokudb_buffer.h"
+#include "fake_mysql.h"
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include "tokudb_card.h"
+
+static uint32_t hton32(uint32_t n) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return __builtin_bswap32(n);
+#else
+ return n;
+#endif
+}
+
+struct key {
+ uint32_t k0;
+ uint32_t seq;
+}; // __attribute__((packed));
+
+struct val {
+ uint32_t v0;
+}; // __attribute__((packed));
+
+// load nrows into the db
+static void load_db(DB_ENV *env, DB *db, uint32_t nrows) {
+ DB_TXN *txn = NULL;
+ int r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ DB_LOADER *loader = NULL;
+ uint32_t db_flags[1] = { 0 };
+ uint32_t dbt_flags[1] = { 0 };
+ uint32_t loader_flags = 0;
+ r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
+ assert(r == 0);
+
+ for (uint32_t seq = 0; seq < nrows ; seq++) {
+ struct key k = { 0, hton32(seq) };
+ struct val v = { seq };
+ DBT key = { .data = &k, .size = sizeof k };
+ DBT val = { .data = &v, .size = sizeof v };
+ r = loader->put(loader, &key, &val);
+ assert(r == 0);
+ }
+
+ r = loader->close(loader);
+ assert(r == 0);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+// only compare the first level of the key
+static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
+ assert(level == 1);
+ assert(a->size == b->size);
+ assert(a->size == sizeof (struct key));
+ return memcmp(a->data, b->data, sizeof (uint32_t));
+}
+
+static void test_card(DB_ENV *env, DB *db, uint64_t expect_card) {
+ int r;
+
+ DB_TXN *txn = NULL;
+ r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ uint64_t num_key_parts = 1;
+ uint64_t rec_per_key[num_key_parts];
+
+ r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, NULL, NULL);
+ assert(r == 0);
+
+ assert(rec_per_key[0] == expect_card);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char * const argv[]) {
+ uint64_t nrows = 1000000;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
+ nrows = atoll(argv[++i]);
+ continue;
+ }
+ }
+
+ int r;
+ r = system("rm -rf " __FILE__ ".testdir");
+ assert(r == 0);
+ r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ DB_ENV *env = NULL;
+ r = db_env_create(&env, 0);
+ assert(r == 0);
+
+ 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);
+ assert(r == 0);
+
+ // create the db
+ DB *db = NULL;
+ r = db_create(&db, env, 0);
+ assert(r == 0);
+
+ r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ // load the db
+ load_db(env, db, nrows);
+
+ // test cardinality
+ test_card(env, db, nrows);
+
+ r = db->close(db, 0);
+ assert(r == 0);
+
+ r = env->close(env, 0);
+ assert(r == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_inf_1.cc b/storage/tokudb/tests/card_inf_1.cc
new file mode 100644
index 00000000..ca35b260
--- /dev/null
+++ b/storage/tokudb/tests/card_inf_1.cc
@@ -0,0 +1,170 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// Test cardinality algorithm on a 2 level key where the first level is identical and the second level is unique
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <memory.h>
+#include <assert.h>
+#include <errno.h>
+#include <db.h>
+#if __linux__
+#include <endian.h>
+#endif
+#include <sys/stat.h>
+typedef unsigned long long ulonglong;
+#include "tokudb_status.h"
+#include "tokudb_buffer.h"
+#include "fake_mysql.h"
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include "tokudb_card.h"
+
+static uint32_t hton32(uint32_t n) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return __builtin_bswap32(n);
+#else
+ return n;
+#endif
+}
+
+struct key {
+ uint32_t k0;
+ uint32_t seq;
+}; // __attribute__((packed));
+
+struct val {
+ uint32_t v0;
+}; // __attribute__((packed));
+
+// load nrows into the db
+static void load_db(DB_ENV *env, DB *db, uint32_t nrows) {
+ DB_TXN *txn = NULL;
+ int r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ DB_LOADER *loader = NULL;
+ uint32_t db_flags[1] = { 0 };
+ uint32_t dbt_flags[1] = { 0 };
+ uint32_t loader_flags = 0;
+ r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
+ assert(r == 0);
+
+ for (uint32_t seq = 0; seq < nrows ; seq++) {
+ struct key k = { 0, hton32(seq) };
+ struct val v = { seq };
+ DBT key = { .data = &k, .size = sizeof k };
+ DBT val = { .data = &v, .size = sizeof v };
+ r = loader->put(loader, &key, &val);
+ assert(r == 0);
+ }
+
+ r = loader->close(loader);
+ assert(r == 0);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
+ assert(a->size == b->size);
+ switch (level) {
+ default:
+ assert(0);
+ case 1:
+ return memcmp(a->data, b->data, sizeof (uint32_t));
+ case 2:
+ assert(a->size == sizeof (struct key));
+ return memcmp(a->data, b->data, sizeof (struct key));
+ }
+}
+
+static void test_card(DB_ENV *env, DB *db, uint64_t expect[]) {
+ int r;
+
+ DB_TXN *txn = NULL;
+ r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ uint64_t num_key_parts = 2;
+ uint64_t rec_per_key[num_key_parts];
+
+ r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, NULL, NULL);
+ assert(r == 0);
+
+ assert(rec_per_key[0] == expect[0]);
+ assert(rec_per_key[1] == expect[1]);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char * const argv[]) {
+ uint64_t nrows = 1000000;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
+ nrows = atoll(argv[++i]);
+ continue;
+ }
+ }
+
+ int r;
+ r = system("rm -rf " __FILE__ ".testdir");
+ assert(r == 0);
+ r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ DB_ENV *env = NULL;
+ r = db_env_create(&env, 0);
+ assert(r == 0);
+
+ 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);
+ assert(r == 0);
+
+ // create the db
+ DB *db = NULL;
+ r = db_create(&db, env, 0);
+ assert(r == 0);
+
+ r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ // load the db
+ load_db(env, db, nrows);
+
+ uint64_t expect[2] = { nrows, 1 };
+ test_card(env, db, expect);
+
+ r = db->close(db, 0);
+ assert(r == 0);
+
+ r = env->close(env, 0);
+ assert(r == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_random_1.cc b/storage/tokudb/tests/card_random_1.cc
new file mode 100644
index 00000000..a7603ab6
--- /dev/null
+++ b/storage/tokudb/tests/card_random_1.cc
@@ -0,0 +1,176 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// Test cardinality algorithm on a 2 level key where the first level is random in a space of size maxrand
+// and the second level is unique.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <memory.h>
+#include <assert.h>
+#include <errno.h>
+#include <db.h>
+#if __linux__
+#include <endian.h>
+#endif
+#include <sys/stat.h>
+typedef unsigned long long ulonglong;
+#include "tokudb_status.h"
+#include "tokudb_buffer.h"
+#include "fake_mysql.h"
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include "tokudb_card.h"
+
+static uint32_t hton32(uint32_t n) {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ return __builtin_bswap32(n);
+#else
+ return n;
+#endif
+}
+
+struct key {
+ uint32_t r;
+ uint32_t seq;
+}; // __attribute__((packed));
+
+struct val {
+ uint32_t v0;
+}; // __attribute__((packed));
+
+// load nrows into the db
+static void load_db(DB_ENV *env, DB *db, uint32_t nrows, uint32_t maxrand) {
+ DB_TXN *txn = NULL;
+ int r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ DB_LOADER *loader = NULL;
+ uint32_t db_flags[1] = { 0 };
+ uint32_t dbt_flags[1] = { 0 };
+ uint32_t loader_flags = 0;
+ r = env->create_loader(env, txn, &loader, db, 1, &db, db_flags, dbt_flags, loader_flags);
+ assert(r == 0);
+
+ for (uint32_t seq = 0; seq < nrows ; seq++) {
+ struct key k = { hton32(random() % maxrand), hton32(seq) };
+ struct val v = { seq };
+ DBT key = { .data = &k, .size = sizeof k };
+ DBT val = { .data = &v, .size = sizeof v };
+ r = loader->put(loader, &key, &val);
+ assert(r == 0);
+ }
+
+ r = loader->close(loader);
+ assert(r == 0);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+static int analyze_key_compare(DB *db __attribute__((unused)), const DBT *a, const DBT *b, uint level) {
+ assert(a->size == b->size);
+ switch (level) {
+ default:
+ assert(0);
+ case 1:
+ return memcmp(a->data, b->data, sizeof (uint32_t));
+ case 2:
+ assert(a->size == sizeof (struct key));
+ return memcmp(a->data, b->data, sizeof (struct key));
+ }
+}
+
+static void test_card(DB_ENV *env, DB *db, uint64_t expect[]) {
+ int r;
+
+ DB_TXN *txn = NULL;
+ r = env->txn_begin(env, NULL, &txn, 0);
+ assert(r == 0);
+
+ uint64_t num_key_parts = 2;
+ uint64_t rec_per_key[num_key_parts];
+
+ r = tokudb::analyze_card(db, txn, false, num_key_parts, rec_per_key, analyze_key_compare, NULL, NULL);
+ assert(r == 0);
+
+ assert(rec_per_key[0] == expect[0]);
+ assert(rec_per_key[1] == expect[1]);
+
+ r = txn->commit(txn, 0);
+ assert(r == 0);
+}
+
+int main(int argc, char * const argv[]) {
+ uint64_t nrows = 1000000;
+ uint32_t maxrand = 10;
+ for (int i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--nrows") == 0 && i+1 < argc) {
+ nrows = atoll(argv[++i]);
+ continue;
+ }
+ if (strcmp(argv[i], "--maxrand") == 0 && i+1 < argc) {
+ maxrand = atoi(argv[++i]);
+ continue;
+ }
+ }
+
+ int r;
+ r = system("rm -rf " __FILE__ ".testdir");
+ assert(r == 0);
+ r = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ DB_ENV *env = NULL;
+ r = db_env_create(&env, 0);
+ assert(r == 0);
+
+ 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);
+ assert(r == 0);
+
+ // create the db
+ DB *db = NULL;
+ r = db_create(&db, env, 0);
+ assert(r == 0);
+
+ r = db->open(db, NULL, "test.db", 0, DB_BTREE, DB_CREATE + DB_AUTO_COMMIT, S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(r == 0);
+
+ // load the db
+ load_db(env, db, nrows, maxrand);
+
+ uint64_t expect[2] = { nrows/maxrand, 1 };
+ test_card(env, db, expect);
+
+ r = db->close(db, 0);
+ assert(r == 0);
+
+ r = env->close(env, 0);
+ assert(r == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_test.cc b/storage/tokudb/tests/card_test.cc
new file mode 100644
index 00000000..b34a94cf
--- /dev/null
+++ b/storage/tokudb/tests/card_test.cc
@@ -0,0 +1,204 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// test tokudb cardinality in status dictionary
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <memory.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <db.h>
+typedef unsigned long long ulonglong;
+#include <tokudb_status.h>
+#include <tokudb_buffer.h>
+
+#include "fake_mysql.h"
+
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include <tokudb_card.h>
+
+// verify that we can create and close a status dictionary
+static void test_create(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status.db", txn);
+ assert(error == 0);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+// verify that no card row in status works
+static void test_no_card(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::open_status(env, &status_db, "status.db", txn);
+ assert(error == 0);
+
+ error = tokudb::get_card_from_status(status_db, txn, 0, NULL);
+ assert(error == DB_NOTFOUND);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+// verify that a card row with 0 array elements works
+static void test_0(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::open_status(env, &status_db, "status.db", txn);
+ assert(error == 0);
+
+ tokudb::set_card_in_status(status_db, txn, 0, NULL);
+
+ error = tokudb::get_card_from_status(status_db, txn, 0, NULL);
+ assert(error == 0);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+// verify that writing and reading card info works for several sized card arrays
+static void test_10(DB_ENV *env) {
+ int error;
+
+ for (uint64_t i = 0; i < 20; i++) {
+
+ uint64_t rec_per_key[i];
+ for (uint64_t j = 0; j < i; j++)
+ rec_per_key[j] = j == 0 ? 10+i : 10 * rec_per_key[j-1];
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::open_status(env, &status_db, "status.db", txn);
+ assert(error == 0);
+
+ tokudb::set_card_in_status(status_db, txn, i, rec_per_key);
+
+ uint64_t stored_rec_per_key[i];
+ error = tokudb::get_card_from_status(status_db, txn, i, stored_rec_per_key);
+ assert(error == 0);
+
+ for (uint64_t j = 0; j < i; j++)
+ assert(rec_per_key[j] == stored_rec_per_key[j]);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ error = tokudb::open_status(env, &status_db, "status.db", txn);
+ assert(error == 0);
+
+ tokudb::set_card_in_status(status_db, txn, i, rec_per_key);
+
+ error = tokudb::get_card_from_status(status_db, txn, i, stored_rec_per_key);
+ assert(error == 0);
+
+ for (uint64_t j = 0; j < i; j++)
+ assert(rec_per_key[j] == stored_rec_per_key[j]);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ // test delete card
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ error = tokudb::delete_card_from_status(status_db, txn);
+ assert(error == 0);
+
+ error = tokudb::get_card_from_status(status_db, txn, 0, NULL);
+ assert(error == DB_NOTFOUND);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+ }
+}
+
+int main() {
+ int error;
+
+ error = system("rm -rf " __FILE__ ".testdir");
+ assert(error == 0);
+
+ error = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(error == 0);
+
+ DB_ENV *env = NULL;
+ error = db_env_create(&env, 0);
+ assert(error == 0);
+
+ error = 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);
+ assert(error == 0);
+
+ test_create(env);
+ test_no_card(env);
+ test_0(env);
+ test_10(env);
+
+ error = env->close(env, 0);
+ assert(error == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_test_alter.cc b/storage/tokudb/tests/card_test_alter.cc
new file mode 100644
index 00000000..236dfbf1
--- /dev/null
+++ b/storage/tokudb/tests/card_test_alter.cc
@@ -0,0 +1,621 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// test tokudb cardinality in status dictionary
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <memory.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <db.h>
+typedef unsigned long long ulonglong;
+#include <tokudb_status.h>
+#include <tokudb_buffer.h>
+
+#include "fake_mysql.h"
+
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include <tokudb_card.h>
+
+static void test_no_keys(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_no_keys", txn);
+ assert(error == 0);
+
+ const uint keys = 0;
+ const uint key_parts = 0;
+ TABLE_SHARE s = { MAX_KEY, keys, key_parts, NULL };
+
+ error = tokudb::alter_card(status_db, txn, &s, &s);
+ assert(error == 0);
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_keys(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_keys", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 3;
+ const uint ta_key_parts = 1;
+ const int ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 1000, 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_a" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &ta);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[ta_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, ta_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < ta_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == ta_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_drop_0(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_drop_0", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 3;
+ const uint ta_key_parts = 1;
+ const uint ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 1000, 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_a" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[2], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 2;
+ const uint tb_key_parts = 1;
+ const int tb_rec_per_keys = tb_keys * tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 2000, 3000,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, tb_key_parts, &tb_rec_per_key[0], (char *) "key_b" },
+ { 0, tb_key_parts, &tb_rec_per_key[1], (char *) "key_c" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_drop_1(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_drop_1", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 3;
+ const uint ta_key_parts = 1;
+ const uint ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 1000, 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_a" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[2], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 2;
+ const uint tb_key_parts = 1;
+ const int tb_rec_per_keys = tb_keys * tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 1000, 3000,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, tb_key_parts, &tb_rec_per_key[0], (char *) "key_a" },
+ { 0, tb_key_parts, &tb_rec_per_key[1], (char *) "key_c" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_drop_2(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_drop_2", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 3;
+ const uint ta_key_parts = 1;
+ const uint ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 1000, 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_a" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[2], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 2;
+ const uint tb_key_parts = 1;
+ const int tb_rec_per_keys = tb_keys * tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 1000, 2000,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, tb_key_parts, &tb_rec_per_key[0], (char *) "key_a" },
+ { 0, tb_key_parts, &tb_rec_per_key[1], (char *) "key_b" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_drop_1_multiple_parts(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_drop_1_multiple_parts", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 3;
+ const uint ta_key_parts = 1+2+3;
+ const uint ta_rec_per_keys = ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 1000, 2000, 2001, 3000, 3001, 3002,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, 1, &ta_rec_per_key[0], (char *) "key_a" },
+ { 0, 2, &ta_rec_per_key[0+1], (char *) "key_b" },
+ { 0, 3, &ta_rec_per_key[0+1+2], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 2;
+ const uint tb_key_parts = 1+3;
+ const int tb_rec_per_keys = tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 1000, 3000, 3001, 3002,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, 1, &tb_rec_per_key[0], (char *) "key_a" },
+ { 0, 3, &tb_rec_per_key[0+1], (char *) "key_c" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_add_0(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_add_0", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 2;
+ const uint ta_key_parts = 1;
+ const uint ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 3;
+ const uint tb_key_parts = 1;
+ const int tb_rec_per_keys = tb_keys * tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 0 /*not computed*/, 2000, 3000,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, tb_key_parts, &tb_rec_per_key[0], (char *) "key_a" },
+ { 0, tb_key_parts, &tb_rec_per_key[1], (char *) "key_b" },
+ { 0, tb_key_parts, &tb_rec_per_key[2], (char *) "key_c" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_add_1(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_add_1", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 2;
+ const uint ta_key_parts = 1;
+ const uint ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 3;
+ const uint tb_key_parts = 1;
+ const int tb_rec_per_keys = tb_keys * tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 2000, 0 /*not computed*/, 3000,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, tb_key_parts, &tb_rec_per_key[0], (char *) "key_b" },
+ { 0, tb_key_parts, &tb_rec_per_key[1], (char *) "key_a" },
+ { 0, tb_key_parts, &tb_rec_per_key[2], (char *) "key_c" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_add_2(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_add_2", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 2;
+ const uint ta_key_parts = 1;
+ const uint ta_rec_per_keys = ta_keys * ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 2000, 3000,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, ta_key_parts, &ta_rec_per_key[0], (char *) "key_b" },
+ { 0, ta_key_parts, &ta_rec_per_key[1], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 3;
+ const uint tb_key_parts = 1;
+ const int tb_rec_per_keys = tb_keys * tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 2000, 3000, 0 /*not computed*/,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, tb_key_parts, &tb_rec_per_key[0], (char *) "key_b" },
+ { 0, tb_key_parts, &tb_rec_per_key[1], (char *) "key_c" },
+ { 0, tb_key_parts, &tb_rec_per_key[2], (char *) "key_a" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+static void test_add_0_multiple_parts(DB_ENV *env) {
+ int error;
+
+ DB_TXN *txn = NULL;
+ error = env->txn_begin(env, NULL, &txn, 0);
+ assert(error == 0);
+
+ DB *status_db = NULL;
+ error = tokudb::create_status(env, &status_db, "status_add_0_multiple_parts", txn);
+ assert(error == 0);
+
+ // define tables
+ const uint ta_keys = 2;
+ const uint ta_key_parts = 3+4;
+ const uint ta_rec_per_keys = ta_key_parts;
+ uint64_t ta_rec_per_key[ta_rec_per_keys] = {
+ 2000, 2001, 2002, 3000, 3001, 3002, 3003,
+ };
+ KEY_INFO ta_key_info[ta_rec_per_keys] = {
+ { 0, 3, &ta_rec_per_key[0], (char *) "key_b" },
+ { 0, 4, &ta_rec_per_key[3], (char *) "key_c" },
+ };
+ TABLE_SHARE ta = { MAX_KEY, ta_keys, ta_key_parts, ta_key_info };
+
+ const uint tb_keys = 3;
+ const uint tb_key_parts = 2+3+4;
+ const int tb_rec_per_keys = tb_key_parts;
+ uint64_t tb_rec_per_key[tb_rec_per_keys] = {
+ 0, 0 /*not computed*/, 2000, 2001, 2002, 3000, 3001, 3002, 3003,
+ };
+ KEY_INFO tb_key_info[tb_rec_per_keys] = {
+ { 0, 2, &tb_rec_per_key[0], (char *) "key_a" },
+ { 0, 3, &tb_rec_per_key[0+2], (char *) "key_b" },
+ { 0, 4, &tb_rec_per_key[0+2+3], (char *) "key_c" },
+ };
+ TABLE_SHARE tb = { MAX_KEY, tb_keys, tb_key_parts, tb_key_info };
+
+ // set initial cardinality
+ error = tokudb::set_card_in_status(status_db, txn, ta_rec_per_keys, ta_rec_per_key);
+ assert(error == 0);
+
+ error = tokudb::alter_card(status_db, txn, &ta, &tb);
+ assert(error == 0);
+
+ // verify
+ uint64_t current_rec_per_key[tb_rec_per_keys];
+ error = tokudb::get_card_from_status(status_db, txn, tb_rec_per_keys, current_rec_per_key);
+ assert(error == 0);
+ for (uint i = 0; i < tb_rec_per_keys; i++) {
+ assert(current_rec_per_key[i] == tb_rec_per_key[i]);
+ }
+
+ error = txn->commit(txn, 0);
+ assert(error == 0);
+
+ error = tokudb::close_status(&status_db);
+ assert(error == 0);
+}
+
+int main() {
+ int error;
+
+ error = system("rm -rf " __FILE__ ".testdir");
+ assert(error == 0);
+
+ error = mkdir(__FILE__ ".testdir", S_IRWXU+S_IRWXG+S_IRWXO);
+ assert(error == 0);
+
+ DB_ENV *env = NULL;
+ error = db_env_create(&env, 0);
+ assert(error == 0);
+
+ error = 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);
+ assert(error == 0);
+
+ test_no_keys(env);
+ test_keys(env);
+ test_drop_0(env);
+ test_drop_1(env);
+ test_drop_2(env);
+ test_drop_1_multiple_parts(env);
+ test_add_0(env);
+ test_add_1(env);
+ test_add_2(env);
+ test_add_0_multiple_parts(env);
+
+ error = env->close(env, 0);
+ assert(error == 0);
+
+ return 0;
+}
diff --git a/storage/tokudb/tests/card_test_key_info.cc b/storage/tokudb/tests/card_test_key_info.cc
new file mode 100644
index 00000000..97748def
--- /dev/null
+++ b/storage/tokudb/tests/card_test_key_info.cc
@@ -0,0 +1,146 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// test tokudb cardinality in status dictionary
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <memory.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <db.h>
+typedef unsigned long long ulonglong;
+#include <tokudb_status.h>
+#include <tokudb_buffer.h>
+
+#include "fake_mysql.h"
+
+#if __APPLE__
+typedef unsigned long ulong;
+#endif
+#include <tokudb_card.h>
+
+static void test_no_keys() {
+ TABLE_SHARE s = { 0, 0, 0, NULL };
+ TABLE t = { &s, NULL };
+ assert(tokudb::compute_total_key_parts(&s) == 0);
+ tokudb::set_card_in_key_info(&t, 0, NULL);
+}
+
+static void test_simple_pk() {
+ const uint keys = 1;
+ const uint key_parts = 1;
+ uint64_t pk_rec_per_key[keys] = { 0 };
+ KEY_INFO pk = { 0, key_parts, pk_rec_per_key, (char *) "PRIMARY" };
+ TABLE_SHARE s = { 0, keys, key_parts, &pk };
+ TABLE t = { &s, &pk };
+ assert(tokudb::compute_total_key_parts(&s) == key_parts);
+ uint64_t computed_rec_per_key[keys] = { 2 };
+ tokudb::set_card_in_key_info(&t, keys, computed_rec_per_key);
+ assert(t.key_info[0].rec_per_key[0] == 1);
+}
+
+static void test_pk_2() {
+ const uint keys = 1;
+ const uint key_parts = 2;
+ uint64_t pk_rec_per_key[keys * key_parts] = { 0 };
+ KEY_INFO pk = { 0, key_parts, pk_rec_per_key, (char *) "PRIMARY" };
+ TABLE_SHARE s = { 0, keys, key_parts, &pk };
+ TABLE t = { &s, &pk };
+ assert(tokudb::compute_total_key_parts(&s) == key_parts);
+ uint64_t computed_rec_per_key[keys * key_parts] = { 2, 3 };
+ tokudb::set_card_in_key_info(&t, keys * key_parts, computed_rec_per_key);
+ assert(t.key_info[0].rec_per_key[0] == 2);
+ assert(t.key_info[0].rec_per_key[1] == 1);
+}
+
+static void test_simple_sk() {
+ const uint keys = 1;
+ const uint key_parts = 1;
+ uint64_t sk_rec_per_key[keys] = { 0 };
+ KEY_INFO sk = { 0, keys, sk_rec_per_key, (char *) "KEY" };
+ TABLE_SHARE s = { MAX_KEY, keys, key_parts, &sk };
+ TABLE t = { &s, &sk };
+ assert(tokudb::compute_total_key_parts(&s) == 1);
+ uint64_t computed_rec_per_key[keys] = { 2 };
+ tokudb::set_card_in_key_info(&t, keys, computed_rec_per_key);
+ assert(t.key_info[0].rec_per_key[0] == 2);
+}
+
+static void test_simple_unique_sk() {
+ const uint keys = 1;
+ uint64_t sk_rec_per_key[keys] = { 0 };
+ KEY_INFO sk = { HA_NOSAME, keys, sk_rec_per_key, (char *) "KEY" };
+ TABLE_SHARE s = { MAX_KEY, keys, keys, &sk };
+ TABLE t = { &s, &sk };
+ assert(tokudb::compute_total_key_parts(&s) == 1);
+ uint64_t computed_rec_per_key[keys] = { 2 };
+ tokudb::set_card_in_key_info(&t, keys, computed_rec_per_key);
+ assert(t.key_info[0].rec_per_key[0] == 1);
+}
+
+static void test_simple_pk_sk() {
+ const uint keys = 2;
+ uint64_t rec_per_key[keys] = { 0 };
+ KEY_INFO key_info[keys] = {
+ { 0, 1, &rec_per_key[0], (char *) "PRIMARY" },
+ { 0, 1, &rec_per_key[1], (char *) "KEY" },
+ };
+ TABLE_SHARE s = { 0, keys, keys, key_info };
+ TABLE t = { &s, key_info };
+ assert(tokudb::compute_total_key_parts(&s) == 2);
+ uint64_t computed_rec_per_key[keys] = { 100, 200 };
+ tokudb::set_card_in_key_info(&t, keys, computed_rec_per_key);
+ assert(t.key_info[0].rec_per_key[0] == 1);
+ assert(t.key_info[1].rec_per_key[0] == 200);
+}
+
+static void test_simple_sk_pk() {
+ const uint keys = 2;
+ uint64_t rec_per_key[keys] = { 0 };
+ KEY_INFO key_info[keys] = {
+ { 0, 1, &rec_per_key[0], (char *) "KEY" },
+ { 0, 1, &rec_per_key[1], (char *) "PRIMARY" },
+ };
+ TABLE_SHARE s = { 1, keys, keys, key_info };
+ TABLE t = { &s, key_info };
+ assert(tokudb::compute_total_key_parts(&s) == 2);
+ uint64_t computed_rec_per_key[keys] = { 100, 200 };
+ tokudb::set_card_in_key_info(&t, keys, computed_rec_per_key);
+ assert(t.key_info[0].rec_per_key[0] == 100);
+ assert(t.key_info[1].rec_per_key[0] == 1);
+}
+
+int main() {
+ test_no_keys();
+ test_simple_pk();
+ test_pk_2();
+ test_simple_sk();
+ test_simple_unique_sk();
+ test_simple_pk_sk();
+ test_simple_sk_pk();
+ return 0;
+}
diff --git a/storage/tokudb/tests/fake_mysql.h b/storage/tokudb/tests/fake_mysql.h
new file mode 100644
index 00000000..f6a200d2
--- /dev/null
+++ b/storage/tokudb/tests/fake_mysql.h
@@ -0,0 +1,50 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// Provide some mimimal MySQL classes just to compile the tokudb cardinality functions
+class KEY_INFO {
+public:
+ uint flags;
+ uint key_parts;
+ uint64_t *rec_per_key;
+ char *name;
+};
+#define HA_NOSAME 1
+class TABLE_SHARE {
+public:
+ uint primary_key;
+ uint keys, key_parts;
+ KEY_INFO *key_info;
+};
+class TABLE {
+public:
+ TABLE_SHARE *s;
+ KEY_INFO *key_info;
+};
+uint get_key_parts(KEY_INFO *key_info) {
+ assert(key_info);
+ return key_info->key_parts;
+}
+#define MAX_KEY (1U << 30)
diff --git a/storage/tokudb/tests/math_test_int.cc b/storage/tokudb/tests/math_test_int.cc
new file mode 100644
index 00000000..3313bdf5
--- /dev/null
+++ b/storage/tokudb/tests/math_test_int.cc
@@ -0,0 +1,272 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <tokudb_math.h>
+using namespace tokudb;
+
+static int64_t sign_extend(uint length_bits, int64_t n) {
+ return n | ~((1ULL<<(length_bits-1))-1);
+}
+
+static void test_int_range(uint length_bits) {
+ assert(int_high_endpoint(length_bits) == (int64_t)((1ULL<<(length_bits-1))-1));
+ assert(int_low_endpoint(length_bits) == sign_extend(length_bits, 1ULL<<(length_bits-1)));
+}
+
+static void test_int8() {
+ printf("%s\n", __FUNCTION__);
+ test_int_range(8);
+ int64_t max = (1LL << 7);
+ for (int64_t x = -max; x <= max-1; x++) {
+ for (int64_t y = -max; y <= max-1; y++) {
+ bool over;
+ int64_t n, m;
+ n = int_add(x, y, 8, &over);
+ m = x + y;
+ if (m > max-1)
+ assert(over);
+ else if (m < -max)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == m);
+ }
+ n = int_sub(x, y, 8, &over);
+ m = x - y;
+ if (m > max-1)
+ assert(over);
+ else if (m < -max)
+ assert(over);
+ else {
+ assert(!over);
+ asset(n == m);
+ }
+ }
+ }
+}
+
+static void test_int16() {
+ printf("%s\n", __FUNCTION__);
+ test_int_range(16);
+ int64_t max = (1LL << 15);
+ for (int64_t x = -max; x <= max-1; x++) {
+ for (int64_t y = -max; y <= max-1; y++) {
+ bool over;
+ int64_t n, m;
+ n = int_add(x, y, 16, &over);
+ m = x + y;
+ if (m > max-1)
+ assert(over);
+ else if (m < -max)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == m);
+ }
+ n = int_sub(x, y, 16, &over);
+ m = x - y;
+ if (m > max-1)
+ assert(over);
+ else if (m < -max)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == m);
+ }
+ }
+ }
+}
+
+static void test_int24() {
+ printf("%s\n", __FUNCTION__);
+ test_int_range(24);
+ int64_t s;
+ bool over;
+
+ s = int_add(1, (1ULL<<23)-1, 24, &over); assert(over);
+ s = int_add((1ULL<<23)-1, 1, 24, &over); assert(over);
+ s = int_sub(-1, (1ULL<<23), 24, &over);
+ assert(!over);
+ assert(s == (1ULL<<23)-1);
+ s = int_sub((1ULL<<23), 1, 24, &over); assert(over);
+
+ s = int_add(0, 0, 24, &over);
+ assert(!over);
+ assert(s == 0);
+ s = int_sub(0, 0, 24, &over);
+ assert(!over);
+ assert(s == 0);
+ s = int_add(0, -1, 24, &over);
+ assert(!over);
+ assert(s == -1);
+ s = int_sub(0, 1, 24, &over);
+ assert(!over);
+ assert(s == -1);
+ s = int_add(0, (1ULL<<23), 24, &over);
+ assert(!over);
+ assert((s & ((1ULL<<24)-1)) == (1ULL<<23));
+ s = int_sub(0, (1ULL<<23)-1, 24, &over);
+ assert(!over);
+ assert((s & ((1ULL<<24)-1)) == (1ULL<<23)+1);
+
+ s = int_add(-1, 0, 24, &over);
+ assert(!over);
+ assert(s == -1);
+ s = int_add(-1, 1, 24, &over);
+ assert(!over);
+ assert(s == 0);
+ s = int_sub(-1, -1, 24, &over);
+ assert(!over);
+ assert(s == 0);
+ s = int_sub(-1, (1ULL<<23)-1, 24, &over);
+ assert(!over);
+ assert((s & ((1ULL<<24)-1)) == (1ULL<<23));
+}
+
+static void test_int32() {
+ printf("%s\n", __FUNCTION__);
+ test_int_range(32);
+ int64_t s;
+ bool over;
+
+ s = int_add(1, (1ULL<<31)-1, 32, &over); assert(over);
+ s = int_add((1ULL<<31)-1, 1, 32, &over); assert(over);
+ s = int_sub(-1, (1ULL<<31), 32, &over);
+ assert(s == (1ULL<<31)-1);
+ assert(!over);
+ s = int_sub((1ULL<<31), 1, 32, &over); assert(over);
+
+ s = int_add(0, 0, 32, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_sub(0, 0, 32, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_add(0, -1, 32, &over);
+ assert(s == -1);
+ assert(!over);
+ s = int_sub(0, 1, 32, &over);
+ assert(s == -1);
+ assert(!over);
+ s = int_add(0, (1ULL<<31), 32, &over);
+ assert((s & ((1ULL<<32)-1)) == (1ULL<<31));
+ assert(!over);
+ s = int_sub(0, (1ULL<<31)-1, 32, &over);
+ assert((s & ((1ULL<<32)-1)) == (1ULL<<31)+1);
+ assert(!over);
+
+ s = int_add(-1, 0, 32, &over);
+ assert(s == -1);
+ assert(!over);
+ s = int_add(-1, 1, 32, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_sub(-1, -1, 32, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_sub(-1, (1ULL<<31)-1, 32, &over);
+ assert((s & ((1ULL<<32)-1)) == (1ULL<<31));
+ assert(!over);
+}
+
+static void test_int64() {
+ printf("%s\n", __FUNCTION__);
+ test_int_range(64);
+ int64_t s;
+ bool over;
+
+ s = int_add(1, (1ULL<<63)-1, 64, &over); assert(over);
+ s = int_add((1ULL<<63)-1, 1, 64, &over); assert(over);
+ s = int_sub(-1, (1ULL<<63), 64, &over);
+ assert(s == (1ULL<<63)-1);
+ assert(!over);
+ s = int_sub((1ULL<<63), 1, 64, &over); assert(over);
+
+ s = int_add(0, 0, 64, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_sub(0, 0, 64, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_add(0, -1, 64, &over);
+ assert(s == -1);
+ assert(!over);
+ s = int_sub(0, 1, 64, &over);
+ assert(s == -1);
+ assert(!over);
+ s = int_add(0, (1ULL<<63), 64, &over);
+ assert(s == (int64_t)(1ULL<<63));
+ assert(!over);
+ s = int_sub(0, (1ULL<<63)-1, 64, &over);
+ assert(s == (int64_t)((1ULL<<63)+1));
+ assert(!over);
+
+ s = int_add(-1, 0, 64, &over);
+ assert(s == -1);
+ assert(!over);
+ s = int_add(-1, 1, 64, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_sub(-1, -1, 64, &over);
+ assert(s == 0);
+ assert(!over);
+ s = int_sub(-1, (1ULL<<63)-1, 64, &over);
+ assert(s == (int64_t)(1ULL<<63));
+ assert(!over);
+}
+
+static void test_int_sign(uint length_bits) {
+ printf("%s %u\n", __FUNCTION__, length_bits);
+ int64_t n;
+
+ n = int_high_endpoint(length_bits);
+ assert(int_sign_extend(n, length_bits) == n);
+ n = (1ULL<<(length_bits-1));
+ assert(int_sign_extend(n, length_bits) == -n);
+}
+
+static void test_int_sign() {
+ test_int_sign(8);
+ test_int_sign(16);
+ test_int_sign(24);
+ test_int_sign(32);
+ test_int_sign(64);
+}
+
+int main() {
+ test_int_sign();
+ test_int8();
+ test_int16();
+ test_int24();
+ test_int32();
+ test_int64();
+ return 0;
+}
+
diff --git a/storage/tokudb/tests/math_test_uint.cc b/storage/tokudb/tests/math_test_uint.cc
new file mode 100644
index 00000000..2c5c9261
--- /dev/null
+++ b/storage/tokudb/tests/math_test_uint.cc
@@ -0,0 +1,187 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <tokudb_math.h>
+using namespace tokudb;
+
+static void test_uint_range(uint length_bits) {
+ assert(uint_low_endpoint(length_bits) == 0);
+ if (length_bits == 64)
+ assert(uint_high_endpoint(length_bits) == ~0ULL);
+ else
+ assert(uint_high_endpoint(length_bits) == (1ULL<<length_bits)-1);
+}
+
+static void test_uint8() {
+ printf("%s\n", __FUNCTION__);
+ test_uint_range(8);
+ bool over;
+ uint8_t n;
+ uint64_t m;
+ for (uint64_t x = 0; x <= (1ULL<<8)-1; x++) {
+ for (uint64_t y = 0; y <= (1ULL<<8)-1; y++) {
+ n = uint_add(x, y, 8, &over);
+ m = x + y;
+ if (m > (1ULL<<8)-1)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == (m % 256));
+ }
+ n = uint_sub(x, y, 8, &over);
+ m = x - y;
+ if (m > x)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == (m % 256));
+ }
+ }
+ }
+}
+
+static void test_uint16() {
+ printf("%s\n", __FUNCTION__);
+ test_uint_range(16);
+ bool over;
+ uint16_t n;
+ uint64_t m;
+ for (uint64_t x = 0; x <= (1ULL<<16)-1; x++) {
+ for (uint64_t y = 0; y <= (1ULL<<16)-1; y++) {
+ n = uint_add(x, y, 16, &over);
+ m = x + y;
+ if (m > (1ULL<<16)-1)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == (m % (1ULL<<16)));
+ }
+ n = uint_sub(x, y, 16, &over);
+ m = x - y;
+ if (m > x)
+ assert(over);
+ else {
+ assert(!over);
+ assert(n == (m % (1ULL<<16)));
+ }
+ }
+ }
+}
+
+static void test_uint24() {
+ printf("%s\n", __FUNCTION__);
+ test_uint_range(24);
+ bool over;
+ uint64_t s;
+
+ s = uint_add((1ULL<<24)-1, (1ULL<<24)-1, 24, &over); assert(over);
+ s = uint_add((1ULL<<24)-1, 1, 24, &over); assert(over);
+ s = uint_add((1ULL<<24)-1, 0, 24, &over);
+ assert(!over);
+ assert(s == (1ULL<<24)-1);
+ s = uint_add(0, 1, 24, &over);
+ assert(!over);
+ assert(s == 1);
+ s = uint_add(0, 0, 24, &over);
+ assert(!over);
+ assert(s == 0);
+ s = uint_sub(0, 0, 24, &over);
+ assert(!over);
+ assert(s == 0);
+ s = uint_sub(0, 1, 24, &over); assert(over);
+ s = uint_sub(0, (1ULL<<24)-1, 24, &over); assert(over);
+ s = uint_sub((1ULL<<24)-1, (1ULL<<24)-1, 24, &over);
+ assert(!over);
+ assert(s == 0);
+}
+
+static void test_uint32() {
+ printf("%s\n", __FUNCTION__);
+ test_uint_range(32);
+ bool over;
+ uint64_t s;
+
+ s = uint_add((1ULL<<32)-1, (1ULL<<32)-1, 32, &over); assert(over);
+ s = uint_add((1ULL<<32)-1, 1, 32, &over); assert(over);
+ s = uint_add((1ULL<<32)-1, 0, 32, &over);
+ assert(!over);
+ assert(s == (1ULL<<32)-1);
+ s = uint_add(0, 1, 32, &over);
+ assert(!over);
+ assert(s == 1);
+ s = uint_add(0, 0, 32, &over);
+ assert(!over);
+ assert(s == 0);
+ s = uint_sub(0, 0, 32, &over);
+ assert(!over);
+ assert(s == 0);
+ s = uint_sub(0, 1, 32, &over); assert(over);
+ s = uint_sub(0, (1ULL<<32)-1, 32, &over); assert(over);
+ s = uint_sub((1ULL<<32)-1, (1ULL<<32)-1, 32, &over);
+ assert(!over);
+ assert(s == 0);
+}
+
+static void test_uint64() {
+ printf("%s\n", __FUNCTION__);
+ test_uint_range(64);
+ bool over;
+ uint64_t s;
+
+ s = uint_add(~0ULL, ~0ULL, 64, &over); assert(over);
+ s = uint_add(~0ULL, 1, 64, &over); assert(over);
+ s = uint_add(~0ULL, 0, 64, &over);
+ assert(!over);
+ assert(s == ~0ULL);
+ s = uint_add(0, 1, 64, &over);
+ assert(!over);
+ assert(s == 1);
+ s = uint_add(0, 0, 64, &over);
+ assert(!over);
+ assert(s == 0);
+ s = uint_sub(0, 0, 64, &over);
+ assert(!over);
+ assert(s == 0);
+ s = uint_sub(0, 1, 64, &over); assert(over);
+ s = uint_sub(0, ~0ULL, 64, &over); assert(over);
+ s = uint_sub(~0ULL, ~0ULL, 64, &over);
+ assert(!over);
+ assert(s == 0);
+}
+
+int main() {
+ test_uint8();
+ test_uint16();
+ test_uint24();
+ test_uint32();
+ test_uint64();
+ return 0;
+}
+
diff --git a/storage/tokudb/tests/max_test.cc b/storage/tokudb/tests/max_test.cc
new file mode 100644
index 00000000..9528111b
--- /dev/null
+++ b/storage/tokudb/tests/max_test.cc
@@ -0,0 +1,47 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+// test explicit generation of a simple template function
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <assert.h>
+
+template <class T> T my_max(T a, T b) {
+ return a > b ? a : b;
+}
+
+template int my_max(int a, int b);
+
+int main(int argc, char *argv[]) {
+ assert(argc == 3);
+ int a = atoi(argv[1]);
+ int b = atoi(argv[2]);
+ int m = my_max<int>(a, b);
+ printf("%d %d %d\n", a, b, m);
+ assert(m == (a > b ? a : b));
+ return 0;
+}
diff --git a/storage/tokudb/tests/sint_test.cc b/storage/tokudb/tests/sint_test.cc
new file mode 100644
index 00000000..7823ee5a
--- /dev/null
+++ b/storage/tokudb/tests/sint_test.cc
@@ -0,0 +1,53 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <tokudb_math.h>
+using namespace tokudb;
+
+static void test(int length_bits) {
+ int64_t max = (1ULL << (length_bits-1)) - 1;
+ for (int64_t x = -max-1; x <= max; x++) {
+ for (int64_t y = -max-1; y <= max; y++) {
+ bool over;
+ int64_t n = int_add(x, y, length_bits, &over);
+ printf("%"PRId64" %"PRId64" %"PRId64" %u\n", x, y, n, over);
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc > 1) {
+ for (int i = 1; i < argc; i++) {
+ test(atoi(argv[i]));
+ }
+ }
+ return 0;
+}
diff --git a/storage/tokudb/tests/tokudb_buffer_test.cc b/storage/tokudb/tests/tokudb_buffer_test.cc
new file mode 100644
index 00000000..7e296790
--- /dev/null
+++ b/storage/tokudb/tests/tokudb_buffer_test.cc
@@ -0,0 +1,234 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdint.h>
+#include <tokudb_buffer.h>
+
+static void test_null() {
+ tokudb::buffer b;
+ assert(b.data() == nullptr);
+ assert(b.size() == 0);
+ assert(b.limit() == 0);
+ b.append(NULL, 0);
+ assert(b.data() == nullptr);
+ assert(b.size() == 0);
+ assert(b.limit() == 0);
+}
+
+static void append_az(tokudb::buffer &b) {
+ for (char c = 'a'; c <= 'z'; c++) {
+ b.append(&c, sizeof c);
+ }
+}
+
+static void assert_az(tokudb::buffer &b) {
+ unsigned char *bp = NULL;
+ for (size_t i = 0; i < b.size(); i++) {
+ bp = (unsigned char *) b.data() + i;
+ assert(*bp == 'a'+i);
+ }
+ assert(*bp == 'z');
+}
+
+static void assert_AZ(tokudb::buffer &b) {
+ unsigned char *bp = NULL;
+ for (size_t i = 0; i < b.size(); i++) {
+ bp = (unsigned char *) b.data() + i;
+ assert(*bp == 'A'+i);
+ }
+ assert(*bp == 'Z');
+}
+
+static void test_append() {
+ tokudb::buffer a;
+
+ a.append(NULL, 0);
+ append_az(a);
+ a.append(NULL, 0);
+ assert(a.size() == 'z'-'a'+1);
+ assert(a.size() <= a.limit());
+ assert_az(a);
+
+ tokudb::buffer b(a.data(), 0, a.size());
+ for (size_t i = 0; i < b.limit(); i++) {
+ assert(i <= a.size());
+ char *ap = (char *) a.data() + i;
+ assert(i <= b.limit());
+ char *bp = (char *) b.data() + i;
+ assert(*ap == *bp);
+ }
+}
+
+static void test_consume() {
+ tokudb::buffer a;
+ append_az(a);
+ tokudb::buffer b(a.data(), 0, a.size());
+ for (size_t i = 0; i < b.limit(); i++) {
+ unsigned char c;
+ b.consume(&c, 1);
+ assert(c == 'a'+i);
+ }
+ assert(b.size() == b.limit());
+}
+
+static void test_consume_ptr() {
+ tokudb::buffer a;
+ append_az(a);
+ tokudb::buffer b(a.data(), 0, a.size());
+ for (size_t i = 0; i < b.limit(); i++) {
+ void *p = b.consume_ptr(1);
+ unsigned char c = *(unsigned char *)p;
+ assert(c == 'a'+i);
+ }
+ assert(b.size() == b.limit());
+ assert(b.consume_ptr(1) == NULL);
+}
+
+static void test_replace() {
+ tokudb::buffer a;
+ append_az(a);
+ assert_az(a);
+ for (size_t i = 0; i < a.size(); i++) {
+ unsigned char newc[1] = { (unsigned char)('A' + i) };
+ a.replace(i, 1, newc, 1);
+ }
+ assert_AZ(a);
+}
+
+static void test_replace_grow() {
+ tokudb::buffer a;
+ append_az(a);
+ assert_az(a);
+
+ // grow field
+ size_t orig_s = a.size();
+ for (size_t i = 0; i < orig_s; i++) {
+ unsigned char newc[2] = { (unsigned char)('a'+i), (unsigned char)('a'+i) };
+ size_t old_s = a.size();
+ a.replace(2*i, 1, newc, 2);
+ assert(a.size() == old_s+1);
+ }
+ for (size_t i = 0; i < a.size()/2; i++) {
+ unsigned char *cp = (unsigned char *) a.data() + 2*i;
+ assert(cp[0] == 'a'+i);
+ assert(cp[1] == 'a'+i);
+ }
+}
+
+static void test_replace_shrink() {
+ tokudb::buffer a;
+ for (char c = 'a'; c <= 'z'; c++) {
+ a.append(&c, sizeof c);
+ a.append(&c, sizeof c);
+ }
+
+ // shrink field
+ for (size_t i = 0; i < a.size(); i++) {
+ unsigned char newc[1] = { (unsigned char)('a'+i) };
+ size_t s = a.size();
+ a.replace(i, 2, newc, 1);
+ assert(a.size() == s-1);
+ }
+ assert_az(a);
+}
+
+static void test_replace_null() {
+ tokudb::buffer a;
+ append_az(a);
+ assert_az(a);
+
+ // insert between all
+ size_t n = a.size();
+ for (size_t i = 0; i < n; i++) {
+ unsigned char newc[1] = { (unsigned char)('a'+i) };
+ a.replace(2*i, 0, newc, 1);
+ }
+
+ a.replace(a.size(), 0, (void *)"!", 1);
+ a.append((void *)"?", 1);
+}
+
+namespace tokudb {
+ template size_t vlq_encode_ui(uint8_t, void *, size_t);
+ template size_t vlq_decode_ui(uint8_t *, void *, size_t);
+ template size_t vlq_encode_ui(uint32_t, void *, size_t);
+ template size_t vlq_decode_ui(uint32_t *, void *, size_t);
+};
+
+static void test_ui8() {
+ tokudb::buffer a;
+ for (uint8_t n = 0; ; n++) {
+ assert(a.append_ui<uint8_t>(n) != 0);
+ if (n == 255)
+ break;
+ }
+ tokudb::buffer b(a.data(), 0, a.size());
+ for (uint8_t n = 0; ; n++) {
+ uint8_t v;
+ if (b.consume_ui<uint8_t>(&v) == 0)
+ break;
+ assert(v == n);
+ if (n == 255)
+ break;
+ }
+ assert(b.size() == b.limit());
+}
+
+static void test_ui32() {
+ tokudb::buffer a;
+ for (uint32_t n = 0; ; n++) {
+ assert(a.append_ui<uint32_t>(n) != 0);
+ if (n == 1<<22)
+ break;
+ }
+ tokudb::buffer b(a.data(), 0, a.size());
+ for (uint32_t n = 0; ; n++) {
+ uint32_t v;
+ if (b.consume_ui<uint32_t>(&v) == 0)
+ break;
+ assert(v == n);
+ if (n == 1<<22)
+ break;
+ }
+ assert(b.size() == b.limit());
+}
+
+int main() {
+ test_null();
+ test_append();
+ test_consume();
+ test_consume_ptr();
+ test_replace();
+ test_replace_grow();
+ test_replace_shrink();
+ test_replace_null();
+ test_ui8();
+ test_ui32();
+ return 0;
+}
diff --git a/storage/tokudb/tests/uint_test.cc b/storage/tokudb/tests/uint_test.cc
new file mode 100644
index 00000000..e3aa1a6f
--- /dev/null
+++ b/storage/tokudb/tests/uint_test.cc
@@ -0,0 +1,54 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <tokudb_math.h>
+using namespace tokudb;
+
+static void test(int length_bits) {
+ printf("%s %d\n", __FUNCTION__, length_bits);
+ uint64_t max = (1ULL << length_bits) - 1;
+ for (uint64_t x = 0; x <= max; x++) {
+ for (uint64_t y = 0; y <= max; y++) {
+ bool over;
+ uint64_t n = uint_add(x, y, max, &over);
+ printf("%"PRIu64" %"PRIu64" %"PRIu64"\n", x, y, n);
+ }
+ }
+}
+
+int main(int argc, char *argv[]) {
+ if (argc > 1) {
+ for (int i = 1; i < argc; i++) {
+ test(atoi(argv[i]));
+ }
+ }
+ return 0;
+}
diff --git a/storage/tokudb/tests/vlq_test.cc b/storage/tokudb/tests/vlq_test.cc
new file mode 100644
index 00000000..12b222f0
--- /dev/null
+++ b/storage/tokudb/tests/vlq_test.cc
@@ -0,0 +1,88 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <tokudb_vlq.h>
+
+namespace tokudb {
+ template size_t vlq_encode_ui(uint32_t n, void *p, size_t s);
+ template size_t vlq_decode_ui(uint32_t *np, void *p, size_t s);
+ template size_t vlq_encode_ui(uint64_t n, void *p, size_t s);
+ template size_t vlq_decode_ui(uint64_t *np, void *p, size_t s);
+};
+
+static void test_vlq_uint32_error(void) {
+ uint32_t n;
+ unsigned char b[5];
+ size_t out_s, in_s;
+
+ out_s = tokudb::vlq_encode_ui<uint32_t>(128, b, 0);
+ assert(out_s == 0);
+ out_s = tokudb::vlq_encode_ui<uint32_t>(128, b, 1);
+ assert(out_s == 0);
+ out_s = tokudb::vlq_encode_ui<uint32_t>(128, b, 2);
+ assert(out_s == 2);
+ in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, 0);
+ assert(in_s == 0);
+ in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, 1);
+ assert(in_s == 0);
+ in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, 2);
+ assert(in_s == 2);
+ assert(n == 128);
+}
+
+static void test_80000000(void) {
+ uint64_t n;
+ unsigned char b[10];
+ size_t out_s, in_s;
+ uint64_t v = 0x80000000;
+ out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 5);
+ in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 5);
+ assert(n == v);
+}
+
+static void test_100000000(void) {
+ uint64_t n;
+ unsigned char b[10];
+ size_t out_s, in_s;
+ uint64_t v = 0x100000000;
+ out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 5);
+ in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 5);
+ assert(n == v);
+}
+
+int main(void) {
+ test_vlq_uint32_error();
+ test_80000000();
+ test_100000000();
+ return 0;
+}
diff --git a/storage/tokudb/tests/vlq_test_uint32.cc b/storage/tokudb/tests/vlq_test_uint32.cc
new file mode 100644
index 00000000..3cc8af77
--- /dev/null
+++ b/storage/tokudb/tests/vlq_test_uint32.cc
@@ -0,0 +1,99 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <tokudb_vlq.h>
+
+namespace tokudb {
+ template size_t vlq_encode_ui(uint32_t n, void *p, size_t s);
+ template size_t vlq_decode_ui(uint32_t *np, void *p, size_t s);
+ template size_t vlq_encode_ui(uint64_t n, void *p, size_t s);
+ template size_t vlq_decode_ui(uint64_t *np, void *p, size_t s);
+};
+
+static void test_vlq_uint32(void) {
+ printf("%u\n", 0);
+ for (uint32_t v = 0; v < (1<<7); v++) {
+ unsigned char b[5];
+ size_t out_s = tokudb::vlq_encode_ui<uint32_t>(v, b, sizeof b);
+ assert(out_s == 1);
+ uint32_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, out_s);
+ assert(in_s == 1);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<7);
+ for (uint32_t v = (1<<7); v < (1<<14); v++) {
+ unsigned char b[5];
+ size_t out_s = tokudb::vlq_encode_ui<uint32_t>(v, b, sizeof b);
+ assert(out_s == 2);
+ uint32_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, out_s);
+ assert(in_s == 2);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<14);
+ for (uint32_t v = (1<<14); v < (1<<21); v++) {
+ unsigned char b[5];
+ size_t out_s = tokudb::vlq_encode_ui<uint32_t>(v, b, sizeof b);
+ assert(out_s == 3);
+ uint32_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, out_s);
+ assert(in_s == 3);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<21);
+ for (uint32_t v = (1<<21); v < (1<<28); v++) {
+ unsigned char b[5];
+ size_t out_s = tokudb::vlq_encode_ui<uint32_t>(v, b, sizeof b);
+ assert(out_s == 4);
+ uint32_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, out_s);
+ assert(in_s == 4);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<28);
+ for (uint32_t v = (1<<28); v != 0; v++) {
+ unsigned char b[5];
+ size_t out_s = tokudb::vlq_encode_ui<uint32_t>(v, b, sizeof b);
+ assert(out_s == 5);
+ uint32_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint32_t>(&n, b, out_s);
+ assert(in_s == 5);
+ assert(n == v);
+ }
+}
+
+int main(void) {
+ test_vlq_uint32();
+ return 0;
+}
diff --git a/storage/tokudb/tests/vlq_test_uint64.cc b/storage/tokudb/tests/vlq_test_uint64.cc
new file mode 100644
index 00000000..697c5977
--- /dev/null
+++ b/storage/tokudb/tests/vlq_test_uint64.cc
@@ -0,0 +1,110 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
+#ident "$Id$"
+/*======
+This file is part of TokuDB
+
+
+Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
+
+ TokuDBis is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License, version 2,
+ as published by the Free Software Foundation.
+
+ TokuDB is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TokuDB. If not, see <http://www.gnu.org/licenses/>.
+
+======= */
+
+#ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <tokudb_vlq.h>
+
+namespace tokudb {
+ template size_t vlq_encode_ui(uint32_t n, void *p, size_t s);
+ template size_t vlq_decode_ui(uint32_t *np, void *p, size_t s);
+ template size_t vlq_encode_ui(uint64_t n, void *p, size_t s);
+ template size_t vlq_decode_ui(uint64_t *np, void *p, size_t s);
+};
+
+// test a slice of the number space where the slice is described by
+// a start number and a stride through the space.
+static void test_vlq_uint64(uint64_t start, uint64_t stride) {
+ printf("%u\n", 0);
+ for (uint64_t v = 0 + start; v < (1<<7); v += stride) {
+ unsigned char b[10];
+ size_t out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 1);
+ uint64_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 1);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<7);
+ for (uint64_t v = (1<<7) + start; v < (1<<14); v += stride) {
+ unsigned char b[10];
+ size_t out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 2);
+ uint64_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 2);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<14);
+ for (uint64_t v = (1<<14) + start; v < (1<<21); v += stride) {
+ unsigned char b[10];
+ size_t out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 3);
+ uint64_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 3);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<21);
+ for (uint64_t v = (1<<21) + start; v < (1<<28); v += stride) {
+ unsigned char b[10];
+ size_t out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 4);
+ uint64_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 4);
+ assert(n == v);
+ }
+
+ printf("%u\n", 1<<28);
+#if USE_OPENMP
+#pragma omp parallel num_threads(4)
+#pragma omp for
+#endif
+ for (uint64_t v = (1<<28) + start; v < (1ULL<<35); v += stride) {
+ unsigned char b[10];
+ size_t out_s = tokudb::vlq_encode_ui<uint64_t>(v, b, sizeof b);
+ assert(out_s == 5);
+ uint64_t n;
+ size_t in_s = tokudb::vlq_decode_ui<uint64_t>(&n, b, out_s);
+ assert(in_s == 5);
+ assert(n == v);
+ }
+}
+
+int main(int argc, char *argv[]) {
+ uint64_t start = 0, stride = 1;
+ if (argc == 3) {
+ start = atoll(argv[1]);
+ stride = atoll(argv[2]);
+ }
+ test_vlq_uint64(start, stride);
+ return 0;
+}