Squashed 'src/nudb/' content from commit 00adc6a

git-subtree-dir: src/nudb
git-subtree-split: 00adc6a4f16679a376f40c967f77dfa544c179c1
This commit is contained in:
Vinnie Falco
2016-09-29 19:24:12 -04:00
commit 79159ffd87
113 changed files with 15806 additions and 0 deletions

38
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,38 @@
# Part of nudb
GroupSources(test "/")
GroupSources(include/nudb nudb)
GroupSources(extras/nudb extras)
GroupSources(extras/beast/include/beast beast)
GroupSources(extras/beast/extras/beast beast)
add_executable(test-all
${EXTRAS_INCLUDES}
${NUDB_INCLUDES}
${BEAST_INCLUDES}
../extras/beast/extras/beast/unit_test/main.cpp
basic_store.cpp
buffer.cpp
callgrind_test.cpp
concepts.cpp
create.cpp
error.cpp
file.cpp
native_file.cpp
posix_file.cpp
recover.cpp
rekey.cpp
store.cpp
type_traits.cpp
verify.cpp
version.cpp
visit.cpp
win32_file.cpp
xxhasher.cpp
)
if (WIN32)
target_link_libraries(test-all ${Boost_LIBRARIES})
else ()
target_link_libraries(test-all ${Boost_LIBRARIES} rt Threads::Threads)
endif ()

30
test/Jamfile Normal file
View File

@@ -0,0 +1,30 @@
#
# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
import os ;
unit-test test-all :
../extras/beast/extras/beast/unit_test/main.cpp
basic_store.cpp
buffer.cpp
callgrind_test.cpp
concepts.cpp
create.cpp
error.cpp
file.cpp
native_file.cpp
posix_file.cpp
recover.cpp
rekey.cpp
store.cpp
type_traits.cpp
verify.cpp
version.cpp
visit.cpp
win32_file.cpp
xxhasher.cpp
;

250
test/basic_store.cpp Normal file
View File

@@ -0,0 +1,250 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/basic_store.hpp>
#include <nudb/test/test_store.hpp>
#include <nudb/detail/arena.hpp>
#include <nudb/detail/cache.hpp>
#include <nudb/detail/pool.hpp>
#include <nudb/progress.hpp>
#include <nudb/verify.hpp>
#include <beast/unit_test/suite.hpp>
#include <limits>
#include <type_traits>
namespace nudb {
namespace detail {
static_assert(!std::is_copy_constructible <arena>{}, "");
static_assert(!std::is_copy_assignable <arena>{}, "");
static_assert( std::is_move_constructible <arena>{}, "");
static_assert(!std::is_move_assignable <arena>{}, "");
static_assert(!std::is_copy_constructible <cache>{}, "");
static_assert(!std::is_copy_assignable <cache>{}, "");
static_assert( std::is_move_constructible <cache>{}, "");
static_assert(!std::is_move_assignable <cache>{}, "");
static_assert(!std::is_copy_constructible <pool>{}, "");
static_assert(!std::is_copy_assignable <pool>{}, "");
static_assert( std::is_move_constructible <pool>{}, "");
static_assert(!std::is_move_assignable <pool>{}, "");
} // detail
namespace test {
class basic_store_test : public beast::unit_test::suite
{
public:
void
test_members()
{
std::size_t const keySize = 4;
std::size_t const blockSize = 4096;
float loadFactor = 0.5f;
error_code ec;
test_store ts{keySize, blockSize, loadFactor};
// Files not found
ts.open(ec);
if(! BEAST_EXPECTS(ec ==
errc::no_such_file_or_directory, ec.message()))
return;
ec = {};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
BEAST_EXPECT(ts.db.dat_path() == ts.dp);
BEAST_EXPECT(ts.db.key_path() == ts.kp);
BEAST_EXPECT(ts.db.log_path() == ts.lp);
BEAST_EXPECT(ts.db.appnum() == ts.appnum);
BEAST_EXPECT(ts.db.key_size() == ts.keySize);
BEAST_EXPECT(ts.db.block_size() == ts.blockSize);
}
// Inserts a bunch of values then fetches them
void
do_insert_fetch(
std::size_t N,
std::size_t keySize,
std::size_t blockSize,
float loadFactor,
bool sleep)
{
testcase <<
"N=" << N << ", "
"keySize=" << keySize << ", "
"blockSize=" << blockSize;
error_code ec;
test_store ts{keySize, blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Insert
for(std::size_t n = 0; n < N; ++n)
{
auto const item = ts[n];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
// Fetch
for(std::size_t n = 0; n < N; ++n)
{
auto const item = ts[n];
ts.db.fetch(item.key,
[&](void const* data, std::size_t size)
{
if(! BEAST_EXPECT(size == item.size))
return;
BEAST_EXPECT(
std::memcmp(data, item.data, size) == 0);
}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
// Insert Duplicate
for(std::size_t n = 0; n < N; ++n)
{
auto const item = ts[n];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(
ec == error::key_exists, ec.message()))
return;
ec = {};
}
// Insert and Fetch
if(keySize > 1)
{
for(std::size_t n = 0; n < N; ++n)
{
auto item = ts[n];
ts.db.fetch(item.key,
[&](void const* data, std::size_t size)
{
if(! BEAST_EXPECT(size == item.size))
return;
BEAST_EXPECT(
std::memcmp(data, item.data, size) == 0);
}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
item = ts[N + n];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.db.fetch(item.key,
[&](void const* data, std::size_t size)
{
if(! BEAST_EXPECT(size == item.size))
return;
BEAST_EXPECT(
std::memcmp(data, item.data, size) == 0);
}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
}
if(sleep)
{
// Make sure we run periodic activity
std::this_thread::sleep_for(
std::chrono::milliseconds{3000});
}
ts.close(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
// Perform insert/fetch test across a range of parameters
void
test_insert_fetch()
{
for(auto const keySize : {
1, 2, 3, 31, 32, 33, 63, 64, 65, 95, 96, 97 })
{
std::size_t N;
std::size_t constexpr blockSize = 4096;
float loadFactor = 0.95f;
switch(keySize)
{
case 1: N = 10; break;
case 2: N = 100; break;
case 3: N = 250; break;
default:
N = 5000;
break;
};
do_insert_fetch(N, keySize, blockSize, loadFactor,
keySize == 97);
}
}
void
test_bulk_insert(std::size_t N, std::size_t keySize,
std::size_t blockSize, float loadFactor)
{
testcase <<
"bulk_insert N=" << N << ", "
"keySize=" << keySize << ", "
"blockSize=" << blockSize;
error_code ec;
test_store ts{keySize, blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Insert
for(std::size_t n = 0; n < N; ++n)
{
auto const item = ts[n];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
ts.close(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
verify_info info;
verify<xxhasher>(info, ts.dp, ts.kp,
64 * 1024 * 1024 , no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
log << info;
}
void
run() override
{
#if 1
test_members();
test_insert_fetch();
#else
// bulk-insert performance test
test_bulk_insert(10000000, 8, 4096, 0.5f);
#endif
}
};
BEAST_DEFINE_TESTSUITE(basic_store, test, nudb);
} // test
} // nudb

77
test/buffer.cpp Normal file
View File

@@ -0,0 +1,77 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/detail/buffer.hpp>
#include <beast/unit_test/suite.hpp>
#include <type_traits>
namespace nudb {
namespace test {
class buffer_test : public beast::unit_test::suite
{
public:
void
run()
{
using buffer = nudb::detail::buffer;
static_assert(std::is_default_constructible<buffer>::value, "");
#if 0
static_assert(std::is_copy_constructible<buffer>::value, "");
static_assert(std::is_copy_assignable<buffer>::value, "");
#else
static_assert(! std::is_copy_constructible<buffer>::value, "");
static_assert(! std::is_copy_assignable<buffer>::value, "");
#endif
static_assert(std::is_move_constructible<buffer>::value, "");
static_assert(std::is_move_assignable<buffer>::value, "");
{
buffer b;
}
{
buffer b1(1024);
BEAST_EXPECT(b1.size() == 1024);
buffer b2(std::move(b1));
BEAST_EXPECT(b1.size() == 0);
BEAST_EXPECT(b2.size() == 1024);
}
{
buffer b1(1024);
BEAST_EXPECT(b1.size() == 1024);
buffer b2;
b2 = std::move(b1);
BEAST_EXPECT(b1.size() == 0);
BEAST_EXPECT(b2.size() == 1024);
}
#if 0
{
buffer b1(1024);
BEAST_EXPECT(b1.size() == 1024);
buffer b2(b1);
BEAST_EXPECT(b1.size() == 1024);
BEAST_EXPECT(b2.size() == 1024);
}
{
buffer b1(1024);
BEAST_EXPECT(b1.size() == 1024);
buffer b2;
b2 = b1;
BEAST_EXPECT(b1.size() == 1024);
BEAST_EXPECT(b2.size() == 1024);
}
#endif
}
};
BEAST_DEFINE_TESTSUITE(buffer, test, nudb);
} // test
} // nudb

92
test/callgrind_test.cpp Normal file
View File

@@ -0,0 +1,92 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <nudb/test/test_store.hpp>
#include <beast/unit_test/suite.hpp>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <memory>
#include <utility>
namespace nudb {
namespace test {
// This test is designed for callgrind runs to find hotspots
class callgrind_test : public beast::unit_test::suite
{
public:
// Creates and opens a database, performs a bunch
// of inserts, then alternates fetching all the keys
// with keys not present.
//
void
testCallgrind(std::size_t N)
{
using key_type = std::uint64_t;
std::size_t const blockSize = 4096;
float const loadFactor = 0.5;
error_code ec;
test_store ts{sizeof(key_type), blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
for(std::size_t i = 0; i < N; ++i)
{
auto const item = ts[i];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
Buffer b;
for(std::size_t i = 0; i < N * 2; ++i)
{
if(! (i%2))
{
auto const item = ts[i/2];
ts.db.fetch(item.key, b, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
if(! BEAST_EXPECT(b.size() == item.size))
return;
if(! BEAST_EXPECT(std::memcmp(b.data(),
item.data, item.size) == 0))
return;
}
else
{
auto const item = ts[N + i/2];
ts.db.fetch(item.key, b, ec);
if(! BEAST_EXPECTS(ec ==
error::key_not_found, ec.message()))
return;
ec = {};
}
}
ts.close(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
void run()
{
// higher numbers, more pain
std::size_t constexpr N = 100000;
testCallgrind(N);
}
};
BEAST_DEFINE_TESTSUITE(callgrind, test, nudb);
} // test
} // nudb

9
test/concepts.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/concepts.hpp>

49
test/create.cpp Normal file
View File

@@ -0,0 +1,49 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/create.hpp>
#include <nudb/test/test_store.hpp>
#include <nudb/create.hpp>
#include <beast/unit_test/suite.hpp>
namespace nudb {
namespace test {
class create_test : public beast::unit_test::suite
{
public:
void
test_create()
{
std::size_t const keySize = 8;
std::size_t const blockSize = 256;
float const loadFactor = 0.5f;
error_code ec;
test_store ts{keySize, blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.create(ec);
if(! BEAST_EXPECTS(
ec == errc::file_exists, ec.message()))
return;
}
void
run() override
{
test_create();
}
};
BEAST_DEFINE_TESTSUITE(create, test, nudb);
} // test
} // nudb

83
test/error.cpp Normal file
View File

@@ -0,0 +1,83 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/error.hpp>
#include <beast/unit_test/suite.hpp>
namespace nudb {
namespace test {
class error_test : public beast::unit_test::suite
{
public:
void check(char const* name, error ev)
{
auto const ec = make_error_code(ev);
BEAST_EXPECT(std::string{ec.category().name()} == name);
BEAST_EXPECT(! ec.message().empty());
BEAST_EXPECT(std::addressof(ec.category()) ==
std::addressof(nudb_category()));
BEAST_EXPECT(nudb_category().equivalent(static_cast<int>(ev),
ec.category().default_error_condition(static_cast<int>(ev))));
BEAST_EXPECT(nudb_category().equivalent(
ec, static_cast<int>(ev)));
}
void run() override
{
nudb_category().message(0);
nudb_category().message(99999);
check("nudb", error::success);
check("nudb", error::key_not_found);
check("nudb", error::key_exists);
check("nudb", error::short_read);
check("nudb", error::log_file_exists);
check("nudb", error::no_key_file);
check("nudb", error::too_many_buckets);
check("nudb", error::not_data_file);
check("nudb", error::not_key_file);
check("nudb", error::not_log_file);
check("nudb", error::different_version);
check("nudb", error::invalid_key_size);
check("nudb", error::invalid_block_size);
check("nudb", error::short_key_file);
check("nudb", error::short_bucket);
check("nudb", error::short_spill);
check("nudb", error::short_data_record);
check("nudb", error::short_value);
check("nudb", error::hash_mismatch);
check("nudb", error::invalid_load_factor);
check("nudb", error::invalid_capacity);
check("nudb", error::invalid_bucket_count);
check("nudb", error::invalid_bucket_size);
check("nudb", error::incomplete_data_file_header);
check("nudb", error::incomplete_key_file_header);
check("nudb", error::invalid_log_record);
check("nudb", error::invalid_log_spill);
check("nudb", error::invalid_log_offset);
check("nudb", error::invalid_log_index);
check("nudb", error::invalid_spill_size);
check("nudb", error::uid_mismatch);
check("nudb", error::appnum_mismatch);
check("nudb", error::key_size_mismatch);
check("nudb", error::salt_mismatch);
check("nudb", error::pepper_mismatch);
check("nudb", error::block_size_mismatch);
check("nudb", error::orphaned_value);
check("nudb", error::missing_value);
check("nudb", error::size_mismatch);
check("nudb", error::duplicate_value);
}
};
BEAST_DEFINE_TESTSUITE(error, test, nudb);
} // test
} // nudb

9
test/file.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/file.hpp>

9
test/native_file.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/native_file.hpp>

9
test/posix_file.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/posix_file.hpp>

191
test/recover.cpp Normal file
View File

@@ -0,0 +1,191 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/recover.hpp>
#include <nudb/test/fail_file.hpp>
#include <nudb/test/test_store.hpp>
#include <nudb/progress.hpp>
#include <beast/unit_test/suite.hpp>
#include <cmath>
#include <cstring>
#include <memory>
#include <random>
#include <utility>
namespace nudb {
namespace test {
class basic_recover_test : public beast::unit_test::suite
{
public:
using key_type = std::uint32_t;
void
test_ok()
{
std::size_t const keySize = 8;
std::size_t const blockSize = 256;
float const loadFactor = 0.5f;
error_code ec;
test_store ts{keySize, blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
recover<xxhasher>(ts.dp, ts.kp, ts.lp, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
// Creates and opens a database, performs a bunch
// of inserts, then fetches all of them to make sure
// they are there. Uses a fail_file that causes the n-th
// I/O to fail, causing an exception.
void
do_work(
test_store& ts,
std::size_t N,
fail_counter& c,
error_code& ec)
{
ts.create(ec);
if(ec)
return;
basic_store<xxhasher, fail_file<native_file>> db;
db.open(ts.dp, ts.kp, ts.lp, ec, c);
if(ec)
return;
if(! BEAST_EXPECT(db.appnum() == ts.appnum))
return;
// Insert
for(std::size_t i = 0; i < N; ++i)
{
auto const item = ts[i];
db.insert(item.key, item.data, item.size, ec);
if(ec == test_error::failure)
return;
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
// Fetch
Buffer b;
for(std::size_t i = 0; i < N; ++i)
{
auto const item = ts[i];
db.fetch(item.key, b, ec);
if(ec == test_error::failure)
return;
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
if(! BEAST_EXPECT(b.size() == item.size))
return;
if(! BEAST_EXPECT(std::memcmp(b.data(),
item.data, item.size) == 0))
return;
}
db.close(ec);
if(ec == test_error::failure)
return;
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Verify
verify_info info;
verify<xxhasher>(info, ts.dp, ts.kp,
0, no_progress{}, ec);
if(ec)
{
log << info;
return;
}
}
void
do_recover(
test_store& ts, fail_counter& c, error_code& ec)
{
recover<xxhasher, fail_file<native_file>>(
ts.dp, ts.kp, ts.lp, ec, c);
if(ec)
return;
// Verify
verify_info info;
verify<xxhasher>(info, ts.dp, ts.kp,
0, no_progress{}, ec);
if(ec)
return;
ts.erase();
}
void
test_recover(std::size_t blockSize,
float loadFactor, std::size_t N)
{
testcase(std::to_string(N) + " inserts",
beast::unit_test::abort_on_fail);
test_store ts{sizeof(key_type), blockSize, loadFactor};
for(std::size_t n = 1;; ++n)
{
{
error_code ec;
fail_counter c{n};
do_work(ts, N, c, ec);
if(! ec)
{
ts.close(ec);
ts.erase();
break;
}
if(! BEAST_EXPECTS(ec ==
test::test_error::failure, ec.message()))
return;
}
for(std::size_t m = 1;; ++m)
{
error_code ec;
fail_counter c{m};
do_recover(ts, c, ec);
if(! ec)
break;
if(! BEAST_EXPECTS(ec ==
test::test_error::failure, ec.message()))
return;
}
}
}
};
class recover_test : public basic_recover_test
{
public:
void
run() override
{
test_ok();
test_recover(128, 0.55f, 0);
test_recover(128, 0.55f, 10);
test_recover(128, 0.55f, 100);
}
};
class recover_big_test : public basic_recover_test
{
public:
void
run() override
{
test_recover(256, 0.55f, 1000);
test_recover(256, 0.90f, 10000);
}
};
BEAST_DEFINE_TESTSUITE(recover, test, nudb);
//BEAST_DEFINE_TESTSUITE_MANUAL(recover_big, test, nudb);
} // test
} // nudb

136
test/rekey.cpp Normal file
View File

@@ -0,0 +1,136 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/rekey.hpp>
#include <nudb/test/fail_file.hpp>
#include <nudb/test/test_store.hpp>
#include <nudb/progress.hpp>
#include <nudb/verify.hpp>
#include <beast/unit_test/suite.hpp>
namespace nudb {
namespace test {
// Simple test to check that rekey works, and
// also to exercise all its failure paths.
//
class rekey_test : public beast::unit_test::suite
{
public:
void
do_recover(
std::size_t N, nsize_t blockSize, float loadFactor)
{
using key_type = std::uint32_t;
auto const keys = static_cast<std::size_t>(
loadFactor * detail::bucket_capacity(blockSize));
std::size_t const bufferSize =
(blockSize * (1 + ((N + keys - 1) / keys)))
/ 2;
error_code ec;
test_store ts{sizeof(key_type), blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Insert
for(std::size_t i = 0; i < N; ++i)
{
auto const item = ts[i];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
ts.close(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Verify
verify_info info;
verify<xxhasher>(
info, ts.dp, ts.kp, bufferSize, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
if(! BEAST_EXPECT(info.value_count == N))
return;
if(! BEAST_EXPECT(info.spill_count > 0))
return;
// Rekey
auto const kp2 = ts.kp + "2";
for(std::size_t n = 1;; ++n)
{
fail_counter fc{n};
rekey<xxhasher, fail_file<native_file>>(
ts.dp, kp2, ts.lp, blockSize, loadFactor,
N, bufferSize, ec, no_progress{}, fc);
if(! ec)
break;
if(! BEAST_EXPECTS(ec ==
test::test_error::failure, ec.message()))
return;
ec = {};
recover<xxhasher, native_file>(
ts.dp, kp2, ts.lp, ec);
if(ec == error::no_key_file ||
ec == errc::no_such_file_or_directory)
{
ec = {};
continue;
}
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
native_file::erase(kp2, ec);
if(ec == errc::no_such_file_or_directory)
ec = {};
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Verify
verify<xxhasher>(info, ts.dp, ts.kp,
bufferSize, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
if(! BEAST_EXPECT(info.value_count == N))
return;
}
// Verify
verify<xxhasher>(info, ts.dp, ts.kp,
bufferSize, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
if(! BEAST_EXPECT(info.value_count == N))
return;
verify<xxhasher>(info, ts.dp, kp2,
bufferSize, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
if(! BEAST_EXPECT(info.value_count == N))
return;
}
void
run() override
{
enum
{
N = 50000,
blockSize = 256
};
float const loadFactor = 0.95f;
do_recover(N, blockSize, loadFactor);
}
};
BEAST_DEFINE_TESTSUITE(rekey, test, nudb);
} // test
} // nudb

9
test/store.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/store.hpp>

9
test/type_traits.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/type_traits.hpp>

94
test/verify.cpp Normal file
View File

@@ -0,0 +1,94 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/verify.hpp>
#include <nudb/test/test_store.hpp>
#include <nudb/progress.hpp>
#include <nudb/verify.hpp>
#include <beast/unit_test/suite.hpp>
namespace nudb {
namespace test {
class verify_test : public beast::unit_test::suite
{
public:
// File doesn't exist
void
test_missing()
{
error_code ec;
test_store ts{4, 4096, 0.5f};
verify_info info;
verify<xxhasher>(info,
ts.dp, ts.kp, 0, no_progress{}, ec);
BEAST_EXPECTS(ec ==
errc::no_such_file_or_directory, ec.message());
}
void
test_verify(
std::size_t N,
std::size_t keySize,
std::size_t blockSize,
float loadFactor)
{
testcase <<
"N=" << N << ", "
"keySize=" << keySize << ", "
"blockSize=" << blockSize;
error_code ec;
test_store ts{keySize, blockSize, loadFactor};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Insert
for(std::size_t n = 0; n < N; ++n)
{
auto const item = ts[n];
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
ts.close(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Verify
verify_info info;
verify<xxhasher>(info, ts.dp, ts.kp,
0, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
BEAST_EXPECT(info.hist[1] > 0);
// Verify fast
verify<xxhasher>(info, ts.dp, ts.kp,
10 * 1024 * 1024, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
BEAST_EXPECT(info.hist[1] > 0);
}
void
run() override
{
float const loadFactor = 0.95f;
test_missing();
test_verify(5000, 4, 256, loadFactor);
}
};
BEAST_DEFINE_TESTSUITE(verify, test, nudb);
} // test
} // nudb

9
test/version.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/version.hpp>

114
test/visit.cpp Normal file
View File

@@ -0,0 +1,114 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/visit.hpp>
#include <nudb/test/test_store.hpp>
#include <nudb/progress.hpp>
#include <beast/unit_test/suite.hpp>
#include <unordered_map>
namespace nudb {
namespace test {
class visit_test : public beast::unit_test::suite
{
public:
void
do_visit(
std::size_t N,
std::size_t blockSize,
float loadFactor)
{
using key_type = std::uint32_t;
error_code ec;
test_store ts{sizeof(key_type), blockSize, loadFactor};
// File not present
visit(ts.dp,
[&](void const* key, std::size_t keySize,
void const* data, std::size_t dataSize,
error_code& ec)
{
}, no_progress{}, ec);
if(! BEAST_EXPECTS(ec ==
errc::no_such_file_or_directory, ec.message()))
return;
ec = {};
ts.create(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
ts.open(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
std::unordered_map<key_type, std::size_t> map;
// Insert
for(std::size_t i = 0; i < N; ++i)
{
auto const item = ts[i];
key_type const k = item.key[0] +
(static_cast<key_type>(item.key[1]) << 8) +
(static_cast<key_type>(item.key[2]) << 16) +
(static_cast<key_type>(item.key[3]) << 24);
map[k] = i;
ts.db.insert(item.key, item.data, item.size, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
ts.close(ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
// Visit
visit(ts.dp,
[&](void const* key, std::size_t keySize,
void const* data, std::size_t dataSize,
error_code& ec)
{
auto const fail =
[&ec]
{
ec = error_code{
errc::invalid_argument, generic_category()};
};
if(! BEAST_EXPECT(keySize == sizeof(key_type)))
return fail();
auto const p =
reinterpret_cast<std::uint8_t const*>(key);
key_type const k = p[0] +
(static_cast<key_type>(p[1]) << 8) +
(static_cast<key_type>(p[2]) << 16) +
(static_cast<key_type>(p[3]) << 24);
auto const it = map.find(k);
if(it == map.end())
return fail();
auto const item = ts[it->second];
if(! BEAST_EXPECT(dataSize == item.size))
return fail();
auto const result =
std::memcmp(data, item.data, item.size);
if(result != 0)
return fail();
}, no_progress{}, ec);
if(! BEAST_EXPECTS(! ec, ec.message()))
return;
}
void
run() override
{
float const loadFactor = 0.95f;
do_visit(5000, 4096, loadFactor);
}
};
BEAST_DEFINE_TESTSUITE(visit, test, nudb);
} // test
} // nudb

9
test/win32_file.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/win32_file.hpp>

9
test/xxhasher.cpp Normal file
View File

@@ -0,0 +1,9 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained
#include <nudb/xxhasher.hpp>