Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions include/bitcoin/database/impl/primitives/arrayhead.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,20 @@ bool CLASS::enabled() const NOEXCEPT
}

TEMPLATE
Link CLASS::index(const Key& key) const NOEXCEPT
Link CLASS::index(size_t key) const NOEXCEPT
{
// Key is the logical bucket index (no-hash).
if (key < buckets())
return manager<Link, system::data_array<zero>, Link::size>::
cast_link(key);
if (key >= buckets())
return {};

return {};
// Put index does not validate, allowing for head expansion.
return putter_index(key);
}

TEMPLATE
Link CLASS::putter_index(size_t key) const NOEXCEPT
{
// Key is the logical bucket index (no-hash).
return body::cast_link(key);
}

TEMPLATE
Expand Down Expand Up @@ -117,15 +123,13 @@ bool CLASS::set_body_count(const Link& count) NOEXCEPT
}

TEMPLATE
Link CLASS::top(const Key& key) const NOEXCEPT
Link CLASS::at(size_t key) const NOEXCEPT
{
return top(index(key));
}
const auto link = index(key);
if (link.is_terminal())
return {};

TEMPLATE
Link CLASS::top(const Link& index) const NOEXCEPT
{
const auto ptr = file_.get(link_to_position(index));
const auto ptr = file_.get(link_to_position(link));
if (is_null(ptr))
return {};

Expand Down
34 changes: 10 additions & 24 deletions include/bitcoin/database/impl/primitives/arraymap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -129,62 +129,48 @@ code CLASS::reload() NOEXCEPT
// ----------------------------------------------------------------------------

TEMPLATE
Link CLASS::top(const Link& link) const NOEXCEPT
bool CLASS::exists(size_t key) const NOEXCEPT
{
if (link >= head_.buckets())
return {};

return head_.top(link);
return !at(key).is_terminal();
}

TEMPLATE
bool CLASS::exists(const Key& key) const NOEXCEPT
Link CLASS::at(size_t key) const NOEXCEPT
{
return !first(key).is_terminal();
}

TEMPLATE
Link CLASS::first(const Key& key) const NOEXCEPT
{
return head_.top(key);
return head_.at(key);
}

TEMPLATE
template <typename Element, if_equal<Element::size, Size>>
bool CLASS::find(const Key& key, Element& element) const NOEXCEPT
bool CLASS::at(size_t key, Element& element) const NOEXCEPT
{
// This override avoids duplicated memory_ptr construct in get(first()).
const auto ptr = body_.get();
return read(ptr, first(ptr, head_.top(key), key), element);
return get(at(key), element);
}

TEMPLATE
template <typename Element, if_equal<Element::size, Size>>
bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
{
// This override is the normal form.
return read(body_.get(), link, element);
}

TEMPLATE
template <typename Element, if_equal<Element::size, Size>>
bool CLASS::put(const Key& key, const Element& element) NOEXCEPT
bool CLASS::put(size_t key, const Element& element) NOEXCEPT
{
using namespace system;
const auto count = element.count();
const auto link = allocate(count);
const auto link = body_.allocate(count);
const auto ptr = body_.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);

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) && head_.push(link, head_.putter_index(key));
}

// protected
Expand All @@ -195,10 +181,10 @@ template <typename Element, if_equal<Element::size, Size>>
bool CLASS::read(const memory_ptr& ptr, const Link& link,
Element& element) NOEXCEPT
{
using namespace system;
if (!ptr || link.is_terminal())
return false;

using namespace system;
const auto start = body::link_to_position(link);
if (is_limited<ptrdiff_t>(start))
return false;
Expand Down
20 changes: 13 additions & 7 deletions include/bitcoin/database/primitives/arrayhead.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace database {

/// Dynamically expanding array map header.
/// Less efficient than a fixed-size header.
template <typename Link, typename Key = size_t>
template <typename Link>
class arrayhead
{
public:
Expand Down Expand Up @@ -57,15 +57,21 @@ class arrayhead
bool get_body_count(Link& count) const NOEXCEPT;
bool set_body_count(const Link& count) NOEXCEPT;

/// Convert natural key to head bucket index.
Link index(const Key& key) const NOEXCEPT;
/// Convert natural key to head bucket index (validated).
Link index(size_t key) const NOEXCEPT;

/// Convert natural key to head bucket index (unvalidated).
Link putter_index(size_t key) const NOEXCEPT;

/// Unsafe if verify false.
Link top(const Key& key) const NOEXCEPT;
Link top(const Link& index) const NOEXCEPT;
Link at(size_t key) const NOEXCEPT;

/// Assign value to bucket index.
bool push(const bytes& current, const Link& index) NOEXCEPT;

private:
using body = manager<Link, system::data_array<zero>, Link::size>;

template <size_t Bytes>
static auto& array_cast(memory::iterator buffer) NOEXCEPT
{
Expand Down Expand Up @@ -98,8 +104,8 @@ class arrayhead
} // namespace database
} // namespace libbitcoin

#define TEMPLATE template <typename Link, typename Key>
#define CLASS arrayhead<Link, Key>
#define TEMPLATE template <typename Link>
#define CLASS arrayhead<Link>

#include <bitcoin/database/impl/primitives/arrayhead.ipp>

Expand Down
26 changes: 10 additions & 16 deletions include/bitcoin/database/primitives/arraymap.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,13 @@ namespace database {
/// 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 <typename Link, typename Key, size_t Size>
template <typename Link, size_t Size>
class arraymap
{
public:
DEFAULT_COPY_MOVE_DESTRUCT(arraymap);

using key = Key;
using link = Link;
using iterator = database::iterator<Link, Key, Size>;

arraymap(storage& header, storage& body, const Link& buckets) NOEXCEPT;

Expand Down Expand Up @@ -89,18 +87,15 @@ class arraymap
/// Query interface, iterator is not thread safe.
/// -----------------------------------------------------------------------

/// 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;
bool exists(size_t key) const NOEXCEPT;

/// Return first element link or terminal if not found/error.
Link first(const Key& key) const NOEXCEPT;
/// Return element link at key or terminal if not found/error.
Link at(size_t key) const NOEXCEPT;

/// Get first element matching the search key, false if not found/error.
template <typename Element, if_equal<Element::size, Size> = true>
bool find(const Key& key, Element& element) const NOEXCEPT;
bool at(size_t key, Element& element) const NOEXCEPT;

/// Get element at link, false if deserialize error.
template <typename Element, if_equal<Element::size, Size> = true>
Expand All @@ -109,7 +104,7 @@ class arraymap
/// Allocate, set, commit element to key.
/// Expands table AND HEADER as necessary.
template <typename Element, if_equal<Element::size, Size> = true>
bool put(const Key& key, const Element& element) NOEXCEPT;
bool put(size_t key, const Element& element) NOEXCEPT;

protected:
/// Get element at link using memory object, false if deserialize error.
Expand All @@ -121,7 +116,7 @@ class arraymap
static constexpr auto is_slab = (Size == max_size_t);

using head = database::arrayhead<Link>;
using body = database::manager<Link, Key, Size>;
using body = database::manager<Link, system::data_array<0>, Size>;

// Thread safe (index/top/push).
// Not thread safe (create/open/close/backup/restore).
Expand All @@ -132,14 +127,13 @@ class arraymap
};

template <typename Element>
using array_map = arraymap<linkage<Element::pk>, system::data_array<Element::sk>,
Element::size>;
using array_map = arraymap<linkage<Element::pk>, Element::size>;

} // namespace database
} // namespace libbitcoin

#define TEMPLATE template <typename Link, typename Key, size_t Size>
#define CLASS arraymap<Link, Key, Size>
#define TEMPLATE template <typename Link, size_t Size>
#define CLASS arraymap<Link, Size>

#include <bitcoin/database/impl/primitives/arraymap.ipp>

Expand Down
2 changes: 1 addition & 1 deletion include/bitcoin/database/tables/schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ namespace schema
struct prevout
{
static constexpr size_t pk = schema::spend_;
static constexpr size_t sk = zero;
////static constexpr size_t sk = zero;
static constexpr size_t minsize =
schema::bit + // TODO: merge bit.
schema::spend_ +
Expand Down
22 changes: 14 additions & 8 deletions test/mocks/chunk_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,20 @@ size_t chunk_storage::allocate(size_t chunk) NOEXCEPT
memory_ptr chunk_storage::set(size_t offset, size_t size,
uint8_t backfill) NOEXCEPT
{
std::unique_lock field_lock(field_mutex_);
if (system::is_add_overflow(offset, size))
return {};

std::unique_lock map_lock(map_mutex_);
const auto minimum = offset + size;
if (minimum > buffer_.size())
buffer_.resize(minimum, backfill);
{
std::unique_lock field_lock(field_mutex_);
if (system::is_add_overflow(offset, size))
{
return {};
}
else
{
std::unique_lock map_lock(map_mutex_);
const auto minimum = offset + size;
if (minimum > buffer_.size())
buffer_.resize(minimum, backfill);
}
}

return get(offset);
}
Expand Down
22 changes: 3 additions & 19 deletions test/primitives/arrayhead.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ constexpr auto buckets = sub1(links);
static_assert(buckets == 20u);

using link = linkage<link_size>;
using test_header = arrayhead<link, size_t>;
using test_header = arrayhead<link>;

class nullptr_storage
: public test::chunk_storage
Expand Down Expand Up @@ -103,30 +103,14 @@ BOOST_AUTO_TEST_CASE(arrayhead__set_body_count__get__expected)
BOOST_REQUIRE_EQUAL(count, expected);
}

BOOST_AUTO_TEST_CASE(arrayhead__top__link__terminal)
{
test::chunk_storage store;
test_header head{ store, buckets };
BOOST_REQUIRE(head.create());
BOOST_REQUIRE(head.top(9).is_terminal());
}

BOOST_AUTO_TEST_CASE(arrayhead__top__nullptr__terminal)
{
nullptr_storage store;
test_header head{ store, buckets };
BOOST_REQUIRE(head.create());
BOOST_REQUIRE(head.top(9).is_terminal());
}

BOOST_AUTO_TEST_CASE(arrayhead__top__key__terminal)
BOOST_AUTO_TEST_CASE(arrayhead__at__key__terminal)
{
test::chunk_storage store;
test_header head{ store, buckets };

// create() allocates and fills buckets with terminal.
BOOST_REQUIRE(head.create());
BOOST_REQUIRE(head.top(zero).is_terminal());
BOOST_REQUIRE(head.at(zero).is_terminal());
}

BOOST_AUTO_TEST_SUITE_END()
Loading
Loading