Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement reload, expose more detailed error info from set. #473

Merged
merged 5 commits into from
May 16, 2024
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
42 changes: 24 additions & 18 deletions include/bitcoin/database/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,11 @@ enum error_t : uint8_t
size_failure,
close_loaded,
close_failure,
load_locked,
load_loaded,
load_locked,
load_failure,
reload_unloaded,
reload_locked,
flush_unloaded,
flush_failure,
unload_locked,
Expand Down Expand Up @@ -87,29 +89,14 @@ enum error_t : uint8_t
restore_table,
verify_table,

/// tx fully valid in the given header context.
/// validation/confirmation
tx_connected,

/// tx conditionally valid in the given header context.
tx_preconnected,

/// tx not valid in the given header context.
tx_disconnected,

/// block is valid and confirmable.
block_confirmable,

/// block is valid but has not been evaluated for confirmability.
block_preconfirmable,

/// block is unconfirmable (invalid or spends not confirmable).
block_unconfirmable,

/// header has not been invalidated and its txs are not associated.
unassociated,

/// header|block has not been validated.
/// tx has not been validated in the given block context.
unvalidated,

/// confirmation (require not just context but prevouts and/or metadata).
Expand All @@ -118,7 +105,26 @@ enum error_t : uint8_t
unspent_coinbase_collision,
relative_time_locked,
unconfirmed_spend,
confirmed_double_spend
confirmed_double_spend,

/// tx archive
tx_empty,
tx_tx_allocate,
tx_spend_allocate,
tx_input_put,
tx_point_put,
tx_spend_set,
tx_output_put,
tx_tx_set,
tx_puts_put,
tx_spend_commit,
tx_address_put,
tx_tx_commit,

/// txs archive
txs_header,
////txs_tx,
txs_txs_put
};

// No current need for error_code equivalence mapping.
Expand Down
8 changes: 4 additions & 4 deletions include/bitcoin/database/impl/primitives/arraymap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ code CLASS::get_fault() const NOEXCEPT
}

TEMPLATE
bool CLASS::is_full() const NOEXCEPT
size_t CLASS::get_space() const NOEXCEPT
{
manager_.is_full();
return manager_.get_space();
}

TEMPLATE
void CLASS::reset_full() NOEXCEPT
code CLASS::reload() NOEXCEPT
{
manager_.reset_full();
return manager_.reload();
}

// query interface
Expand Down
8 changes: 4 additions & 4 deletions include/bitcoin/database/impl/primitives/hashmap.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -113,15 +113,15 @@ code CLASS::get_fault() const NOEXCEPT
}

TEMPLATE
bool CLASS::is_full() const NOEXCEPT
size_t CLASS::get_space() const NOEXCEPT
{
manager_.is_full();
return manager_.get_space();
}

TEMPLATE
void CLASS::reset_full() NOEXCEPT
code CLASS::reload() NOEXCEPT
{
manager_.reset_full();
return manager_.reload();
}

// query interface
Expand Down
8 changes: 4 additions & 4 deletions include/bitcoin/database/impl/primitives/manager.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ code CLASS::get_fault() const NOEXCEPT
}

TEMPLATE
bool CLASS::is_full() const NOEXCEPT
size_t CLASS::get_space() const NOEXCEPT
{
file_.is_full();
return file_.get_space();
}

TEMPLATE
void CLASS::reset_full() NOEXCEPT
code CLASS::reload() NOEXCEPT
{
file_.reset_full();
return file_.load();
}

// private
Expand Down
104 changes: 66 additions & 38 deletions include/bitcoin/database/impl/query/archive.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -658,22 +658,28 @@ typename CLASS::inputs_ptr CLASS::get_spenders(const tx_link& link,
return get_spenders(to_output(link, output_index));
}

// TODO: rename/change spend to archive table.
// The only multitable write, all archive except header, also address.
TEMPLATE
tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
{
tx_link out{};
return set_code(out, tx) ? tx_link{} : out;
}

// The only multitable write query (except initialize/genesis).
TEMPLATE
code CLASS::set_code(tx_link& out_fk, const transaction& tx) NOEXCEPT
{
using namespace system;
if (tx.is_empty())
return {};
return error::tx_empty;

const auto key = tx.hash(false);

// GUARD (tx redundancy)
// This is only fully effective if there is a single database thread.
auto tx_fk = to_tx(key);
if (!tx_fk.is_terminal())
return tx_fk;
out_fk = to_tx(key);
if (!out_fk.is_terminal())
return error::success;

// Declare puts record.
const auto& ins = *tx.inputs_ptr();
Expand All @@ -691,16 +697,16 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT

// Allocate tx record.
// Clean single allocation failure (e.g. disk full).
tx_fk = store_.tx.allocate(1);
if (tx_fk.is_terminal())
return {};
out_fk = store_.tx.allocate(1);
if (out_fk.is_terminal())
return error::tx_tx_allocate;

// Allocate spend records.
// Clean single allocation failure (e.g. disk full).
const auto count = possible_narrow_cast<spend_link::integer>(ins.size());
auto spend_fk = store_.spend.allocate(count);
if (spend_fk.is_terminal())
return {};
return error::tx_spend_allocate;

// Commit input records (spend records not indexed).
for (const auto& in: ins)
Expand All @@ -714,7 +720,7 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
*in
}))
{
return {};
return error::tx_input_put;
}

// Input point aliases.
Expand All @@ -733,7 +739,7 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
{
}))
{
return {};
return error::tx_point_put;
}
}
}
Expand All @@ -746,12 +752,12 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
if (!store_.spend.set(spend_fk, table::spend::record
{
{},
tx_fk,
out_fk,
in->sequence(),
input_fk
}))
{
return {};
return error::tx_spend_set;
}

// Acumulate spends (input references) in order.
Expand All @@ -766,11 +772,11 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
if (!store_.output.put_link(output_fk, table::output::put_ref
{
{},
tx_fk,
out_fk,
*out
}))
{
return {};
return error::tx_output_put;
}

// Acumulate outputs in order.
Expand All @@ -781,12 +787,12 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
// Safe allocation failure, unlinked blob links spend/output blobs.
const auto puts_fk = store_.puts.put_link(puts);
if (puts_fk.is_terminal())
return {};
return error::tx_puts_put;

// Write tx record.
// Safe allocation failure, index is deferred for spend index consistency.
using ix = linkage<schema::index>;
if (!store_.tx.set(tx_fk, table::transaction::record_put_ref
if (!store_.tx.set(out_fk, table::transaction::record_put_ref
{
{},
tx,
Expand All @@ -795,7 +801,7 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
puts_fk
}))
{
return {};
return error::tx_tx_set;
}

// Commit spends to search.
Expand All @@ -807,13 +813,13 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
{
--spend_fk.value;
if (store_.spend.commit_link(spend_fk, spend).is_terminal())
return {};
return error::tx_spend_commit;
}

// Commit addresses to search if address index is enabled.
if (address_enabled())
{
auto out_fk = puts.out_fks.begin();
auto output_fk = puts.out_fks.begin();
for (const auto& out: outs)
{
// Safe allocation failure, unindexed tx outputs linked by address,
Expand All @@ -824,17 +830,17 @@ tx_link CLASS::set_link(const transaction& tx) NOEXCEPT
if (!store_.address.put(out->script().hash(), table::address::record
{
{},
*out_fk++
*output_fk++
}))
{
return {};
return error::tx_address_put;
}
}
}

// Commit tx to search.
// Clean single allocation failure (e.g. disk full).
return store_.tx.commit_link(tx_fk, key);
return store_.tx.commit(out_fk, key) ? error::success : error::tx_tx_commit;
// ========================================================================
}

Expand Down Expand Up @@ -925,25 +931,45 @@ header_link CLASS::set_link(const block& block) NOEXCEPT
}

TEMPLATE
txs_link CLASS::set_link(const transactions& txs,
const header_link& link, size_t size) NOEXCEPT
txs_link CLASS::set_link(const transactions& txs, const header_link& key,
size_t size) NOEXCEPT
{
if (link.is_terminal())
return{};
txs_link out{};
return set_code(out, txs, key, size) ? txs_link{} : out;
}

TEMPLATE
code CLASS::set_code(const transactions& txs, const header_link& key,
size_t size) NOEXCEPT
{
txs_link out_fk{};
return set_code(out_fk, txs, key, size);
}

TEMPLATE
code CLASS::set_code(txs_link& out_fk, const transactions& txs,
const header_link& key, size_t size) NOEXCEPT
{
if (key.is_terminal())
return error::txs_header;

// GUARD (block (txs) redundancy)
// This is only fully effective if there is a single database thread.
// Guard must be lifted for an existing top malleable association so
// that a non-malleable association may be accomplished.
const auto txs_link = to_txs_link(link);
if (!txs_link.is_terminal() && !is_malleable(link))
return txs_link;
out_fk = to_txs_link(key);
if (!out_fk.is_terminal() && !is_malleable(key))
return error::success;

code ec{};
tx_link tx_fk{};
tx_links links{};
links.reserve(txs.size());
for (const auto& tx: txs)
if (!push_link_value(links, set_link(*tx)))
return {};
{
if ((ec = set_code(tx_fk, *tx))) return ec;
links.push_back(tx_fk.value);
}

using bytes = linkage<schema::size>::integer;
const auto wire = system::possible_narrow_cast<bytes>(size);
Expand All @@ -954,30 +980,32 @@ txs_link CLASS::set_link(const transactions& txs,

// Header link is the key for the txs table.
// Clean single allocation failure (e.g. disk full).
return store_.txs.put_link(link, table::txs::slab
out_fk = store_.txs.put_link(key, table::txs::slab
{
{},
malleable,
wire,
links
});

return out_fk.is_terminal() ? error::txs_txs_put : error::success;
// ========================================================================
}

TEMPLATE
bool CLASS::set_dissasociated(const header_link& link) NOEXCEPT
bool CLASS::set_dissasociated(const header_link& key) NOEXCEPT
{
if (link.is_terminal())
if (key.is_terminal())
return false;

const auto malleable = is_malleable(link);
const auto malleable = is_malleable(key);

// ========================================================================
const auto scope = store_.get_transactor();

// Header link is the key for the txs table.
// Clean single allocation failure (e.g. disk full).
return store_.txs.put(link, table::txs::slab
return store_.txs.put(key, table::txs::slab
{
{},
malleable,
Expand Down
Loading
Loading