diff --git a/Makefile.am b/Makefile.am
index 3c6f3ac6c..221622e52 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -76,14 +76,14 @@ test_libbitcoin_database_test_SOURCES = \
test/mocks/chunk_storage.hpp \
test/mocks/chunk_store.hpp \
test/mocks/map_store.hpp \
+ test/primitives/arrayhead.cpp \
test/primitives/arraymap.cpp \
test/primitives/hashmap.cpp \
- test/primitives/hashmap2.cpp \
test/primitives/head.cpp \
- test/primitives/head2.cpp \
test/primitives/iterator.cpp \
test/primitives/linkage.cpp \
test/primitives/manager.cpp \
+ test/primitives/nomap.cpp \
test/query/archive.cpp \
test/query/confirm.cpp \
test/query/context.cpp \
@@ -159,14 +159,14 @@ include_bitcoin_database_impl_memory_HEADERS = \
include_bitcoin_database_impl_primitivesdir = ${includedir}/bitcoin/database/impl/primitives
include_bitcoin_database_impl_primitives_HEADERS = \
+ include/bitcoin/database/impl/primitives/arrayhead.ipp \
include/bitcoin/database/impl/primitives/arraymap.ipp \
include/bitcoin/database/impl/primitives/hashmap.ipp \
- include/bitcoin/database/impl/primitives/hashmap2.ipp \
include/bitcoin/database/impl/primitives/head.ipp \
- include/bitcoin/database/impl/primitives/head2.ipp \
include/bitcoin/database/impl/primitives/iterator.ipp \
include/bitcoin/database/impl/primitives/linkage.ipp \
- include/bitcoin/database/impl/primitives/manager.ipp
+ include/bitcoin/database/impl/primitives/manager.ipp \
+ include/bitcoin/database/impl/primitives/nomap.ipp
include_bitcoin_database_impl_querydir = ${includedir}/bitcoin/database/impl/query
include_bitcoin_database_impl_query_HEADERS = \
@@ -206,14 +206,14 @@ include_bitcoin_database_memory_interfaces_HEADERS = \
include_bitcoin_database_primitivesdir = ${includedir}/bitcoin/database/primitives
include_bitcoin_database_primitives_HEADERS = \
+ include/bitcoin/database/primitives/arrayhead.hpp \
include/bitcoin/database/primitives/arraymap.hpp \
include/bitcoin/database/primitives/hashmap.hpp \
- include/bitcoin/database/primitives/hashmap2.hpp \
include/bitcoin/database/primitives/head.hpp \
- include/bitcoin/database/primitives/head2.hpp \
include/bitcoin/database/primitives/iterator.hpp \
include/bitcoin/database/primitives/linkage.hpp \
include/bitcoin/database/primitives/manager.hpp \
+ include/bitcoin/database/primitives/nomap.hpp \
include/bitcoin/database/primitives/primitives.hpp
include_bitcoin_database_tablesdir = ${includedir}/bitcoin/database/tables
diff --git a/builds/cmake/CMakeLists.txt b/builds/cmake/CMakeLists.txt
index 36fee6177..f01d716aa 100644
--- a/builds/cmake/CMakeLists.txt
+++ b/builds/cmake/CMakeLists.txt
@@ -284,14 +284,14 @@ if (with-tests)
"../../test/mocks/chunk_storage.hpp"
"../../test/mocks/chunk_store.hpp"
"../../test/mocks/map_store.hpp"
+ "../../test/primitives/arrayhead.cpp"
"../../test/primitives/arraymap.cpp"
"../../test/primitives/hashmap.cpp"
- "../../test/primitives/hashmap2.cpp"
"../../test/primitives/head.cpp"
- "../../test/primitives/head2.cpp"
"../../test/primitives/iterator.cpp"
"../../test/primitives/linkage.cpp"
"../../test/primitives/manager.cpp"
+ "../../test/primitives/nomap.cpp"
"../../test/query/archive.cpp"
"../../test/query/confirm.cpp"
"../../test/query/context.cpp"
diff --git a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj
index ee72c818f..54dc5b415 100644
--- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj
@@ -85,14 +85,14 @@
$(IntDir)test_memory_utilities.obj
+
-
-
+
diff --git a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters
index 4f7eb488a..8e1d963ce 100644
--- a/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-database-test/libbitcoin-database-test.vcxproj.filters
@@ -78,21 +78,18 @@
src\mocks
-
+
src\primitives
-
+
src\primitives
-
+
src\primitives
src\primitives
-
- src\primitives
-
src\primitives
@@ -102,6 +99,9 @@
src\primitives
+
+ src\primitives
+
src\query
diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj
index b5a8344fb..4dfd15a83 100644
--- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj
@@ -113,14 +113,14 @@
+
-
-
+
@@ -153,14 +153,14 @@
+
-
-
+
diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters
index 7ab8c117c..8da6a2fa2 100644
--- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters
@@ -182,21 +182,18 @@
include\bitcoin\database\memory
-
+
include\bitcoin\database\primitives
-
+
include\bitcoin\database\primitives
-
+
include\bitcoin\database\primitives
include\bitcoin\database\primitives
-
- include\bitcoin\database\primitives
-
include\bitcoin\database\primitives
@@ -206,6 +203,9 @@
include\bitcoin\database\primitives
+
+ include\bitcoin\database\primitives
+
include\bitcoin\database\primitives
@@ -298,21 +298,18 @@
include\bitcoin\database\impl\memory
-
+
include\bitcoin\database\impl\primitives
-
+
include\bitcoin\database\impl\primitives
-
+
include\bitcoin\database\impl\primitives
include\bitcoin\database\impl\primitives
-
- include\bitcoin\database\impl\primitives
-
include\bitcoin\database\impl\primitives
@@ -322,6 +319,9 @@
include\bitcoin\database\impl\primitives
+
+ include\bitcoin\database\impl\primitives
+
include\bitcoin\database\impl\query
diff --git a/include/bitcoin/database.hpp b/include/bitcoin/database.hpp
index fb615bb16..87ad9f6b3 100644
--- a/include/bitcoin/database.hpp
+++ b/include/bitcoin/database.hpp
@@ -42,14 +42,14 @@
#include
#include
#include
+#include
#include
#include
-#include
#include
-#include
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/bitcoin/database/impl/primitives/head2.ipp b/include/bitcoin/database/impl/primitives/arrayhead.ipp
similarity index 93%
rename from include/bitcoin/database/impl/primitives/head2.ipp
rename to include/bitcoin/database/impl/primitives/arrayhead.ipp
index 2eebc233b..4d7c17a73 100644
--- a/include/bitcoin/database/impl/primitives/head2.ipp
+++ b/include/bitcoin/database/impl/primitives/arrayhead.ipp
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_HEAD2_IPP
-#define LIBBITCOIN_DATABASE_PRIMITIVES_HEAD2_IPP
+#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_ARRAYHEAD_IPP
+#define LIBBITCOIN_DATABASE_PRIMITIVES_ARRAYHEAD_IPP
#include
#include
@@ -27,7 +27,7 @@ namespace libbitcoin {
namespace database {
TEMPLATE
-CLASS::head2(storage& head, const Link& buckets) NOEXCEPT
+CLASS::arrayhead(storage& head, const Link& buckets) NOEXCEPT
: file_(head), initial_buckets_(buckets)
{
}
@@ -98,7 +98,7 @@ TEMPLATE
bool CLASS::get_body_count(Link& count) const NOEXCEPT
{
const auto ptr = file_.get();
- if (!ptr)
+ if (!ptr || Link::size > file_.size())
return false;
count = array_cast(ptr->data());
@@ -109,7 +109,7 @@ TEMPLATE
bool CLASS::set_body_count(const Link& count) NOEXCEPT
{
const auto ptr = file_.get();
- if (!ptr)
+ if (!ptr || Link::size > file_.size())
return false;
array_cast(ptr->data()) = count;
diff --git a/include/bitcoin/database/impl/primitives/arraymap.ipp b/include/bitcoin/database/impl/primitives/arraymap.ipp
index a2a89276c..e669588ed 100644
--- a/include/bitcoin/database/impl/primitives/arraymap.ipp
+++ b/include/bitcoin/database/impl/primitives/arraymap.ipp
@@ -19,15 +19,16 @@
#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_ARRAYMAP_IPP
#define LIBBITCOIN_DATABASE_PRIMITIVES_ARRAYMAP_IPP
+#include
#include
#include
namespace libbitcoin {
namespace database {
-
+
TEMPLATE
-CLASS::arraymap(storage& header, storage& body) NOEXCEPT
- : head_(header, 0), manager_(body)
+CLASS::arraymap(storage& header, storage& body, const Link& buckets) NOEXCEPT
+ : head_(header, buckets), manager_(body)
{
}
@@ -38,8 +39,8 @@ TEMPLATE
bool CLASS::create() NOEXCEPT
{
Link count{};
- return head_.create() &&
- head_.get_body_count(count) && manager_.truncate(count);
+ return head_.create() && head_.get_body_count(count) &&
+ manager_.truncate(count);
}
TEMPLATE
@@ -58,21 +59,27 @@ TEMPLATE
bool CLASS::restore() NOEXCEPT
{
Link count{};
- return head_.verify() &&
- head_.get_body_count(count) && manager_.truncate(count);
+ return head_.verify() && head_.get_body_count(count) &&
+ manager_.truncate(count);
}
TEMPLATE
bool CLASS::verify() const NOEXCEPT
{
Link count{};
- return head_.verify() &&
- head_.get_body_count(count) && count == manager_.count();
+ return head_.verify() && head_.get_body_count(count) &&
+ (count == manager_.count());
}
// sizing
// ----------------------------------------------------------------------------
+TEMPLATE
+bool CLASS::enabled() const NOEXCEPT
+{
+ return head_.enabled();
+}
+
TEMPLATE
size_t CLASS::buckets() const NOEXCEPT
{
@@ -97,13 +104,7 @@ Link CLASS::count() const NOEXCEPT
return manager_.count();
}
-TEMPLATE
-bool CLASS::truncate(const Link& count) NOEXCEPT
-{
- return manager_.truncate(count);
-}
-
-// error condition
+// query interface
// ----------------------------------------------------------------------------
TEMPLATE
@@ -128,51 +129,95 @@ code CLASS::reload() NOEXCEPT
// ----------------------------------------------------------------------------
TEMPLATE
-template >
-bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
+Link CLASS::top(const Link& link) const NOEXCEPT
{
- using namespace system;
- const auto ptr = manager_.get(link);
- if (!ptr)
- return false;
+ if (link >= head_.buckets())
+ return {};
- iostream stream{ *ptr };
- reader source{ stream };
- if constexpr (!is_slab) { source.set_limit(Size); }
- return element.from_data(source);
+ return head_.top(link);
+}
+
+TEMPLATE
+bool CLASS::exists(const Key& key) const NOEXCEPT
+{
+ return !first(key).is_terminal();
+}
+
+TEMPLATE
+Link CLASS::first(const Key& key) const NOEXCEPT
+{
+ return head_.top(key);
+}
+
+TEMPLATE
+template >
+bool CLASS::find(const Key& key, Element& element) const NOEXCEPT
+{
+ // This override avoids duplicated memory_ptr construct in get(first()).
+ const auto ptr = manager_.get();
+ return read(ptr, first(ptr, head_.top(key), key), element);
}
TEMPLATE
template >
-bool CLASS::put(const Element& element) NOEXCEPT
+bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
{
- Link link{};
- return put_link(link, element);
+ // This override is the normal form.
+ return read(manager_.get(), link, element);
}
TEMPLATE
template >
-bool CLASS::put_link(Link& link, const Element& element) NOEXCEPT
+bool CLASS::put(const Key& key, const Element& element) NOEXCEPT
{
using namespace system;
const auto count = element.count();
- link = manager_.allocate(count);
+ const auto link = allocate(count);
const auto ptr = manager_.get(link);
if (!ptr)
return false;
+ // iostream.flush is a nop (direct copy).
iostream stream{ *ptr };
- flipper sink{ stream };
+ finalizer sink{ stream };
+ sink.skip_bytes(Link::size);
+ sink.write_bytes(key);
+
if constexpr (!is_slab) { BC_DEBUG_ONLY(sink.set_limit(Size * count);) }
- return element.to_data(sink);
+ return element.to_data(sink) && head_.push(link, head_.index(key));
}
+// protected
+// ----------------------------------------------------------------------------
+
TEMPLATE
template >
-Link CLASS::put_link(const Element& element) NOEXCEPT
+bool CLASS::read(const memory_ptr& ptr, const Link& link,
+ Element& element) NOEXCEPT
{
- Link link{};
- return put_link(link, element) ? link : Link{};
+ if (!ptr || link.is_terminal())
+ return false;
+
+ using namespace system;
+ const auto start = manager::link_to_position(link);
+ if (is_limited(start))
+ return false;
+
+ const auto size = ptr->size();
+ const auto position = possible_narrow_and_sign_cast(start);
+ if (position > size)
+ return false;
+
+ const auto offset = ptr->offset(position);
+ if (is_null(offset))
+ return false;
+
+ // Stream starts at record and the index is skipped for reader convenience.
+ iostream stream{ offset, size - position };
+ reader source{ stream };
+
+ if constexpr (!is_slab) { BC_DEBUG_ONLY(source.set_limit(Size);) }
+ return element.from_data(source);
}
} // namespace database
diff --git a/include/bitcoin/database/impl/primitives/manager.ipp b/include/bitcoin/database/impl/primitives/manager.ipp
index 0986bdbbe..60ce7166a 100644
--- a/include/bitcoin/database/impl/primitives/manager.ipp
+++ b/include/bitcoin/database/impl/primitives/manager.ipp
@@ -64,7 +64,7 @@ Link CLASS::allocate(const Link& size) NOEXCEPT
if (start == storage::eof)
return Link::terminal;
- // Callers (arraymap and hashmap) handle terminal allocation.
+ // Callers (nomap and hashmap) handle terminal allocation.
return position_to_link(start);
}
diff --git a/include/bitcoin/database/impl/primitives/hashmap2.ipp b/include/bitcoin/database/impl/primitives/nomap.ipp
similarity index 56%
rename from include/bitcoin/database/impl/primitives/hashmap2.ipp
rename to include/bitcoin/database/impl/primitives/nomap.ipp
index 60e15de4f..eec17c9bf 100644
--- a/include/bitcoin/database/impl/primitives/hashmap2.ipp
+++ b/include/bitcoin/database/impl/primitives/nomap.ipp
@@ -16,19 +16,18 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_HASHMAP2_IPP
-#define LIBBITCOIN_DATABASE_PRIMITIVES_HASHMAP2_IPP
+#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_NOMAP_IPP
+#define LIBBITCOIN_DATABASE_PRIMITIVES_NOMAP_IPP
-#include
#include
#include
namespace libbitcoin {
namespace database {
-
+
TEMPLATE
-CLASS::hashmap2(storage& header, storage& body, const Link& buckets) NOEXCEPT
- : head_(header, buckets), manager_(body)
+CLASS::nomap(storage& header, storage& body) NOEXCEPT
+ : head_(header, 0), manager_(body)
{
}
@@ -39,8 +38,8 @@ TEMPLATE
bool CLASS::create() NOEXCEPT
{
Link count{};
- return head_.create() && head_.get_body_count(count) &&
- manager_.truncate(count);
+ return head_.create() &&
+ head_.get_body_count(count) && manager_.truncate(count);
}
TEMPLATE
@@ -59,27 +58,21 @@ TEMPLATE
bool CLASS::restore() NOEXCEPT
{
Link count{};
- return head_.verify() && head_.get_body_count(count) &&
- manager_.truncate(count);
+ return head_.verify() &&
+ head_.get_body_count(count) && manager_.truncate(count);
}
TEMPLATE
bool CLASS::verify() const NOEXCEPT
{
Link count{};
- return head_.verify() && head_.get_body_count(count) &&
- (count == manager_.count());
+ return head_.verify() &&
+ head_.get_body_count(count) && count == manager_.count();
}
// sizing
// ----------------------------------------------------------------------------
-TEMPLATE
-bool CLASS::enabled() const NOEXCEPT
-{
- return head_.enabled();
-}
-
TEMPLATE
size_t CLASS::buckets() const NOEXCEPT
{
@@ -104,7 +97,13 @@ Link CLASS::count() const NOEXCEPT
return manager_.count();
}
-// query interface
+TEMPLATE
+bool CLASS::truncate(const Link& count) NOEXCEPT
+{
+ return manager_.truncate(count);
+}
+
+// error condition
// ----------------------------------------------------------------------------
TEMPLATE
@@ -128,96 +127,52 @@ code CLASS::reload() NOEXCEPT
// query interface
// ----------------------------------------------------------------------------
-TEMPLATE
-Link CLASS::top(const Link& link) const NOEXCEPT
-{
- if (link >= head_.buckets())
- return {};
-
- return head_.top(link);
-}
-
-TEMPLATE
-bool CLASS::exists(const Key& key) const NOEXCEPT
-{
- return !first(key).is_terminal();
-}
-
-TEMPLATE
-Link CLASS::first(const Key& key) const NOEXCEPT
-{
- return head_.top(key);
-}
-
TEMPLATE
template >
-bool CLASS::find(const Key& key, Element& element) const NOEXCEPT
+bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
{
- // This override avoids duplicated memory_ptr construct in get(first()).
- const auto ptr = manager_.get();
- return read(ptr, first(ptr, head_.top(key), key), element);
+ using namespace system;
+ const auto ptr = manager_.get(link);
+ if (!ptr)
+ return false;
+
+ iostream stream{ *ptr };
+ reader source{ stream };
+ if constexpr (!is_slab) { source.set_limit(Size); }
+ return element.from_data(source);
}
TEMPLATE
template >
-bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
+bool CLASS::put(const Element& element) NOEXCEPT
{
- // This override is the normal form.
- return read(manager_.get(), link, element);
+ Link link{};
+ return put_link(link, element);
}
TEMPLATE
template >
-bool CLASS::put(const Key& key, const Element& element) NOEXCEPT
+bool CLASS::put_link(Link& link, const Element& element) NOEXCEPT
{
using namespace system;
const auto count = element.count();
- const auto link = allocate(count);
+ link = manager_.allocate(count);
const auto ptr = manager_.get(link);
if (!ptr)
return false;
- // iostream.flush is a nop (direct copy).
iostream stream{ *ptr };
- finalizer sink{ stream };
- sink.skip_bytes(Link::size);
- sink.write_bytes(key);
-
+ flipper sink{ stream };
if constexpr (!is_slab) { BC_DEBUG_ONLY(sink.set_limit(Size * count);) }
- return element.to_data(sink) && head_.push(link, head_.index(key));
+ return element.to_data(sink);
}
-// protected
-// ----------------------------------------------------------------------------
-
TEMPLATE
template >
-bool CLASS::read(const memory_ptr& ptr, const Link& link,
- Element& element) NOEXCEPT
+Link CLASS::put_link(const Element& element) NOEXCEPT
{
- if (!ptr || link.is_terminal())
- return false;
-
- using namespace system;
- const auto start = manager::link_to_position(link);
- if (is_limited(start))
- return false;
-
- const auto size = ptr->size();
- const auto position = possible_narrow_and_sign_cast(start);
- if (position > size)
- return false;
-
- const auto offset = ptr->offset(position);
- if (is_null(offset))
- return false;
-
- // Stream starts at record and the index is skipped for reader convenience.
- iostream stream{ offset, size - position };
- reader source{ stream };
-
- if constexpr (!is_slab) { BC_DEBUG_ONLY(source.set_limit(Size);) }
- return element.from_data(source);
+ Link link{};
+ return put_link(link, element) ? link : Link{};
}
} // namespace database
diff --git a/include/bitcoin/database/primitives/head2.hpp b/include/bitcoin/database/primitives/arrayhead.hpp
similarity index 89%
rename from include/bitcoin/database/primitives/head2.hpp
rename to include/bitcoin/database/primitives/arrayhead.hpp
index cfab95188..431388a76 100644
--- a/include/bitcoin/database/primitives/head2.hpp
+++ b/include/bitcoin/database/primitives/arrayhead.hpp
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_HEAD2_HPP
-#define LIBBITCOIN_DATABASE_PRIMITIVES_HEAD2_HPP
+#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_ARRAYHEAD_HPP
+#define LIBBITCOIN_DATABASE_PRIMITIVES_ARRAYHEAD_HPP
#include
#include
@@ -30,15 +30,15 @@ namespace database {
/// Dynamically expanding array map header.
/// Less efficient than a fixed-size header.
template
-class head2
+class arrayhead
{
public:
- DEFAULT_COPY_MOVE_DESTRUCT(head2);
+ DEFAULT_COPY_MOVE_DESTRUCT(arrayhead);
using bytes = typename Link::bytes;
- /// An array head has zero buckets (and cannot call index()).
- head2(storage& head, const Link& buckets) NOEXCEPT;
+ /// An array head is disabled it if has one or less buckets.
+ arrayhead(storage& head, const Link& buckets) NOEXCEPT;
/// Sizing is dynamic (thread safe).
size_t size() const NOEXCEPT;
@@ -99,9 +99,9 @@ class head2
} // namespace libbitcoin
#define TEMPLATE template
-#define CLASS head2
+#define CLASS arrayhead
-#include
+#include
#undef CLASS
#undef TEMPLATE
diff --git a/include/bitcoin/database/primitives/arraymap.hpp b/include/bitcoin/database/primitives/arraymap.hpp
index 03d7190bb..049325cb4 100644
--- a/include/bitcoin/database/primitives/arraymap.hpp
+++ b/include/bitcoin/database/primitives/arraymap.hpp
@@ -22,24 +22,30 @@
#include
#include
#include
-#include
+#include
+#include
#include
#include
namespace libbitcoin {
namespace database {
-
-/// Caution: reader/writer hold body remap lock until disposed.
+
+/// Caution: iterator/reader/finalizer hold body remap lock until disposed.
/// These handles should be used for serialization and immediately disposed.
-template
+/// Readers and writers are always prepositioned at data, and are limited to
+/// the extent the record/slab size is known (limit can always be removed).
+/// Streams are always initialized from first element byte up to file limit.
+template
class arraymap
{
public:
DEFAULT_COPY_MOVE_DESTRUCT(arraymap);
+ using key = Key;
using link = Link;
+ using iterator = database::iterator;
- arraymap(storage& header, storage& body) NOEXCEPT;
+ arraymap(storage& header, storage& body, const Link& buckets) NOEXCEPT;
/// Setup, not thread safe.
/// -----------------------------------------------------------------------
@@ -53,7 +59,10 @@ class arraymap
/// Sizing.
/// -----------------------------------------------------------------------
- /// Hash table bucket count (zero).
+ /// The instance is enabled (more than 1 bucket).
+ bool enabled() const NOEXCEPT;
+
+ /// Hash table bucket count.
size_t buckets() const NOEXCEPT;
/// Head file bytes.
@@ -65,9 +74,6 @@ class arraymap
/// Count of records (or body file bytes if slab).
Link count() const NOEXCEPT;
- /// Reduce count as specified.
- bool truncate(const Link& count) NOEXCEPT;
-
/// Errors.
/// -----------------------------------------------------------------------
@@ -80,29 +86,44 @@ class arraymap
/// Resume from disk full condition.
code reload() NOEXCEPT;
- /// Query interface.
+ /// Query interface, iterator is not thread safe.
/// -----------------------------------------------------------------------
- /// Get element at link.
+ /// Return the link at the top of the conflict list (for table scanning).
+ Link top(const Link& list) const NOEXCEPT;
+
+ /// True if an instance of object with key exists.
+ bool exists(const Key& key) const NOEXCEPT;
+
+ /// Return first element link or terminal if not found/error.
+ Link first(const Key& key) const NOEXCEPT;
+
+ /// Get first element matching the search key, false if not found/error.
template = true>
- bool get(const Link& link, Element& element) const NOEXCEPT;
+ bool find(const Key& key, Element& element) const NOEXCEPT;
- /// Put element.
+ /// Get element at link, false if deserialize error.
template = true>
- bool put(const Element& element) NOEXCEPT;
+ bool get(const Link& link, Element& element) const NOEXCEPT;
- /// Put element and return link.
+ /// Allocate, set, commit element to key.
+ /// Expands table AND HEADER as necessary.
template = true>
- bool put_link(Link& link, const Element& element) NOEXCEPT;
+ bool put(const Key& key, const Element& element) NOEXCEPT;
+
+protected:
+ /// Get element at link using memory object, false if deserialize error.
template = true>
- Link put_link(const Element& element) NOEXCEPT;
+ static bool read(const memory_ptr& ptr, const Link& link,
+ Element& element) NOEXCEPT;
private:
static constexpr auto is_slab = (Size == max_size_t);
- using head = database::head, false>;
- using manager = database::manager, Size>;
- // Unsafe with zero buckets (index/top/push).
+ using head = database::arrayhead;
+ using manager = database::manager;
+
+ // Thread safe (index/top/push).
// Not thread safe (create/open/close/backup/restore).
head head_;
@@ -111,13 +132,14 @@ class arraymap
};
template
-using array_map = arraymap, Element::size>;
+using array_map = arraymap, system::data_array,
+ Element::size>;
} // namespace database
} // namespace libbitcoin
-#define TEMPLATE template
-#define CLASS arraymap
+#define TEMPLATE template
+#define CLASS arraymap
#include
diff --git a/include/bitcoin/database/primitives/hashmap2.hpp b/include/bitcoin/database/primitives/nomap.hpp
similarity index 56%
rename from include/bitcoin/database/primitives/hashmap2.hpp
rename to include/bitcoin/database/primitives/nomap.hpp
index b92e2531e..b512f35c3 100644
--- a/include/bitcoin/database/primitives/hashmap2.hpp
+++ b/include/bitcoin/database/primitives/nomap.hpp
@@ -16,36 +16,30 @@
/// You should have received a copy of the GNU Affero General Public License
/// along with this program. If not, see .
*/
-#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_HASHMAP2_HPP
-#define LIBBITCOIN_DATABASE_PRIMITIVES_HASHMAP2_HPP
+#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_NOMAP_HPP
+#define LIBBITCOIN_DATABASE_PRIMITIVES_NOMAP_HPP
#include
#include
#include
-#include
-#include
+#include
#include
#include
namespace libbitcoin {
namespace database {
-
-/// Caution: iterator/reader/finalizer hold body remap lock until disposed.
+
+/// Caution: reader/writer hold body remap lock until disposed.
/// These handles should be used for serialization and immediately disposed.
-/// Readers and writers are always prepositioned at data, and are limited to
-/// the extent the record/slab size is known (limit can always be removed).
-/// Streams are always initialized from first element byte up to file limit.
-template
-class hashmap2
+template
+class nomap
{
public:
- DEFAULT_COPY_MOVE_DESTRUCT(hashmap2);
+ DEFAULT_COPY_MOVE_DESTRUCT(nomap);
- using key = Key;
using link = Link;
- using iterator = database::iterator;
- hashmap2(storage& header, storage& body, const Link& buckets) NOEXCEPT;
+ nomap(storage& header, storage& body) NOEXCEPT;
/// Setup, not thread safe.
/// -----------------------------------------------------------------------
@@ -59,10 +53,7 @@ class hashmap2
/// Sizing.
/// -----------------------------------------------------------------------
- /// The instance is enabled (more than 1 bucket).
- bool enabled() const NOEXCEPT;
-
- /// Hash table bucket count.
+ /// Hash table bucket count (zero).
size_t buckets() const NOEXCEPT;
/// Head file bytes.
@@ -74,6 +65,9 @@ class hashmap2
/// Count of records (or body file bytes if slab).
Link count() const NOEXCEPT;
+ /// Reduce count as specified.
+ bool truncate(const Link& count) NOEXCEPT;
+
/// Errors.
/// -----------------------------------------------------------------------
@@ -86,42 +80,27 @@ class hashmap2
/// Resume from disk full condition.
code reload() NOEXCEPT;
- /// Query interface, iterator is not thread safe.
+ /// Query interface.
/// -----------------------------------------------------------------------
- /// Return the link at the top of the conflict list (for table scanning).
- Link top(const Link& list) const NOEXCEPT;
-
- /// True if an instance of object with key exists.
- bool exists(const Key& key) const NOEXCEPT;
-
- /// Return first element link or terminal if not found/error.
- Link first(const Key& key) const NOEXCEPT;
-
- /// Get first element matching the search key, false if not found/error.
- template = true>
- bool find(const Key& key, Element& element) const NOEXCEPT;
-
- /// Get element at link, false if deserialize error.
+ /// Get element at link.
template = true>
bool get(const Link& link, Element& element) const NOEXCEPT;
- /// Allocate, set, commit element to key.
- /// Expands table AND HEADER as necessary.
+ /// Put element.
template = true>
- bool put(const Key& key, const Element& element) NOEXCEPT;
+ bool put(const Element& element) NOEXCEPT;
-protected:
- /// Get element at link using memory object, false if deserialize error.
+ /// Put element and return link.
template = true>
- static bool read(const memory_ptr& ptr, const Link& link,
- Element& element) NOEXCEPT;
+ bool put_link(Link& link, const Element& element) NOEXCEPT;
+ template = true>
+ Link put_link(const Element& element) NOEXCEPT;
private:
static constexpr auto is_slab = (Size == max_size_t);
-
- using head = database::head2;
- using manager = database::manager;
+ using manager = database::manager, Size>;
+ using head = database::arrayhead;
// Thread safe (index/top/push).
// Not thread safe (create/open/close/backup/restore).
@@ -132,16 +111,15 @@ class hashmap2
};
template
-using hash_map2 = hashmap2, system::data_array,
- Element::size>;
+using no_map = nomap, Element::size>;
} // namespace database
} // namespace libbitcoin
-#define TEMPLATE template
-#define CLASS hashmap2
+#define TEMPLATE template
+#define CLASS nomap
-#include
+#include
#undef CLASS
#undef TEMPLATE
diff --git a/include/bitcoin/database/primitives/primitives.hpp b/include/bitcoin/database/primitives/primitives.hpp
index f1ef80732..fbcd7b2b9 100644
--- a/include/bitcoin/database/primitives/primitives.hpp
+++ b/include/bitcoin/database/primitives/primitives.hpp
@@ -19,13 +19,13 @@
#ifndef LIBBITCOIN_DATABASE_PRIMITIVES_PRIMITIVES_HPP
#define LIBBITCOIN_DATABASE_PRIMITIVES_PRIMITIVES_HPP
+#include
#include
-#include
-#include
#include
-#include
+#include
#include
#include
#include
+#include
#endif
diff --git a/include/bitcoin/database/tables/archives/input.hpp b/include/bitcoin/database/tables/archives/input.hpp
index d02bbfc9f..dd0c101ba 100644
--- a/include/bitcoin/database/tables/archives/input.hpp
+++ b/include/bitcoin/database/tables/archives/input.hpp
@@ -36,9 +36,9 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
/// Input is a blob (set of non-searchable slabs).
/// Input can be obtained by fk navigation (eg from tx/puts/spend).
struct input
- : public array_map
+ : public no_map
{
- using array_map::arraymap;
+ using no_map::nomap;
struct slab
: public schema::input
diff --git a/include/bitcoin/database/tables/archives/output.hpp b/include/bitcoin/database/tables/archives/output.hpp
index 90a8767f4..0ea2e8c32 100644
--- a/include/bitcoin/database/tables/archives/output.hpp
+++ b/include/bitcoin/database/tables/archives/output.hpp
@@ -35,10 +35,10 @@ BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
/// Output is a blob (set of non-searchable slabs).
/// Output can be obtained by fk navigation (eg from tx/index).
struct output
- : public array_map
+ : public no_map
{
using tx = linkage;
- using array_map::arraymap;
+ using no_map::nomap;
struct slab
: public schema::output
diff --git a/include/bitcoin/database/tables/archives/puts.hpp b/include/bitcoin/database/tables/archives/puts.hpp
index a98981b89..500f4088f 100644
--- a/include/bitcoin/database/tables/archives/puts.hpp
+++ b/include/bitcoin/database/tables/archives/puts.hpp
@@ -32,13 +32,13 @@ namespace table {
/// Puts is an blob of spend and output fk records.
struct puts
- : public array_map
+ : public no_map
{
using spend = linkage;
using out = linkage;
using spend_links = std_vector;
using output_links = std_vector;
- using array_map::arraymap;
+ using no_map::nomap;
// TODO: There is a potential optimization available given that the inputs
// (spend puts) for a given transaction are sequential. This means that an
diff --git a/include/bitcoin/database/tables/indexes/height.hpp b/include/bitcoin/database/tables/indexes/height.hpp
index 59b9a503c..142d9b80d 100644
--- a/include/bitcoin/database/tables/indexes/height.hpp
+++ b/include/bitcoin/database/tables/indexes/height.hpp
@@ -30,10 +30,10 @@ namespace table {
/// height is an array of header fk records.
struct height
- : public array_map
+ : public no_map
{
using block = linkage;
- using array_map::arraymap;
+ using no_map::nomap;
struct record
: public schema::height
diff --git a/include/bitcoin/database/tables/optionals/bootstrap.hpp b/include/bitcoin/database/tables/optionals/bootstrap.hpp
index 59d6da289..590d0d95e 100644
--- a/include/bitcoin/database/tables/optionals/bootstrap.hpp
+++ b/include/bitcoin/database/tables/optionals/bootstrap.hpp
@@ -30,9 +30,9 @@
////
/////// bootstrap is an array of header hashes (initial blockchain).
////struct bootstrap
-//// : public array_map
+//// : public no_map
////{
-//// using array_map::arraymap;
+//// using no_map::nomap;
////
//// struct record
//// : public schema::bootstrap
diff --git a/src/memory/map.cpp b/src/memory/map.cpp
index 179ba88e6..202908f04 100644
--- a/src/memory/map.cpp
+++ b/src/memory/map.cpp
@@ -242,13 +242,13 @@ size_t map::allocate(size_t chunk) NOEXCEPT
auto end = logical_ + chunk;
if (end > capacity_)
{
- const auto new_capacity = to_capacity(end);
+ const auto capacity = to_capacity(end);
// TODO: Could loop over a try lock here and log deadlock warning.
std::unique_lock remap_lock(remap_mutex_);
// Disk full condition leaves store in valid state despite eof return.
- if (!remap_(new_capacity))
+ if (!remap_(capacity))
return storage::eof;
}
@@ -267,20 +267,18 @@ memory_ptr map::set(size_t offset, size_t size, uint8_t backfill) NOEXCEPT
const auto end = std::max(logical_, offset + size);
if (end > capacity_)
{
- const auto old_capacity = capacity_;
- const auto new_capacity = to_capacity(end);
+ const auto capacity = to_capacity(end);
// TODO: Could loop over a try lock here and log deadlock warning.
std::unique_lock remap_lock(remap_mutex_);
// Disk full condition leaves store in valid state despite null.
- if (!remap_(new_capacity))
+ if (!remap_(capacity))
return {};
// Fill new capacity as offset may not be at end due to expansion.
BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
- std::fill_n(memory_map_ + logical_, new_capacity - logical_,
- backfill);
+ std::fill_n(memory_map_ + logical_, capacity - logical_, backfill);
BC_POP_WARNING()
}
diff --git a/test/primitives/head2.cpp b/test/primitives/arrayhead.cpp
similarity index 85%
rename from test/primitives/head2.cpp
rename to test/primitives/arrayhead.cpp
index 18766f128..ece55c439 100644
--- a/test/primitives/head2.cpp
+++ b/test/primitives/arrayhead.cpp
@@ -19,7 +19,7 @@
#include "../test.hpp"
#include "../mocks/chunk_storage.hpp"
-BOOST_AUTO_TEST_SUITE(head2_tests)
+BOOST_AUTO_TEST_SUITE(arrayhead_tests)
using namespace system;
@@ -35,7 +35,7 @@ constexpr auto buckets = sub1(links);
static_assert(buckets == 20u);
using link = linkage;
-using test_header = head2;
+using test_header = arrayhead;
class nullptr_storage
: public test::chunk_storage
@@ -49,7 +49,7 @@ class nullptr_storage
}
};
-BOOST_AUTO_TEST_CASE(head__create__size__expected)
+BOOST_AUTO_TEST_CASE(arrayhead__create__size__expected)
{
data_chunk data;
test::chunk_storage store{ data };
@@ -58,7 +58,7 @@ BOOST_AUTO_TEST_CASE(head__create__size__expected)
BOOST_REQUIRE_EQUAL(data.size(), head_size);
}
-BOOST_AUTO_TEST_CASE(head__verify__uncreated__false)
+BOOST_AUTO_TEST_CASE(arrayhead__verify__uncreated__false)
{
data_chunk data;
test::chunk_storage store{ data };
@@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE(head__verify__uncreated__false)
BOOST_REQUIRE(!head.verify());
}
-BOOST_AUTO_TEST_CASE(head__verify__created__false)
+BOOST_AUTO_TEST_CASE(arrayhead__verify__created__false)
{
data_chunk data;
test::chunk_storage store{ data };
@@ -76,7 +76,7 @@ BOOST_AUTO_TEST_CASE(head__verify__created__false)
BOOST_REQUIRE(head.verify());
}
-BOOST_AUTO_TEST_CASE(head__get_body_count__created__zero)
+BOOST_AUTO_TEST_CASE(arrayhead__get_body_count__created__zero)
{
data_chunk data;
test::chunk_storage store{ data };
@@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE(head__get_body_count__created__zero)
BOOST_REQUIRE_EQUAL(count, zero);
}
-BOOST_AUTO_TEST_CASE(head__set_body_count__get__expected)
+BOOST_AUTO_TEST_CASE(arrayhead__set_body_count__get__expected)
{
data_chunk data;
test::chunk_storage store{ data };
@@ -103,7 +103,7 @@ BOOST_AUTO_TEST_CASE(head__set_body_count__get__expected)
BOOST_REQUIRE_EQUAL(count, expected);
}
-BOOST_AUTO_TEST_CASE(head__top__link__terminal)
+BOOST_AUTO_TEST_CASE(arrayhead__top__link__terminal)
{
test::chunk_storage store;
test_header head{ store, buckets };
@@ -111,7 +111,7 @@ BOOST_AUTO_TEST_CASE(head__top__link__terminal)
BOOST_REQUIRE(head.top(9).is_terminal());
}
-BOOST_AUTO_TEST_CASE(head__top__nullptr__terminal)
+BOOST_AUTO_TEST_CASE(arrayhead__top__nullptr__terminal)
{
nullptr_storage store;
test_header head{ store, buckets };
@@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(head__top__nullptr__terminal)
BOOST_REQUIRE(head.top(9).is_terminal());
}
-BOOST_AUTO_TEST_CASE(head__top__key__terminal)
+BOOST_AUTO_TEST_CASE(arrayhead__top__key__terminal)
{
test::chunk_storage store;
test_header head{ store, buckets };
diff --git a/test/primitives/arraymap.cpp b/test/primitives/arraymap.cpp
index 348094a5c..205df7ab4 100644
--- a/test/primitives/arraymap.cpp
+++ b/test/primitives/arraymap.cpp
@@ -21,212 +21,173 @@
BOOST_AUTO_TEST_SUITE(arraymap_tests)
-template
+template
class arraymap_
- : public arraymap
+ : public arraymap
{
public:
- using base = arraymap;
- using base::arraymap;
- ////using reader_ptr = std::shared_ptr;
- ////using writer_ptr = std::shared_ptr;
- ////
- ////reader_ptr getter_(const Link& link) const NOEXCEPT
- ////{
- //// using namespace system;
- //// const auto ptr = manager_.get(link);
- //// if (!ptr)
- //// return {};
- ////
- //// istream stream{ *ptr };
- //// const auto source = std::make_shared(stream);
- //// if constexpr (!is_slab) { source->set_limit(Size); }
- //// return source;
- ////}
- ////
- ////writer_ptr creater_(const Link& size=one) NOEXCEPT
- ////{
- //// using namespace system;
- //// const auto link = manager_.allocate(size);
- //// const auto ptr = manager_.get(link);
- //// if (!ptr)
- //// return {};
- ////
- //// iostream stream{ *ptr };
- //// const auto sink = std::make_shared(stream);
- //// if constexpr (!is_slab) { sink.set_limit(Size * size); }
- //// return sink;
- ////}
+ using base = arraymap;
+ using arraymap::arraymap;
};
-// There is no internal linkage, but we still have primary key domain.
using namespace system;
using link5 = linkage<5>;
+using key1 = data_array<1>;
+using key10 = data_array<10>;
+
+// Key size does not factor into header byte size (for first key only).
+constexpr size_t header_size = 105;
+constexpr auto links = header_size / link5::size;
+static_assert(links == 21u);
+
+// Bucket count is one less than link count, due to header.size field.
+constexpr auto buckets = bc::sub1(links);
+static_assert(buckets == 20u);
+
struct slab0 { static constexpr size_t size = max_size_t; };
struct record4 { static constexpr size_t size = 4; };
-using slab_table = arraymap_;
-using record_table = arraymap_;
+using slab_table = arraymap_;
+using record_table = arraymap_;
-// record arraymap
+// record hashmap
// ----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(arraymap__record_construct__empty__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const record_table instance{ head_store, body_store };
- BOOST_REQUIRE(body_file.empty());
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ const record_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(body_store.buffer().empty());
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_construct__non_empty__expected)
{
constexpr auto body_size = 12345u;
- data_chunk head_file;
- data_chunk body_file(body_size);
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const record_table instance{ head_store, body_store };
- BOOST_REQUIRE_EQUAL(body_file.size(), body_size);
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ body_store.buffer().resize(body_size);
+ const record_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), body_size);
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_getter__terminal__false)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
////BOOST_REQUIRE(!instance.getter_(link5::terminal));
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_getter__empty__exhausted)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
////BOOST_REQUIRE(instance.getter_(0)->is_exhausted());
////BOOST_REQUIRE(instance.getter_(19)->is_exhausted());
BOOST_REQUIRE(!instance.get_fault());
}
-// slab arraymap
+BOOST_AUTO_TEST_CASE(arraymap__record_getter__empty__false)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+ ////BOOST_REQUIRE(!instance.getter_(key10{ 0x00 }));
+ ////BOOST_REQUIRE(!instance.getter_(key10{ 0x42 }));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+// slab hashmap
// ----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(arraymap__slab_construct__empty__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const slab_table instance{ head_store, body_store };
- BOOST_REQUIRE(body_file.empty());
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ const slab_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(body_store.buffer().empty());
BOOST_REQUIRE(!instance.get_fault());
}
-BOOST_AUTO_TEST_CASE(arraymap__slab_construct__non_empty__expected)
+BOOST_AUTO_TEST_CASE(arraymap__slab_construct__non_empty__expected_enabled)
{
constexpr auto body_size = 12345u;
- data_chunk head_file;
- data_chunk body_file(body_size);
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const slab_table instance{ head_store, body_store };
- BOOST_REQUIRE_EQUAL(body_file.size(), body_size);
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ body_store.buffer().resize(body_size);
+ const slab_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), body_size);
+ BOOST_REQUIRE(instance.enabled());
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_getter__terminal__false)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
////BOOST_REQUIRE(!instance.getter_(link5::terminal));
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_getter__empty__exhausted)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
////BOOST_REQUIRE(instance.getter_(0)->is_exhausted());
////BOOST_REQUIRE(instance.getter_(19)->is_exhausted());
BOOST_REQUIRE(!instance.get_fault());
}
-// push/found/at (protected interface positive tests)
-// ----------------------------------------------------------------------------
+BOOST_AUTO_TEST_CASE(arraymap__slab_getter__empty__false)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+ ////BOOST_REQUIRE(!instance.getter_(key10{ 0x00 }));
+ ////BOOST_REQUIRE(!instance.getter_(key10{ 0x42 }));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__enabled__non_empty_slab_zero_buckets__false)
+{
+ constexpr auto body_size = 12345u;
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ body_store.buffer().resize(body_size);
+ const slab_table instance{ head_store, body_store, 0 };
+ BOOST_REQUIRE(!instance.enabled());
+ BOOST_REQUIRE(!instance.get_fault());
+}
-////BOOST_AUTO_TEST_CASE(arraymap__record_readers__empty__expected)
-////{
-//// data_chunk head_file;
-//// data_chunk body_file;
-//// test::chunk_storage head_store{ head_file };
-//// test::chunk_storage body_store{ body_file };
-//// record_table instance{ head_store, body_store };
-////
-//// auto stream0 = instance.creater_();
-//// BOOST_REQUIRE_EQUAL(body_file.size(), record4::size);
-//// BOOST_REQUIRE(!stream0->is_exhausted());
-//// BOOST_REQUIRE(instance.getter_(0));
-//// stream0.reset();
-////
-//// auto stream1 = instance.creater_();
-//// BOOST_REQUIRE_EQUAL(body_file.size(), 2u * record4::size);
-//// BOOST_REQUIRE(!stream1->is_exhausted());
-//// BOOST_REQUIRE(instance.getter_(1));
-//// stream1.reset();
-////
-//// // Past end is valid pointer but exhausted stream.
-//// BOOST_REQUIRE(instance.getter_(2));
-//// BOOST_REQUIRE(instance.getter_(2)->is_exhausted());
-////
-//// // record (assumes zero fill)
-//// // =================================
-//// // 00000000 [0]
-//// // 00000000 [1]
-////}
-////
-////BOOST_AUTO_TEST_CASE(arraymap__slab_readers__empty__expected)
-////{
-//// data_chunk head_file;
-//// data_chunk body_file;
-//// test::chunk_storage head_store{ head_file };
-//// test::chunk_storage body_store{ body_file };
-//// slab_table instance{ head_store, body_store };
-////
-//// auto stream0 = instance.creater_(record4::size);
-//// BOOST_REQUIRE_EQUAL(body_file.size(), record4::size);
-//// BOOST_REQUIRE(!stream0->is_exhausted());
-//// BOOST_REQUIRE(instance.getter_(0));
-//// stream0.reset();
-////
-//// auto stream1 = instance.creater_(record4::size);
-//// BOOST_REQUIRE_EQUAL(body_file.size(), 2u * record4::size);
-//// BOOST_REQUIRE(!stream1->is_exhausted());
-//// BOOST_REQUIRE(instance.getter_(record4::size));
-//// stream1.reset();
-////
-//// // Past end is valid pointer but exhausted stream.
-//// BOOST_REQUIRE(instance.getter_(2u * record4::size));
-//// BOOST_REQUIRE(instance.getter_(2u * record4::size)->is_exhausted());
-////
-//// // record (assumes zero fill)
-//// // =================================
-//// // 00000000 [0]
-//// // 00000000 [1]
-////}
+BOOST_AUTO_TEST_CASE(arraymap__enabled__empty_slab_one_bucket__false)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, 1 };
+ BOOST_REQUIRE(!instance.enabled());
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__enabled__empty_slab_nonzero_buckets__true)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.enabled());
+ BOOST_REQUIRE(!instance.get_fault());
+}
// get/put
// ----------------------------------------------------------------------------
@@ -246,7 +207,7 @@ class little_record
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_little_endian(value);
return sink;
@@ -267,7 +228,7 @@ class big_record
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_big_endian(value);
return sink;
@@ -278,11 +239,9 @@ class big_record
BOOST_AUTO_TEST_CASE(arraymap__record_get__terminal__invalid)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const arraymap instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ const hashmap instance{ head_store, body_store, buckets };
little_record record{};
BOOST_REQUIRE(!instance.get(link5::terminal, record));
@@ -291,11 +250,9 @@ BOOST_AUTO_TEST_CASE(arraymap__record_get__terminal__invalid)
BOOST_AUTO_TEST_CASE(arraymap__record_get__empty__invalid)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const arraymap instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ const hashmap instance{ head_store, body_store, buckets };
little_record record{};
BOOST_REQUIRE(!instance.get(0, record));
@@ -305,10 +262,15 @@ BOOST_AUTO_TEST_CASE(arraymap__record_get__empty__invalid)
BOOST_AUTO_TEST_CASE(arraymap__record_get__populated__valid)
{
data_chunk head_file;
- data_chunk body_file{ 0x01, 0x02, 0x03, 0x04 };
+ data_chunk body_file
+ {
+ 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+ 0x01, 0x02, 0x03, 0x04
+ };
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- const arraymap instance{ head_store, body_store };
+ const hashmap instance{ head_store, body_store, buckets };
little_record record{};
BOOST_REQUIRE(instance.get(0, record));
@@ -316,61 +278,22 @@ BOOST_AUTO_TEST_CASE(arraymap__record_get__populated__valid)
BOOST_REQUIRE(!instance.get_fault());
}
-BOOST_AUTO_TEST_CASE(arraymap__record_put__get__expected)
+BOOST_AUTO_TEST_CASE(arraymap__record_put__multiple__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
- BOOST_REQUIRE(instance.put(big_record{ 0xa1b2c3d4_u32 }));
-
- big_record record{};
- BOOST_REQUIRE(instance.get(0, record));
- BOOST_REQUIRE_EQUAL(record.value, 0xa1b2c3d4_u32);
-
- const data_chunk expected_file{ 0xa1, 0xb2, 0xc3, 0xd4 };
- BOOST_REQUIRE_EQUAL(body_file, expected_file);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(arraymap__record_count__truncate__expected)
-{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
- BOOST_REQUIRE(instance.put(big_record{ 0xa1b2c3d4_u32 }));
- BOOST_REQUIRE(instance.put(big_record{ 0xa1b2c3d4_u32 }));
-
- const data_chunk expected_file1{ 0xa1, 0xb2, 0xc3, 0xd4, 0xa1, 0xb2, 0xc3, 0xd4 };
- const data_chunk expected_file2{ 0xa1, 0xb2, 0xc3, 0xd4 };
- BOOST_REQUIRE_EQUAL(instance.count(), 2u);
- BOOST_REQUIRE_EQUAL(body_file, expected_file1);
- BOOST_REQUIRE(instance.truncate(1));
- BOOST_REQUIRE_EQUAL(instance.count(), 1u);
- BOOST_REQUIRE_EQUAL(body_file, expected_file2);
- BOOST_REQUIRE(instance.truncate(0));
- BOOST_REQUIRE_EQUAL(instance.count(), 0u);
- BOOST_REQUIRE(body_file.empty());
- BOOST_REQUIRE(!instance.get_fault());
-}
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
-BOOST_AUTO_TEST_CASE(arraymap__record_put_link__multiple__expected)
-{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
+ constexpr key1 key1_big{ 0x41 };
+ constexpr key1 key1_little{ 0x42 };
link5 link{};
- BOOST_REQUIRE(instance.put_link(link, big_record{ 0xa1b2c3d4_u32 }));
+ BOOST_REQUIRE(instance.put_link(link, key1_big, big_record{ 0xa1b2c3d4_u32 }));
BOOST_REQUIRE(!link.is_terminal());
BOOST_REQUIRE_EQUAL(link, 0u);
- link = instance.put_link(little_record{ 0xa1b2c3d4_u32 });
+ link = instance.put_link(key1_little, little_record{ 0xa1b2c3d4_u32 });
BOOST_REQUIRE(!link.is_terminal());
BOOST_REQUIRE_EQUAL(link, 1u);
@@ -382,8 +305,18 @@ BOOST_AUTO_TEST_CASE(arraymap__record_put_link__multiple__expected)
BOOST_REQUIRE(instance.get(1, record2));
BOOST_REQUIRE_EQUAL(record2.value, 0xa1b2c3d4_u32);
- const data_chunk expected_file{ 0xa1, 0xb2, 0xc3, 0xd4, 0xd4, 0xc3, 0xb2, 0xa1 };
- BOOST_REQUIRE_EQUAL(body_file, expected_file);
+ // This expecatation relies on the fact of no hash table conflict between 0x41 and 0x42.
+ const data_chunk expected_file
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x41,
+ 0xa1, 0xb2, 0xc3, 0xd4,
+
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x42,
+ 0xd4, 0xc3, 0xb2, 0xa1
+ };
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_file);
BOOST_REQUIRE(!instance.get_fault());
}
@@ -391,7 +324,10 @@ class little_slab
{
public:
static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT { return sizeof(uint32_t); }
+ static constexpr link5 count() NOEXCEPT
+ {
+ return link5::size + array_count + sizeof(uint32_t);
+ }
bool from_data(database::reader& source) NOEXCEPT
{
@@ -399,7 +335,7 @@ class little_slab
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_little_endian(value);
return sink;
@@ -412,7 +348,10 @@ class big_slab
{
public:
static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT { return sizeof(uint32_t); }
+ static constexpr link5 count() NOEXCEPT
+ {
+ return link5::size + array_count + sizeof(uint32_t);
+ }
bool from_data(database::reader& source) NOEXCEPT
{
@@ -420,7 +359,7 @@ class big_slab
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_big_endian(value);
return sink;
@@ -429,74 +368,46 @@ class big_slab
uint32_t value{ 0 };
};
-BOOST_AUTO_TEST_CASE(arraymap__slab_put__get__expected)
+BOOST_AUTO_TEST_CASE(arraymap__slab_put__multiple__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
- BOOST_REQUIRE(instance.put(big_slab{ 0xa1b2c3d4_u32 }));
-
- big_slab slab{};
- BOOST_REQUIRE(instance.get(zero, slab));
- BOOST_REQUIRE_EQUAL(slab.value, 0xa1b2c3d4_u32);
-
- const data_chunk expected_file{ 0xa1, 0xb2, 0xc3, 0xd4 };
- BOOST_REQUIRE_EQUAL(body_file, expected_file);
- BOOST_REQUIRE(!instance.get_fault());
-}
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
-BOOST_AUTO_TEST_CASE(arraymap__slab_count__truncate__expected)
-{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
- BOOST_REQUIRE(instance.put(big_slab{ 0xa1b2c3d4_u32 }));
- BOOST_REQUIRE(instance.put(big_slab{ 0xa1b2c3d4_u32 }));
-
- const data_chunk expected_file1{ 0xa1, 0xb2, 0xc3, 0xd4, 0xa1, 0xb2, 0xc3, 0xd4 };
- const data_chunk expected_file2{ 0xa1, 0xb2, 0xc3, 0xd4 };
- BOOST_REQUIRE_EQUAL(instance.count(), 8u);
- BOOST_REQUIRE_EQUAL(body_file, expected_file1);
- BOOST_REQUIRE(instance.truncate(4));
- BOOST_REQUIRE_EQUAL(instance.count(), 4u);
- BOOST_REQUIRE_EQUAL(body_file, expected_file2);
- BOOST_REQUIRE(instance.truncate(0));
- BOOST_REQUIRE_EQUAL(instance.count(), 0u);
- BOOST_REQUIRE(body_file.empty());
- BOOST_REQUIRE(!instance.get_fault());
-}
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
-BOOST_AUTO_TEST_CASE(arraymap__slab_put_link__multiple__expected)
-{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
+ constexpr key1 key_big{ 0x41 };
+ constexpr key1 key_little{ 0x42 };
link5 link{};
- BOOST_REQUIRE(instance.put_link(link, big_slab{ 0xa1b2c3d4_u32 }));
+ BOOST_REQUIRE(instance.put_link(link, key_big, big_slab{ 0xa1b2c3d4_u32 }));
BOOST_REQUIRE(!link.is_terminal());
BOOST_REQUIRE_EQUAL(link, 0u);
- link = instance.put_link(little_slab{ 0xa1b2c3d4_u32 });
+ link = instance.put_link(key_little, little_slab{ 0xa1b2c3d4_u32 });
BOOST_REQUIRE(!link.is_terminal());
BOOST_REQUIRE_EQUAL(link, big_slab::count());
big_slab slab1{};
- BOOST_REQUIRE(instance.get(zero, slab1));
+ BOOST_REQUIRE(instance.get(0, slab1));
BOOST_REQUIRE_EQUAL(slab1.value, 0xa1b2c3d4_u32);
little_slab slab2{};
- BOOST_REQUIRE(instance.get(little_slab::count(), slab2));
+ BOOST_REQUIRE(instance.get(big_slab::count(), slab2));
BOOST_REQUIRE_EQUAL(slab2.value, 0xa1b2c3d4_u32);
- const data_chunk expected_file{ 0xa1, 0xb2, 0xc3, 0xd4, 0xd4, 0xc3, 0xb2, 0xa1 };
- BOOST_REQUIRE_EQUAL(body_file, expected_file);
+ // This expecatation relies on the fact of no hash table conflict between 0x41 and 0x42.
+ const data_chunk expected_file
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x41,
+ 0xa1, 0xb2, 0xc3, 0xd4,
+
+ 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x42,
+ 0xd4, 0xc3, 0xb2, 0xa1
+ };
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_file);
BOOST_REQUIRE(!instance.get_fault());
}
@@ -513,7 +424,7 @@ class record_excess
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_big_endian(value);
return sink;
@@ -524,26 +435,41 @@ class record_excess
BOOST_AUTO_TEST_CASE(arraymap__record_get__excess__false)
{
- data_chunk head_file;
- data_chunk body_file{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const arraymap instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
record_excess record{};
- BOOST_REQUIRE(!instance.get(zero, record));
+ BOOST_REQUIRE(!instance.get(0, record));
BOOST_REQUIRE(!instance.get_fault());
}
-BOOST_AUTO_TEST_CASE(arraymap__record_put_link__excess__false)
+BOOST_AUTO_TEST_CASE(arraymap__record_get_key__excess__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
- BOOST_REQUIRE(instance.put_link(record_excess{ 0xa1b2c3d4_u32 }).is_terminal());
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE_EQUAL(instance.get_key(0), key);
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_put__excess__false)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(instance.put_link(key, record_excess{ 0xa1b2c3d4_u32 }).is_terminal());
BOOST_REQUIRE(!instance.get_fault());
}
@@ -560,7 +486,7 @@ class slab_excess
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_big_endian(value);
return sink;
@@ -583,7 +509,7 @@ class file_excess
return source;
}
- bool to_data(database::flipper& sink) const NOEXCEPT
+ bool to_data(database::finalizer& sink) const NOEXCEPT
{
sink.write_big_endian(value);
return sink;
@@ -594,40 +520,510 @@ class file_excess
BOOST_AUTO_TEST_CASE(arraymap__slab_get__excess__true)
{
- data_chunk head_file;
- data_chunk body_file{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const arraymap instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
// Excess read allowed to eof here (reader has only knowledge of size).
- slab_excess record{};
- BOOST_REQUIRE(instance.get(zero, record));
+ slab_excess slab{};
+ BOOST_REQUIRE(instance.get(0, slab));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__slab_get_key__excess__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE_EQUAL(instance.get_key(0), key);
+ BOOST_REQUIRE_EQUAL(instance.get_key(10), key);
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_get__file_excess__false)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
+
+ // Excess read disallowed to here (past eof).
+ slab_excess slab{};
+ BOOST_REQUIRE(!instance.get(0, slab));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__slab_put__excess__false)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(instance.put_link(key, slab_excess{ 0xa1b2c3d4_u32 }).is_terminal());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_top__default__terminal)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+ BOOST_REQUIRE(instance.top(0).is_terminal());
+ BOOST_REQUIRE(instance.top(19).is_terminal());
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_top__past_end__terminal)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+ BOOST_REQUIRE(instance.top(20).is_terminal());
+ BOOST_REQUIRE(instance.top(21).is_terminal());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_top__existing__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ BOOST_REQUIRE(!instance.put_link({ 0x41 }, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link({ 0x42 }, big_record{ 0xa2b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link({ 0x43 }, big_record{ 0xa3b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.top(0).is_terminal());
+ BOOST_REQUIRE(instance.top(1).is_terminal());
+ BOOST_REQUIRE(instance.top(2).is_terminal());
+ BOOST_REQUIRE(instance.top(3).is_terminal());
+ BOOST_REQUIRE(instance.top(4).is_terminal());
+ BOOST_REQUIRE(instance.top(5).is_terminal());
+ BOOST_REQUIRE(instance.top(6).is_terminal());
+ BOOST_REQUIRE(instance.top(7).is_terminal());
+ BOOST_REQUIRE(instance.top(8).is_terminal());
+ BOOST_REQUIRE(instance.top(9).is_terminal());
+ BOOST_REQUIRE(instance.top(10).is_terminal());
+ BOOST_REQUIRE(instance.top(11).is_terminal());
+ BOOST_REQUIRE(instance.top(12).is_terminal());
+ BOOST_REQUIRE(instance.top(13).is_terminal());
+ BOOST_REQUIRE(instance.top(14).is_terminal());
+ BOOST_REQUIRE(instance.top(15).is_terminal());
+ BOOST_REQUIRE(instance.top(16).is_terminal());
+ BOOST_REQUIRE(instance.top(17).is_terminal());
+ BOOST_REQUIRE(!instance.top(18).is_terminal());
+ BOOST_REQUIRE(!instance.top(19).is_terminal());
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_exists__exists__true)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.exists(key));
+ BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(instance.exists(key));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__slab_exists__exists__true)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(!instance.exists(key));
+ BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(instance.exists(key));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_first__exists__true)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(instance.first(key).is_terminal());
+ const auto link = instance.put_link(key, big_record{ 0xa1b2c3d4_u32 });
+ BOOST_REQUIRE(!link.is_terminal());
+ BOOST_REQUIRE_EQUAL(instance.first(key), link);
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__slab_first__exists__true)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(instance.first(key).is_terminal());
+ const auto link = instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 });
+ BOOST_REQUIRE(!link.is_terminal());
+ BOOST_REQUIRE_EQUAL(instance.first(key), link);
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_it__exists__non_terminal)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key{ 0x41 };
+ BOOST_REQUIRE(instance.it(key).self().is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.it(key).self().is_terminal());
+
+ big_record record{};
+ BOOST_REQUIRE(instance.get(instance.it(key).self(), record));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__record_it__multiple__iterated)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, buckets };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key1 key_a{ 0xaa };
+ constexpr key1 key_b{ 0xbb };
+ constexpr key1 key_c{ 0xcc };
+
+ BOOST_REQUIRE(!instance.put_link(key_a, big_record{ 0x000000a1_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_a, big_record{ 0x000000a2_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_a, big_record{ 0x000000a3_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_b, big_record{ 0x000000b1_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_b, big_record{ 0x000000b2_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_b, big_record{ 0x000000b3_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_c, big_record{ 0x000000c1_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_c, big_record{ 0x000000c2_u32 }).is_terminal());
+ BOOST_REQUIRE(!instance.put_link(key_c, big_record{ 0x000000c3_u32 }).is_terminal());
+
+ auto it_a = instance.it(key_a);
+
+ big_record record{};
+ BOOST_REQUIRE(instance.get(it_a.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000a3_u32);
+ BOOST_REQUIRE(it_a.advance());
+ BOOST_REQUIRE(instance.get(it_a.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000a2_u32);
+ BOOST_REQUIRE(it_a.advance());
+ BOOST_REQUIRE(instance.get(it_a.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000a1_u32);
+ BOOST_REQUIRE(!it_a.advance());
+ BOOST_REQUIRE(!instance.get(it_a.self(), record));
+
+ auto it_b = instance.it(key_b);
+
+ BOOST_REQUIRE(instance.get(it_b.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000b3_u32);
+ BOOST_REQUIRE(it_b.advance());
+ BOOST_REQUIRE(instance.get(it_b.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000b2_u32);
+ BOOST_REQUIRE(it_b.advance());
+ BOOST_REQUIRE(instance.get(it_b.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000b1_u32);
+ BOOST_REQUIRE(!it_b.advance());
+ BOOST_REQUIRE(!instance.get(it_b.self(), record));
+
+ auto it_c = instance.it(key_c);
+
+ BOOST_REQUIRE(instance.get(it_c.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000c3_u32);
+ BOOST_REQUIRE(it_c.advance());
+ BOOST_REQUIRE(instance.get(it_c.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000c2_u32);
+ BOOST_REQUIRE(it_c.advance());
+ BOOST_REQUIRE(instance.get(it_c.self(), record));
+ BOOST_REQUIRE_EQUAL(record.value, 0x000000c1_u32);
+ BOOST_REQUIRE(!it_c.advance());
+ BOOST_REQUIRE(!instance.get(it_c.self(), record));
+ BOOST_REQUIRE(!instance.get_fault());
+
+ // [0000000000]
+ //[b] 0500000000
+ // ffffffffff
+ // ffffffffff
+ //[a] 0200000000
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ // ffffffffff
+ //[c] 0800000000
+ // ffffffffff
+ // ffffffffff
+ //==================
+ //[0] ffffffffff
+ // aa
+ // 000000a1
+ //
+ //[1] 0000000000
+ // aa
+ // 000000a2
+ //
+ //[2] 0100000000
+ // aa
+ // 000000a3
+ //
+ //[3] ffffffffff
+ // bb
+ // 000000b1
+ //
+ //[4] 0300000000
+ // bb
+ // 000000b2
+ //
+ //[5] 0400000000
+ // bb
+ // 000000b3
+ //
+ //[6] ffffffffff
+ // cc
+ // 000000c1
+ //
+ //[7] 0600000000
+ // cc
+ // 000000c2
+ //
+ //[8] 0700000000
+ // cc
+ // 000000c3
+}
+
+// mutiphase commit.
+// ----------------------------------------------------------------------------
+
+class flex_record
+{
+public:
+ static constexpr size_t size = sizeof(uint32_t);
+ static constexpr link5 count() NOEXCEPT { return 1; }
+
+ template
+ bool to_data(Sinker& sink) const NOEXCEPT
+ {
+ sink.write_little_endian(value);
+ return sink;
+ }
+
+ uint32_t value{ 0 };
+};
+
+class flex_slab
+{
+public:
+ static constexpr size_t size = max_size_t;
+ static constexpr link5 count() NOEXCEPT
+ {
+ return link5::size + array_count + sizeof(uint32_t);
+ }
+
+ template
+ bool to_data(Sinker& sink) const NOEXCEPT
+ {
+ sink.write_little_endian(value);
+ return sink;
+ }
+
+ uint32_t value{ 0 };
+};
+
+BOOST_AUTO_TEST_CASE(arraymap__set_commit__record__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr auto size = link5::size + array_count + flex_record::size;
+ const auto link = instance.set_link(flex_record{ 0x01020304_u32 });
+ BOOST_REQUIRE(!link.is_terminal());
+ BOOST_REQUIRE_EQUAL(link, 0u);
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.commit(link, key1));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__allocate_set_commit__record__expected)
+{
+ data_chunk head_file;
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr auto size = link5::size + array_count + flex_record::size;
+ const auto link = instance.allocate(1);
+ BOOST_REQUIRE_EQUAL(link, 0u);
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
+
+ BOOST_REQUIRE(instance.set(link, flex_record{ 0x01020304_u32 }));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.commit(link, key1));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__allocate_put1__record__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr auto size = link5::size + array_count + sizeof(uint32_t);
+ const auto link = instance.allocate(1);
+ BOOST_REQUIRE_EQUAL(link, 0u);
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.put(link, key1, flex_record{ 0x01020304_u32 }));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__allocate_put2__record__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.put(key1, flex_record{ 0x01020304_u32 }));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__set_commit_link__slab__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr auto size = link5::size + array_count + sizeof(uint32_t);
+ link5 link{};
+ BOOST_REQUIRE(instance.set_link(link, flex_slab{ 0x01020304_u32 }));
+ BOOST_REQUIRE(!link.is_terminal());
+ BOOST_REQUIRE_EQUAL(link, 0u);
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(!instance.commit_link(link, key1).is_terminal());
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__allocate_set_commit__slab__expected)
+{
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr auto size = link5::size + array_count + sizeof(uint32_t);
+ const auto link = instance.allocate(size);
+ BOOST_REQUIRE_EQUAL(link, 0u);
+ BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
+
+ BOOST_REQUIRE(instance.set(link, flex_slab{ 0x01020304_u32 }));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.commit(link, key1));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
+ BOOST_REQUIRE(!instance.get_fault());
+}
+
+BOOST_AUTO_TEST_CASE(arraymap__allocate_put1__slab__expected)
{
data_chunk head_file;
- data_chunk body_file{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+ data_chunk body_file;
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- const arraymap instance{ head_store, body_store };
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
- // Excess read disallowed to here (past eof).
- file_excess record{};
- BOOST_REQUIRE(!instance.get(zero, record));
+ constexpr auto size = link5::size + array_count + sizeof(uint32_t);
+ const auto link = instance.allocate(size);
+ BOOST_REQUIRE_EQUAL(link, 0u);
+ BOOST_REQUIRE_EQUAL(body_file.size(), size);
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.put(link, key1, flex_slab{ 0x01020304_u32 }));
+ BOOST_REQUIRE_EQUAL(head_file, base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_file, base16_chunk("ffffffffff0102030405060708090a04030201"));
BOOST_REQUIRE(!instance.get_fault());
}
-BOOST_AUTO_TEST_CASE(arraymap__slab_put_link__excess__false)
+BOOST_AUTO_TEST_CASE(arraymap__allocate_put2__slab__expected)
{
data_chunk head_file;
data_chunk body_file;
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- arraymap instance{ head_store, body_store };
- BOOST_REQUIRE(instance.put_link(slab_excess{ 0xa1b2c3d4_u32 }).is_terminal());
+ hashmap instance{ head_store, body_store, 2 };
+ BOOST_REQUIRE(instance.create());
+
+ constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
+ BOOST_REQUIRE(instance.put(key1, flex_slab{ 0x01020304_u32 }));
+ BOOST_REQUIRE_EQUAL(head_file, base16_chunk("00000000000000000000ffffffffff"));
+ BOOST_REQUIRE_EQUAL(body_file, base16_chunk("ffffffffff0102030405060708090a04030201"));
BOOST_REQUIRE(!instance.get_fault());
}
@@ -636,16 +1032,14 @@ BOOST_AUTO_TEST_CASE(arraymap__slab_put_link__excess__false)
BOOST_AUTO_TEST_CASE(arraymap__record_verify__empty_files__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(!instance.verify());
BOOST_REQUIRE(instance.create());
BOOST_REQUIRE(instance.verify());
- BOOST_REQUIRE_EQUAL(head_file.size(), link5::size);
- BOOST_REQUIRE(body_file.empty());
+ BOOST_REQUIRE_EQUAL(head_store.buffer().size(), header_size);
+ BOOST_REQUIRE(body_store.buffer().empty());
BOOST_REQUIRE(!instance.get_fault());
}
@@ -655,10 +1049,10 @@ BOOST_AUTO_TEST_CASE(arraymap__record_create__non_empty_head_file__failure)
data_chunk body_file;
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(!instance.verify());
BOOST_REQUIRE(!instance.create());
- BOOST_REQUIRE_EQUAL(head_file.size(), one);
+ BOOST_REQUIRE_EQUAL(head_file.size(), 1u);
BOOST_REQUIRE(body_file.empty());
BOOST_REQUIRE(!instance.get_fault());
}
@@ -669,24 +1063,21 @@ BOOST_AUTO_TEST_CASE(arraymap__record_create__non_empty_body_file__body_zeroed)
data_chunk body_file{ 0x42 };
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(!instance.verify());
BOOST_REQUIRE(instance.create());
BOOST_REQUIRE(instance.verify());
- BOOST_REQUIRE_EQUAL(head_file.size(), link5::size);
+ BOOST_REQUIRE_EQUAL(head_file.size(), header_size);
BOOST_REQUIRE(body_file.empty());
- BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_body_count__create__zero)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0000000000"));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
BOOST_REQUIRE(!instance.get_fault());
}
@@ -696,7 +1087,7 @@ BOOST_AUTO_TEST_CASE(arraymap__record_body_count__empty_close__zero)
data_chunk body_file;
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.close());
BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0000000000"));
BOOST_REQUIRE(!instance.get_fault());
@@ -704,58 +1095,50 @@ BOOST_AUTO_TEST_CASE(arraymap__record_body_count__empty_close__zero)
BOOST_AUTO_TEST_CASE(arraymap__record_body_count__two_close__two)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- body_file = base16_chunk("1234567812345678");
+ body_store.buffer() = base16_chunk("1122334455667788990011223344556677889911223344556677889900112233445566778899");
BOOST_REQUIRE(instance.close());
- BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0200000000"));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0200000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_body_count__two_backup__two)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- body_file = base16_chunk("1234567812345678");
+ body_store.buffer() = base16_chunk("1122334455667788990011223344556677889911223344556677889900112233445566778899");
BOOST_REQUIRE(instance.backup());
- BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0200000000"));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0200000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_body_count__empty_restore__truncates)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- body_file = base16_chunk("1234567812345678");
+ body_store.buffer() = base16_chunk("1234567812345678");
BOOST_REQUIRE(instance.restore());
- BOOST_REQUIRE(body_file.empty());
+ BOOST_REQUIRE(body_store.buffer().empty());
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__record_body_count__non_empty_restore__truncates)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- record_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ record_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- head_file = base16_chunk("0100000000");
- body_file = base16_chunk("1234567812345678");
+ head_store.buffer() = base16_chunk("0100000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ body_store.buffer() = base16_chunk("1122334455667788990011223344556677889911223344556677889900112233445566778899");
BOOST_REQUIRE(instance.restore());
- BOOST_REQUIRE_EQUAL(body_file, base16_chunk("12345678"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("11223344556677889900112233445566778899"));
BOOST_REQUIRE(!instance.get_fault());
}
@@ -764,16 +1147,14 @@ BOOST_AUTO_TEST_CASE(arraymap__record_body_count__non_empty_restore__truncates)
BOOST_AUTO_TEST_CASE(arraymap__slab_verify__empty_files__expected)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(!instance.verify());
BOOST_REQUIRE(instance.create());
BOOST_REQUIRE(instance.verify());
- BOOST_REQUIRE_EQUAL(head_file.size(), link5::size);
- BOOST_REQUIRE(body_file.empty());
+ BOOST_REQUIRE_EQUAL(head_store.buffer().size(), header_size);
+ BOOST_REQUIRE(body_store.buffer().empty());
BOOST_REQUIRE(!instance.get_fault());
}
@@ -783,10 +1164,10 @@ BOOST_AUTO_TEST_CASE(arraymap__slab_create__non_empty_head_file__failure)
data_chunk body_file;
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(!instance.verify());
BOOST_REQUIRE(!instance.create());
- BOOST_REQUIRE_EQUAL(head_file.size(), one);
+ BOOST_REQUIRE_EQUAL(head_file.size(), 1u);
BOOST_REQUIRE(body_file.empty());
BOOST_REQUIRE(!instance.get_fault());
}
@@ -797,24 +1178,22 @@ BOOST_AUTO_TEST_CASE(arraymap__slab_create__non_empty_body_file__body_zeroed)
data_chunk body_file{ 0x42 };
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(!instance.verify());
BOOST_REQUIRE(instance.create());
BOOST_REQUIRE(instance.verify());
- BOOST_REQUIRE_EQUAL(head_file.size(), link5::size);
+ BOOST_REQUIRE_EQUAL(head_file.size(), header_size);
BOOST_REQUIRE(body_file.empty());
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_body_count__create__zero)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0000000000"));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
BOOST_REQUIRE(!instance.get_fault());
}
@@ -824,66 +1203,62 @@ BOOST_AUTO_TEST_CASE(arraymap__slab_body_count__empty_close__zero)
data_chunk body_file;
test::chunk_storage head_store{ head_file };
test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.close());
BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0000000000"));
+ BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_body_count__two_close__two)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- body_file = base16_chunk("1234");
+ body_store.buffer() = base16_chunk("1234");
BOOST_REQUIRE(instance.close());
- BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0200000000"));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0200000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_body_count__two_backup__two)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- body_file = base16_chunk("1234");
+ body_store.buffer() = base16_chunk("1234");
BOOST_REQUIRE(instance.backup());
- BOOST_REQUIRE_EQUAL(head_file, base16_chunk("0200000000"));
+ BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0200000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_body_count__empty_restore__truncates)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- body_file = base16_chunk("1234567812345678");
+ body_store.buffer() = base16_chunk("1234567812345678");
BOOST_REQUIRE(instance.restore());
- BOOST_REQUIRE(body_file.empty());
+ BOOST_REQUIRE(body_store.buffer().empty());
BOOST_REQUIRE(!instance.get_fault());
}
BOOST_AUTO_TEST_CASE(arraymap__slab_body_count__non_empty_restore__truncates)
{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- slab_table instance{ head_store, body_store };
+ test::chunk_storage head_store{};
+ test::chunk_storage body_store{};
+ slab_table instance{ head_store, body_store, buckets };
BOOST_REQUIRE(instance.create());
- head_file = base16_chunk("0300000000");
- body_file = base16_chunk("1234567812345678");
+ head_store.buffer() = base16_chunk("0300000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ body_store.buffer() = base16_chunk("1234567812345678");
BOOST_REQUIRE(instance.restore());
- BOOST_REQUIRE_EQUAL(body_file, base16_chunk("123456"));
+ BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("123456"));
BOOST_REQUIRE(!instance.get_fault());
}
+////std::cout << head_file << std::endl << std::endl;
+////std::cout << body_file << std::endl << std::endl;
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/test/primitives/hashmap2.cpp b/test/primitives/hashmap2.cpp
deleted file mode 100644
index 5bccfe9c5..000000000
--- a/test/primitives/hashmap2.cpp
+++ /dev/null
@@ -1,1264 +0,0 @@
-/**
- * Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
- *
- * This file is part of libbitcoin.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-#include "../test.hpp"
-#include "../mocks/chunk_storage.hpp"
-
-BOOST_AUTO_TEST_SUITE(hashmap2_tests)
-
-template
-class hashmap_
- : public hashmap2
-{
-public:
- using base = hashmap2;
- using hashmap2::hashmap2;
-};
-
-using namespace system;
-using link5 = linkage<5>;
-using key1 = data_array<1>;
-using key10 = data_array<10>;
-
-// Key size does not factor into header byte size (for first key only).
-constexpr size_t header_size = 105;
-constexpr auto links = header_size / link5::size;
-static_assert(links == 21u);
-
-// Bucket count is one less than link count, due to header.size field.
-constexpr auto buckets = bc::sub1(links);
-static_assert(buckets == 20u);
-
-struct slab0 { static constexpr size_t size = max_size_t; };
-struct record4 { static constexpr size_t size = 4; };
-using slab_table = hashmap_;
-using record_table = hashmap_;
-
-// record hashmap
-// ----------------------------------------------------------------------------
-
-BOOST_AUTO_TEST_CASE(hashmap__record_construct__empty__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- const record_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(body_store.buffer().empty());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_construct__non_empty__expected)
-{
- constexpr auto body_size = 12345u;
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- body_store.buffer().resize(body_size);
- const record_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), body_size);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_getter__terminal__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- record_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- ////BOOST_REQUIRE(!instance.getter_(link5::terminal));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_getter__empty__exhausted)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- record_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- ////BOOST_REQUIRE(instance.getter_(0)->is_exhausted());
- ////BOOST_REQUIRE(instance.getter_(19)->is_exhausted());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_getter__empty__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- record_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- ////BOOST_REQUIRE(!instance.getter_(key10{ 0x00 }));
- ////BOOST_REQUIRE(!instance.getter_(key10{ 0x42 }));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-// slab hashmap
-// ----------------------------------------------------------------------------
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_construct__empty__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- const slab_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(body_store.buffer().empty());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_construct__non_empty__expected_enabled)
-{
- constexpr auto body_size = 12345u;
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- body_store.buffer().resize(body_size);
- const slab_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), body_size);
- BOOST_REQUIRE(instance.enabled());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_getter__terminal__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- slab_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- ////BOOST_REQUIRE(!instance.getter_(link5::terminal));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_getter__empty__exhausted)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- slab_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- ////BOOST_REQUIRE(instance.getter_(0)->is_exhausted());
- ////BOOST_REQUIRE(instance.getter_(19)->is_exhausted());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_getter__empty__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- slab_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- ////BOOST_REQUIRE(!instance.getter_(key10{ 0x00 }));
- ////BOOST_REQUIRE(!instance.getter_(key10{ 0x42 }));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__enabled__non_empty_slab_zero_buckets__false)
-{
- constexpr auto body_size = 12345u;
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- body_store.buffer().resize(body_size);
- const slab_table instance{ head_store, body_store, 0 };
- BOOST_REQUIRE(!instance.enabled());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__enabled__empty_slab_one_bucket__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- slab_table instance{ head_store, body_store, 1 };
- BOOST_REQUIRE(!instance.enabled());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__enabled__empty_slab_nonzero_buckets__true)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- slab_table instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.enabled());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-// get/put
-// ----------------------------------------------------------------------------
-
-class little_record
-{
-public:
- // record bytes or zero for slab (for template).
- static constexpr size_t size = sizeof(uint32_t);
-
- // record count or bytes count for slab (for allocate).
- static constexpr link5 count() NOEXCEPT { return 1; }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_little_endian();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_little_endian(value);
- return sink;
- }
-
- uint32_t value{ 0 };
-};
-
-class big_record
-{
-public:
- static constexpr size_t size = sizeof(uint32_t);
- static constexpr link5 count() NOEXCEPT { return 1; }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_big_endian();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_big_endian(value);
- return sink;
- }
-
- uint32_t value{ 0 };
-};
-
-BOOST_AUTO_TEST_CASE(hashmap__record_get__terminal__invalid)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- const hashmap instance{ head_store, body_store, buckets };
-
- little_record record{};
- BOOST_REQUIRE(!instance.get(link5::terminal, record));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_get__empty__invalid)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- const hashmap instance{ head_store, body_store, buckets };
-
- little_record record{};
- BOOST_REQUIRE(!instance.get(0, record));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_get__populated__valid)
-{
- data_chunk head_file;
- data_chunk body_file
- {
- 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
- 0x01, 0x02, 0x03, 0x04
- };
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- const hashmap instance{ head_store, body_store, buckets };
-
- little_record record{};
- BOOST_REQUIRE(instance.get(0, record));
- BOOST_REQUIRE_EQUAL(record.value, 0x04030201_u32);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_put__multiple__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key1_big{ 0x41 };
- constexpr key1 key1_little{ 0x42 };
-
- link5 link{};
- BOOST_REQUIRE(instance.put_link(link, key1_big, big_record{ 0xa1b2c3d4_u32 }));
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(link, 0u);
-
- link = instance.put_link(key1_little, little_record{ 0xa1b2c3d4_u32 });
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(link, 1u);
-
- big_record record1{};
- BOOST_REQUIRE(instance.get(0, record1));
- BOOST_REQUIRE_EQUAL(record1.value, 0xa1b2c3d4_u32);
-
- little_record record2{};
- BOOST_REQUIRE(instance.get(1, record2));
- BOOST_REQUIRE_EQUAL(record2.value, 0xa1b2c3d4_u32);
-
- // This expecatation relies on the fact of no hash table conflict between 0x41 and 0x42.
- const data_chunk expected_file
- {
- 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x41,
- 0xa1, 0xb2, 0xc3, 0xd4,
-
- 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x42,
- 0xd4, 0xc3, 0xb2, 0xa1
- };
- BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_file);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-class little_slab
-{
-public:
- static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT
- {
- return link5::size + array_count + sizeof(uint32_t);
- }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_little_endian();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_little_endian(value);
- return sink;
- }
-
- uint32_t value{ 0 };
-};
-
-class big_slab
-{
-public:
- static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT
- {
- return link5::size + array_count + sizeof(uint32_t);
- }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_big_endian();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_big_endian(value);
- return sink;
- }
-
- uint32_t value{ 0 };
-};
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_put__multiple__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
-
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key_big{ 0x41 };
- constexpr key1 key_little{ 0x42 };
-
- link5 link{};
- BOOST_REQUIRE(instance.put_link(link, key_big, big_slab{ 0xa1b2c3d4_u32 }));
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(link, 0u);
-
- link = instance.put_link(key_little, little_slab{ 0xa1b2c3d4_u32 });
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(link, big_slab::count());
-
- big_slab slab1{};
- BOOST_REQUIRE(instance.get(0, slab1));
- BOOST_REQUIRE_EQUAL(slab1.value, 0xa1b2c3d4_u32);
-
- little_slab slab2{};
- BOOST_REQUIRE(instance.get(big_slab::count(), slab2));
- BOOST_REQUIRE_EQUAL(slab2.value, 0xa1b2c3d4_u32);
-
- // This expecatation relies on the fact of no hash table conflict between 0x41 and 0x42.
- const data_chunk expected_file
- {
- 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x41,
- 0xa1, 0xb2, 0xc3, 0xd4,
-
- 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x42,
- 0xd4, 0xc3, 0xb2, 0xa1
- };
- BOOST_REQUIRE_EQUAL(body_store.buffer(), expected_file);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-// advertises 32 but reads/writes 64
-class record_excess
-{
-public:
- static constexpr size_t size = sizeof(uint32_t);
- static constexpr link5 count() NOEXCEPT { return 1; }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_big_endian();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_big_endian(value);
- return sink;
- }
-
- uint64_t value{ 0 };
-};
-
-BOOST_AUTO_TEST_CASE(hashmap__record_get__excess__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
-
- record_excess record{};
- BOOST_REQUIRE(!instance.get(0, record));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_get_key__excess__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE_EQUAL(instance.get_key(0), key);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_put__excess__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(instance.put_link(key, record_excess{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-// advertises 32 but reads/writes 64
-class slab_excess
-{
-public:
- static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT { return sizeof(uint32_t); }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_big_endian();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_big_endian(value);
- return sink;
- }
-
- uint64_t value{ 0 };
-};
-
-// advertises 32 but reads 65 (file is 64)/writes 64
-class file_excess
-{
-public:
- static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT { return sizeof(uint32_t); }
-
- bool from_data(database::reader& source) NOEXCEPT
- {
- value = source.read_big_endian();
- source.read_byte();
- return source;
- }
-
- bool to_data(database::finalizer& sink) const NOEXCEPT
- {
- sink.write_big_endian(value);
- return sink;
- }
-
- uint64_t value{ 0 };
-};
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_get__excess__true)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
-
- // Excess read allowed to eof here (reader has only knowledge of size).
- slab_excess slab{};
- BOOST_REQUIRE(instance.get(0, slab));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_get_key__excess__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE_EQUAL(instance.get_key(0), key);
- BOOST_REQUIRE_EQUAL(instance.get_key(10), key);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_get__file_excess__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
-
- // Excess read disallowed to here (past eof).
- slab_excess slab{};
- BOOST_REQUIRE(!instance.get(0, slab));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_put__excess__false)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(instance.put_link(key, slab_excess{ 0xa1b2c3d4_u32 }).is_terminal());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_top__default__terminal)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- BOOST_REQUIRE(instance.top(0).is_terminal());
- BOOST_REQUIRE(instance.top(19).is_terminal());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_top__past_end__terminal)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
- BOOST_REQUIRE(instance.top(20).is_terminal());
- BOOST_REQUIRE(instance.top(21).is_terminal());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_top__existing__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- BOOST_REQUIRE(!instance.put_link({ 0x41 }, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link({ 0x42 }, big_record{ 0xa2b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link({ 0x43 }, big_record{ 0xa3b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.top(0).is_terminal());
- BOOST_REQUIRE(instance.top(1).is_terminal());
- BOOST_REQUIRE(instance.top(2).is_terminal());
- BOOST_REQUIRE(instance.top(3).is_terminal());
- BOOST_REQUIRE(instance.top(4).is_terminal());
- BOOST_REQUIRE(instance.top(5).is_terminal());
- BOOST_REQUIRE(instance.top(6).is_terminal());
- BOOST_REQUIRE(instance.top(7).is_terminal());
- BOOST_REQUIRE(instance.top(8).is_terminal());
- BOOST_REQUIRE(instance.top(9).is_terminal());
- BOOST_REQUIRE(instance.top(10).is_terminal());
- BOOST_REQUIRE(instance.top(11).is_terminal());
- BOOST_REQUIRE(instance.top(12).is_terminal());
- BOOST_REQUIRE(instance.top(13).is_terminal());
- BOOST_REQUIRE(instance.top(14).is_terminal());
- BOOST_REQUIRE(instance.top(15).is_terminal());
- BOOST_REQUIRE(instance.top(16).is_terminal());
- BOOST_REQUIRE(instance.top(17).is_terminal());
- BOOST_REQUIRE(!instance.top(18).is_terminal());
- BOOST_REQUIRE(!instance.top(19).is_terminal());
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_exists__exists__true)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.exists(key));
- BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(instance.exists(key));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_exists__exists__true)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(!instance.exists(key));
- BOOST_REQUIRE(!instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(instance.exists(key));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_first__exists__true)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(instance.first(key).is_terminal());
- const auto link = instance.put_link(key, big_record{ 0xa1b2c3d4_u32 });
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(instance.first(key), link);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__slab_first__exists__true)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(instance.first(key).is_terminal());
- const auto link = instance.put_link(key, big_slab{ 0xa1b2c3d4_u32 });
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(instance.first(key), link);
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_it__exists__non_terminal)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key{ 0x41 };
- BOOST_REQUIRE(instance.it(key).self().is_terminal());
- BOOST_REQUIRE(!instance.put_link(key, big_record{ 0xa1b2c3d4_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.it(key).self().is_terminal());
-
- big_record record{};
- BOOST_REQUIRE(instance.get(instance.it(key).self(), record));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__record_it__multiple__iterated)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, buckets };
- BOOST_REQUIRE(instance.create());
-
- constexpr key1 key_a{ 0xaa };
- constexpr key1 key_b{ 0xbb };
- constexpr key1 key_c{ 0xcc };
-
- BOOST_REQUIRE(!instance.put_link(key_a, big_record{ 0x000000a1_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_a, big_record{ 0x000000a2_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_a, big_record{ 0x000000a3_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_b, big_record{ 0x000000b1_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_b, big_record{ 0x000000b2_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_b, big_record{ 0x000000b3_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_c, big_record{ 0x000000c1_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_c, big_record{ 0x000000c2_u32 }).is_terminal());
- BOOST_REQUIRE(!instance.put_link(key_c, big_record{ 0x000000c3_u32 }).is_terminal());
-
- auto it_a = instance.it(key_a);
-
- big_record record{};
- BOOST_REQUIRE(instance.get(it_a.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000a3_u32);
- BOOST_REQUIRE(it_a.advance());
- BOOST_REQUIRE(instance.get(it_a.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000a2_u32);
- BOOST_REQUIRE(it_a.advance());
- BOOST_REQUIRE(instance.get(it_a.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000a1_u32);
- BOOST_REQUIRE(!it_a.advance());
- BOOST_REQUIRE(!instance.get(it_a.self(), record));
-
- auto it_b = instance.it(key_b);
-
- BOOST_REQUIRE(instance.get(it_b.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000b3_u32);
- BOOST_REQUIRE(it_b.advance());
- BOOST_REQUIRE(instance.get(it_b.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000b2_u32);
- BOOST_REQUIRE(it_b.advance());
- BOOST_REQUIRE(instance.get(it_b.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000b1_u32);
- BOOST_REQUIRE(!it_b.advance());
- BOOST_REQUIRE(!instance.get(it_b.self(), record));
-
- auto it_c = instance.it(key_c);
-
- BOOST_REQUIRE(instance.get(it_c.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000c3_u32);
- BOOST_REQUIRE(it_c.advance());
- BOOST_REQUIRE(instance.get(it_c.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000c2_u32);
- BOOST_REQUIRE(it_c.advance());
- BOOST_REQUIRE(instance.get(it_c.self(), record));
- BOOST_REQUIRE_EQUAL(record.value, 0x000000c1_u32);
- BOOST_REQUIRE(!it_c.advance());
- BOOST_REQUIRE(!instance.get(it_c.self(), record));
- BOOST_REQUIRE(!instance.get_fault());
-
- // [0000000000]
- //[b] 0500000000
- // ffffffffff
- // ffffffffff
- //[a] 0200000000
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- // ffffffffff
- //[c] 0800000000
- // ffffffffff
- // ffffffffff
- //==================
- //[0] ffffffffff
- // aa
- // 000000a1
- //
- //[1] 0000000000
- // aa
- // 000000a2
- //
- //[2] 0100000000
- // aa
- // 000000a3
- //
- //[3] ffffffffff
- // bb
- // 000000b1
- //
- //[4] 0300000000
- // bb
- // 000000b2
- //
- //[5] 0400000000
- // bb
- // 000000b3
- //
- //[6] ffffffffff
- // cc
- // 000000c1
- //
- //[7] 0600000000
- // cc
- // 000000c2
- //
- //[8] 0700000000
- // cc
- // 000000c3
-}
-
-// mutiphase commit.
-// ----------------------------------------------------------------------------
-
-class flex_record
-{
-public:
- static constexpr size_t size = sizeof(uint32_t);
- static constexpr link5 count() NOEXCEPT { return 1; }
-
- template
- bool to_data(Sinker& sink) const NOEXCEPT
- {
- sink.write_little_endian(value);
- return sink;
- }
-
- uint32_t value{ 0 };
-};
-
-class flex_slab
-{
-public:
- static constexpr size_t size = max_size_t;
- static constexpr link5 count() NOEXCEPT
- {
- return link5::size + array_count + sizeof(uint32_t);
- }
-
- template
- bool to_data(Sinker& sink) const NOEXCEPT
- {
- sink.write_little_endian(value);
- return sink;
- }
-
- uint32_t value{ 0 };
-};
-
-BOOST_AUTO_TEST_CASE(hashmap__set_commit__record__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, 2 };
- BOOST_REQUIRE(instance.create());
-
- constexpr auto size = link5::size + array_count + flex_record::size;
- const auto link = instance.set_link(flex_record{ 0x01020304_u32 });
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(link, 0u);
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
-
- constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
- BOOST_REQUIRE(instance.commit(link, key1));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__allocate_set_commit__record__expected)
-{
- data_chunk head_file;
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, 2 };
- BOOST_REQUIRE(instance.create());
-
- constexpr auto size = link5::size + array_count + flex_record::size;
- const auto link = instance.allocate(1);
- BOOST_REQUIRE_EQUAL(link, 0u);
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
-
- BOOST_REQUIRE(instance.set(link, flex_record{ 0x01020304_u32 }));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
-
- constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
- BOOST_REQUIRE(instance.commit(link, key1));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__allocate_put1__record__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, 2 };
- BOOST_REQUIRE(instance.create());
-
- constexpr auto size = link5::size + array_count + sizeof(uint32_t);
- const auto link = instance.allocate(1);
- BOOST_REQUIRE_EQUAL(link, 0u);
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
-
- constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
- BOOST_REQUIRE(instance.put(link, key1, flex_record{ 0x01020304_u32 }));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__allocate_put2__record__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, 2 };
- BOOST_REQUIRE(instance.create());
-
- constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
- BOOST_REQUIRE(instance.put(key1, flex_record{ 0x01020304_u32 }));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__set_commit_link__slab__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, 2 };
- BOOST_REQUIRE(instance.create());
-
- constexpr auto size = link5::size + array_count + sizeof(uint32_t);
- link5 link{};
- BOOST_REQUIRE(instance.set_link(link, flex_slab{ 0x01020304_u32 }));
- BOOST_REQUIRE(!link.is_terminal());
- BOOST_REQUIRE_EQUAL(link, 0u);
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
-
- constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
- BOOST_REQUIRE(!instance.commit_link(link, key1).is_terminal());
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__allocate_set_commit__slab__expected)
-{
- test::chunk_storage head_store{};
- test::chunk_storage body_store{};
- hashmap instance{ head_store, body_store, 2 };
- BOOST_REQUIRE(instance.create());
-
- constexpr auto size = link5::size + array_count + sizeof(uint32_t);
- const auto link = instance.allocate(size);
- BOOST_REQUIRE_EQUAL(link, 0u);
- BOOST_REQUIRE_EQUAL(body_store.buffer().size(), size);
-
- BOOST_REQUIRE(instance.set(link, flex_slab{ 0x01020304_u32 }));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("0000000000ffffffffffffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("00000000000000000000000000000004030201"));
-
- constexpr key10 key1{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a };
- BOOST_REQUIRE(instance.commit(link, key1));
- BOOST_REQUIRE_EQUAL(head_store.buffer(), base16_chunk("00000000000000000000ffffffffff"));
- BOOST_REQUIRE_EQUAL(body_store.buffer(), base16_chunk("ffffffffff0102030405060708090a04030201"));
- BOOST_REQUIRE(!instance.get_fault());
-}
-
-BOOST_AUTO_TEST_CASE(hashmap__allocate_put1__slab__expected)
-{
- data_chunk head_file;
- data_chunk body_file;
- test::chunk_storage head_store{ head_file };
- test::chunk_storage body_store{ body_file };
- hashmap