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
146 changes: 140 additions & 6 deletions include/bitcoin/database/impl/query/optional.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,85 @@ namespace database {

// Address (natural-keyed).
// ----------------------------------------------------------------------------
// Pushing into vectors is more efficient than precomputation of size.

// private/static
TEMPLATE
code CLASS::get_address_outputs(const std::atomic_bool& cancel,
template <typename Functor>
inline code CLASS::parallel_address_transform(const std::atomic_bool& cancel,
outpoints& out, const output_links& links, Functor&& functor) NOEXCEPT
{
constexpr auto parallel = poolstl::execution::par;

std::atomic_bool fail{};
std::vector<outpoint> outpoints(links.size());
std::transform(parallel, links.begin(), links.end(), outpoints.begin(),
[&functor, &fail](const auto& link) NOEXCEPT
{
return functor(link, fail);
});

out.clear();
if (fail) return error::integrity;
if (cancel) return error::canceled;
for (auto& outpoint: outpoints)
{
if (cancel) return error::canceled;
if (outpoint.point().index() != point::null_index)
out.insert(std::move(outpoint));
}

return error::success;
}

// protected
TEMPLATE
code CLASS::to_address_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT
{
// Pushing into the vector is more efficient than precomputation of size.
out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
if (cancel)
return error::canceled;

table::address::record address{};
if (!store_.address.get(it, address))
return error::integrity;

out.push_back(address.output_fk);
}

return error::success;
}

// protected
TEMPLATE
code CLASS::get_address_outputs_turbo(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_address_transform(cancel, out, links,
[this, &cancel](const auto& link, auto& fail) NOEXCEPT
{
if (cancel || fail) return outpoint{};
auto outpoint = get_spent(link);
fail = (outpoint.point().index() == point::null_index);
return outpoint;
});
}

TEMPLATE
code CLASS::get_address_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
{
if (turbo && store_.turbo())
return get_address_outputs_turbo(cancel, out, key);

out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
Expand All @@ -55,10 +128,35 @@ code CLASS::get_address_outputs(const std::atomic_bool& cancel,
return error::success;
}

// protected
TEMPLATE
code CLASS::get_confirmed_unspent_outputs(const std::atomic_bool& cancel,
code CLASS::get_confirmed_unspent_outputs_turbo(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_address_transform(cancel, out, links,
[this, &cancel](const auto& link, auto& fail) NOEXCEPT
{
if (cancel || fail || !is_confirmed_unspent(link))
return outpoint{};

auto outpoint = get_spent(link);
fail = (outpoint.point().index() == point::null_index);
return outpoint;
});
}

TEMPLATE
code CLASS::get_confirmed_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, bool turbo) const NOEXCEPT
{
if (turbo && store_.turbo())
return get_confirmed_unspent_outputs_turbo(cancel, out, key);

out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
Expand All @@ -76,10 +174,46 @@ code CLASS::get_confirmed_unspent_outputs(const std::atomic_bool& cancel,
return error::success;
}

// protected
TEMPLATE
code CLASS::get_minimum_unspent_outputs(const std::atomic_bool& cancel,
code CLASS::get_minimum_unspent_outputs_turbo(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT
{
out.clear();
output_links links{};
if (const code ec = to_address_outputs(cancel, links, key))
return ec;

return parallel_address_transform(cancel, out, links,
[this, &cancel, minimum](const auto& link, auto& fail) NOEXCEPT
{
if (cancel || fail || !is_confirmed_unspent(link))
return outpoint{};

uint64_t value{};
if (!get_value(value, link))
{
fail = true;
return outpoint{};
}

if (value < minimum)
return outpoint{};

auto outpoint = get_spent(link);
fail = (outpoint.point().index() == point::null_index);
return outpoint;
});
}

TEMPLATE
code CLASS::get_minimum_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key,
uint64_t minimum, bool turbo) const NOEXCEPT
{
if (turbo && store_.turbo())
return get_minimum_unspent_outputs_turbo(cancel, out, key, minimum);

out.clear();
for (auto it = store_.address.it(key); it; ++it)
{
Expand All @@ -106,10 +240,10 @@ code CLASS::get_minimum_unspent_outputs(const std::atomic_bool& cancel,

TEMPLATE
code CLASS::get_confirmed_balance(const std::atomic_bool& cancel,
uint64_t& balance, const hash_digest& key) const NOEXCEPT
uint64_t& balance, const hash_digest& key, bool turbo) const NOEXCEPT
{
outpoints outs{};
if (code ec = get_confirmed_unspent_outputs(cancel, outs, key))
if (code ec = get_confirmed_unspent_outputs(cancel, outs, key, turbo))
{
balance = zero;
return ec;
Expand Down
6 changes: 6 additions & 0 deletions include/bitcoin/database/impl/store.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ CLASS::store(const settings& config) NOEXCEPT
{
}

TEMPLATE
bool CLASS::turbo() const NOEXCEPT
{
return configuration_.turbo;
}

TEMPLATE
code CLASS::create(const event_handler& handler) NOEXCEPT
{
Expand Down
27 changes: 23 additions & 4 deletions include/bitcoin/database/query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ class query
point_link top_point(size_t bucket) const NOEXCEPT;
tx_link top_tx(size_t bucket) const NOEXCEPT;

/// optional enumeration
code to_address_outputs(const std::atomic_bool& cancel,
output_links& out, const hash_digest& key) const NOEXCEPT;

/// Archive reads.
/// -----------------------------------------------------------------------

Expand Down Expand Up @@ -550,13 +554,14 @@ class query
/// -----------------------------------------------------------------------

code get_address_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
outpoints& out, const hash_digest& key, bool turbo=false) const NOEXCEPT;
code get_confirmed_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
outpoints& out, const hash_digest& key, bool turbo=false) const NOEXCEPT;
code get_minimum_unspent_outputs(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, uint64_t value) const NOEXCEPT;
outpoints& out, const hash_digest& key, uint64_t value,
bool turbo=false) const NOEXCEPT;
code get_confirmed_balance(const std::atomic_bool& cancel,
uint64_t& balance, const hash_digest& key) const NOEXCEPT;
uint64_t& balance, const hash_digest& key, bool turbo=false) const NOEXCEPT;

bool is_filtered_body(const header_link& link) const NOEXCEPT;
bool get_filter_body(filter& out, const header_link& link) const NOEXCEPT;
Expand Down Expand Up @@ -687,6 +692,16 @@ class query
const system::settings& settings, const header& header,
const header_link& link, size_t height) const NOEXCEPT;

/// address
/// -----------------------------------------------------------------------

code get_address_outputs_turbo(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
code get_confirmed_unspent_outputs_turbo(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key) const NOEXCEPT;
code get_minimum_unspent_outputs_turbo(const std::atomic_bool& cancel,
outpoints& out, const hash_digest& key, uint64_t minimum) const NOEXCEPT;

/// tx_fk must be allocated.
/// -----------------------------------------------------------------------
code set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT;
Expand All @@ -696,6 +711,10 @@ class query
template <typename Bool>
static inline bool push_bool(std_vector<Bool>& stack,
const Bool& element) NOEXCEPT;
template <typename Functor>
static inline code parallel_address_transform(
const std::atomic_bool& cancel, outpoints& out,
const output_links& links, Functor&& functor) NOEXCEPT;

// Not thread safe.
size_t get_fork_() const NOEXCEPT;
Expand Down
1 change: 1 addition & 0 deletions include/bitcoin/database/settings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct BCD_API settings
settings(system::chain::selection context) NOEXCEPT;

/// Properties.
bool turbo;
std::filesystem::path path;

/// Archives.
Expand Down
6 changes: 6 additions & 0 deletions include/bitcoin/database/store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ class store
/// Construct a store from settings.
store(const settings& config) NOEXCEPT;

/// Properties
/// -----------------------------------------------------------------------

/// Allow full throttle concurrent query execution (may use 100% CPU).
bool turbo() const NOEXCEPT;

/// Methods.
/// -----------------------------------------------------------------------

Expand Down
3 changes: 2 additions & 1 deletion src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ namespace database {
using namespace bc::system;

settings::settings() NOEXCEPT
: path{ "bitcoin" },
: turbo{ false },
path{ "bitcoin" },

// Archives.

Expand Down
Loading
Loading