Skip to content

Commit 2e00bef

Browse files
committed
Contiguously allocate block transactions.
1 parent 87158c5 commit 2e00bef

6 files changed

Lines changed: 109 additions & 45 deletions

File tree

include/bitcoin/database/impl/query/archive_read.ipp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ size_t CLASS::get_tx_count(const header_link& link) const NOEXCEPT
9696
if (!store_.txs.find(link, txs))
9797
return {};
9898

99-
return txs.quantity;
99+
return txs.number;
100100
}
101101

102102
TEMPLATE

include/bitcoin/database/impl/query/archive_write.ipp

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,18 @@ bool CLASS::set(const block& block, bool strong) NOEXCEPT
7777
TEMPLATE
7878
code CLASS::set_code(const transaction& tx) NOEXCEPT
7979
{
80-
tx_link unused{};
81-
return set_code(unused, tx);
80+
constexpr auto txs = system::possible_narrow_cast<tx_link::integer>(one);
81+
82+
// Allocate tx record.
83+
const auto tx_fk = store_.tx.allocate(txs);
84+
if (tx_fk.is_terminal())
85+
return error::tx_tx_allocate;
86+
87+
return set_code(tx_fk, tx);
8288
}
8389

8490
TEMPLATE
85-
code CLASS::set_code(tx_link& tx_fk, const transaction& tx) NOEXCEPT
91+
code CLASS::set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT
8692
{
8793
// This is the only multitable write query (except initialize/genesis).
8894
using namespace system;
@@ -92,19 +98,13 @@ code CLASS::set_code(tx_link& tx_fk, const transaction& tx) NOEXCEPT
9298
using ix = linkage<schema::index>;
9399
const auto& ins = tx.inputs_ptr();
94100
const auto& ous = tx.outputs_ptr();
95-
const auto txs = possible_narrow_cast<tx_link::integer>(one);
96101
const auto inputs = possible_narrow_cast<ix::integer>(ins->size());
97102
const auto outputs = possible_narrow_cast<ix::integer>(ous->size());
98103

99104

100105
// ========================================================================
101106
const auto scope = store_.get_transactor();
102107

103-
// Allocate tx record.
104-
tx_fk = store_.tx.allocate(txs);
105-
if (tx_fk.is_terminal())
106-
return error::tx_tx_allocate;
107-
108108
// Allocate contiguously and store inputs.
109109
input_link in_fk{};
110110
if (!store_.input.put_link(in_fk, table::input::put_ref{ {}, tx }))
@@ -321,46 +321,48 @@ TEMPLATE
321321
code CLASS::set_code(txs_link& out_fk, const block& block,
322322
const header_link& key, bool strong) NOEXCEPT
323323
{
324+
using namespace system;
324325
if (key.is_terminal())
325326
return error::txs_header;
326327

327-
const auto count = block.transactions();
328-
if (is_zero(count))
328+
const auto txs = block.transactions();
329+
if (is_zero(txs))
329330
return error::txs_empty;
330331

332+
const auto count = possible_narrow_cast<tx_link::integer>(txs);
333+
const auto tx_fks = store_.tx.allocate(count);
334+
if (tx_fks.is_terminal())
335+
return error::tx_tx_allocate;
336+
331337
code ec{};
332-
tx_link tx_fk{};
333-
tx_links links{};
334-
links.reserve(count);
338+
auto fk = tx_fks;
339+
340+
// Each tx is set under a distinct transactor.
335341
for (const auto& tx: *block.transactions_ptr())
336-
{
337-
// Each tx is set under a distinct transactor.
338-
if ((ec = set_code(tx_fk, *tx)))
342+
if ((ec = set_code(fk++, *tx)))
339343
return ec;
340344

341-
links.push_back(tx_fk.value);
342-
}
343-
344345
using bytes = linkage<schema::size>::integer;
345346
const auto size = block.serialized_size(true);
346-
const auto wire = system::possible_narrow_cast<bytes>(size);
347+
const auto wire = possible_narrow_cast<bytes>(size);
347348

348349
// ========================================================================
349350
const auto scope = store_.get_transactor();
350351
constexpr auto positive = true;
351352

352353
// Clean allocation failure (e.g. disk full), see set_strong() comments.
353354
// Transactor assures cannot be restored without txs, as required to unset.
354-
if (strong && !set_strong(key, links, positive))
355+
if (strong && !set_strong(key, txs, tx_fks, positive))
355356
return error::txs_confirm;
356357

357358
// Header link is the key for the txs table.
358359
// Clean single allocation failure (e.g. disk full).
359-
out_fk = store_.txs.put_link(key, table::txs::slab
360+
out_fk = store_.txs.put_link(key, table::txs::put_group
360361
{
361362
{},
362363
wire,
363-
links
364+
count,
365+
tx_fks
364366
});
365367

366368
return out_fk.is_terminal() ? error::txs_txs_put : error::success;

include/bitcoin/database/impl/query/consensus.ipp

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,6 @@ code CLASS::block_confirmable(const header_link& link) const NOEXCEPT
411411
// ----------------------------------------------------------------------------
412412

413413
// protected
414-
// This is also invoked from block.txs archival (when checkpoint/milestone).
415414
TEMPLATE
416415
bool CLASS::set_strong(const header_link& link, const tx_links& txs,
417416
bool positive) NOEXCEPT
@@ -436,6 +435,34 @@ bool CLASS::set_strong(const header_link& link, const tx_links& txs,
436435
return true;
437436
}
438437

438+
// protected
439+
// This is invoked from block.txs archival (when checkpoint/milestone).
440+
TEMPLATE
441+
bool CLASS::set_strong(const header_link& link, size_t count,
442+
const tx_link& first_fk, bool positive) NOEXCEPT
443+
{
444+
using namespace system;
445+
using link_t = table::strong_tx::link;
446+
using element_t = table::strong_tx::record;
447+
448+
// Preallocate all strong_tx records for the block and reuse memory ptr.
449+
const auto records = possible_narrow_cast<link_t::integer>(count);
450+
auto record = store_.strong_tx.allocate(records);
451+
const auto ptr = store_.strong_tx.get_memory();
452+
const auto end = first_fk + count;
453+
454+
// Contiguous tx links.
455+
for (auto fk = first_fk; fk < end; ++fk)
456+
if (!store_.strong_tx.put(ptr, record++, fk, element_t
457+
{
458+
{},
459+
link,
460+
positive
461+
})) return false;
462+
463+
return true;
464+
}
465+
439466
TEMPLATE
440467
bool CLASS::set_strong(const header_link& link) NOEXCEPT
441468
{

include/bitcoin/database/query.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,6 @@ class query
374374

375375
/// Set transaction.
376376
code set_code(const transaction& tx) NOEXCEPT;
377-
code set_code(tx_link& tx_fk, const transaction& tx) NOEXCEPT;
378377

379378
/// Set header (headers-first).
380379
code set_code(const header& header, const context& ctx,
@@ -563,6 +562,8 @@ class query
563562
const tx_link& prevout_tx, uint32_t version,
564563
const context& ctx) const NOEXCEPT;
565564

565+
bool set_strong(const header_link& link, size_t count,
566+
const tx_link& first_fk, bool positive) NOEXCEPT;
566567
bool set_strong(const header_link& link, const tx_links& txs,
567568
bool positive) NOEXCEPT;
568569

@@ -601,6 +602,10 @@ class query
601602
const system::settings& settings, const header& header,
602603
const header_link& link, size_t height) const NOEXCEPT;
603604

605+
/// tx_fk must be allocated.
606+
/// -----------------------------------------------------------------------
607+
code set_code(const tx_link& tx_fk, const transaction& tx) NOEXCEPT;
608+
604609
private:
605610
struct maybe_strong
606611
{

include/bitcoin/database/tables/archives/txs.hpp

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct txs
3636
: public hash_map<schema::txs>
3737
{
3838
using tx = linkage<schema::tx>;
39+
using ct = linkage<schema::count_>;
3940
using keys = std::vector<tx::integer>;
4041
using bytes = linkage<schema::size>;
4142
using hash_map<schema::txs>::hashmap;
@@ -46,12 +47,12 @@ struct txs
4647
link count() const NOEXCEPT
4748
{
4849
return system::possible_narrow_cast<link::integer>(pk + sk +
49-
schema::count_ + bytes::size + tx::size * tx_fks.size());
50+
ct::size + bytes::size + tx::size * tx_fks.size());
5051
}
5152

5253
inline bool from_data(reader& source) NOEXCEPT
5354
{
54-
tx_fks.resize(source.read_little_endian<tx::integer, schema::count_>());
55+
tx_fks.resize(source.read_little_endian<ct::integer, ct::size>());
5556
wire = source.read_little_endian<bytes::integer, bytes::size>();
5657
std::for_each(tx_fks.begin(), tx_fks.end(), [&](auto& fk) NOEXCEPT
5758
{
@@ -64,10 +65,10 @@ struct txs
6465

6566
inline bool to_data(finalizer& sink) const NOEXCEPT
6667
{
67-
BC_ASSERT(tx_fks.size() < system::power2<uint64_t>(to_bits(schema::count_)));
68-
const auto fks = system::possible_narrow_cast<tx::integer>(tx_fks.size());
68+
BC_ASSERT(tx_fks.size() < system::power2<uint64_t>(to_bits(ct::size)));
69+
const auto fks = system::possible_narrow_cast<ct::integer>(tx_fks.size());
6970

70-
sink.write_little_endian<tx::integer, schema::count_>(fks);
71+
sink.write_little_endian<ct::integer, ct::size>(fks);
7172
sink.write_little_endian<bytes::integer, bytes::size>(wire);
7273
std::for_each(tx_fks.begin(), tx_fks.end(), [&](const auto& fk) NOEXCEPT
7374
{
@@ -88,6 +89,37 @@ struct txs
8889
keys tx_fks{};
8990
};
9091

92+
// put a contiguous set of tx identifiers.
93+
// TODO: this could be collapsed to a count and first using a sentinel.
94+
struct put_group
95+
: public schema::txs
96+
{
97+
link count() const NOEXCEPT
98+
{
99+
return system::possible_narrow_cast<link::integer>(pk + sk +
100+
ct::size + bytes::size + tx::size * number);
101+
}
102+
103+
inline bool to_data(finalizer& sink) const NOEXCEPT
104+
{
105+
BC_ASSERT(number < system::power2<uint64_t>(to_bits(ct::size)));
106+
107+
sink.write_little_endian<ct::integer, ct::size>(number);
108+
sink.write_little_endian<bytes::integer, bytes::size>(wire);
109+
110+
for (auto fk = tx_fk; fk < (tx_fk + number); ++fk)
111+
sink.write_little_endian<tx::integer, tx::size>(fk);
112+
113+
BC_ASSERT(!sink || sink.get_write_position() == count());
114+
return sink;
115+
}
116+
117+
// block.serialized_size(true)
118+
bytes::integer wire{};
119+
ct::integer number{};
120+
tx::integer tx_fk{};
121+
};
122+
91123
struct get_position
92124
: public schema::txs
93125
{
@@ -99,7 +131,7 @@ struct txs
99131

100132
inline bool from_data(reader& source) NOEXCEPT
101133
{
102-
const auto number = source.read_little_endian<tx::integer, schema::count_>();
134+
const auto number = source.read_little_endian<ct::integer, ct::size>();
103135
source.skip_bytes(bytes::size);
104136
for (position = zero; position < number; ++position)
105137
if (source.read_little_endian<tx::integer, tx::size>() == tx_fk)
@@ -124,7 +156,7 @@ struct txs
124156

125157
inline bool from_data(reader& source) NOEXCEPT
126158
{
127-
const auto number = source.read_little_endian<tx::integer, schema::count_>();
159+
const auto number = source.read_little_endian<ct::integer, ct::size>();
128160
source.skip_bytes(bytes::size);
129161
if (is_nonzero(number))
130162
{
@@ -150,7 +182,7 @@ struct txs
150182

151183
inline bool from_data(reader& source) NOEXCEPT
152184
{
153-
source.skip_bytes(schema::count_);
185+
source.skip_bytes(ct::size);
154186
wire = source.read_little_endian<bytes::integer, bytes::size>();
155187
return source;
156188
}
@@ -169,7 +201,7 @@ struct txs
169201

170202
inline bool from_data(reader& source) NOEXCEPT
171203
{
172-
associated = to_bool(source.read_little_endian<tx::integer, schema::count_>());
204+
associated = to_bool(source.read_little_endian<ct::integer, ct::size>());
173205
return source;
174206
}
175207

@@ -187,7 +219,7 @@ struct txs
187219

188220
inline bool from_data(reader& source) NOEXCEPT
189221
{
190-
tx_fks.resize(source.read_little_endian<tx::integer, schema::count_>());
222+
tx_fks.resize(source.read_little_endian<ct::integer, ct::size>());
191223
source.skip_bytes(bytes::size);
192224
std::for_each(tx_fks.begin(), tx_fks.end(), [&](auto& fk) NOEXCEPT
193225
{
@@ -211,7 +243,7 @@ struct txs
211243

212244
inline bool from_data(reader& source) NOEXCEPT
213245
{
214-
const auto number = source.read_little_endian<tx::integer, schema::count_>();
246+
const auto number = source.read_little_endian<ct::integer, ct::size>();
215247
if (number <= one)
216248
return source;
217249

@@ -239,11 +271,11 @@ struct txs
239271

240272
inline bool from_data(reader& source) NOEXCEPT
241273
{
242-
quantity = source.read_little_endian<tx::integer, schema::count_>();
274+
number = source.read_little_endian<ct::integer, ct::size>();
243275
return source;
244276
}
245277

246-
size_t quantity{};
278+
size_t number{};
247279
};
248280
};
249281

test/query/archive.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ BOOST_AUTO_TEST_CASE(query_archive__set_tx__empty__expected)
182182
const auto expected_head5_array = system::base16_chunk("0000000000");
183183
const auto expected_head4_array = system::base16_chunk("00000000");
184184
const auto expected_head4_hash = system::base16_chunk(
185-
"00000000" // record count
185+
"01000000" // record count
186186
"ffffffff" // bucket[0]...
187187
"ffffffff"
188188
"ffffffff"
@@ -214,7 +214,7 @@ BOOST_AUTO_TEST_CASE(query_archive__set_tx__empty__expected)
214214
BOOST_REQUIRE_EQUAL(store.input_head(), expected_head5_array);
215215
BOOST_REQUIRE_EQUAL(store.output_head(), expected_head5_array);
216216
BOOST_REQUIRE_EQUAL(store.outs_head(), expected_head4_array);
217-
BOOST_REQUIRE(store.tx_body().empty());
217+
BOOST_REQUIRE_EQUAL(store.tx_body().size(), schema::transaction::minrow);
218218
BOOST_REQUIRE(store.point_body().empty());
219219
BOOST_REQUIRE(store.input_body().empty());
220220
BOOST_REQUIRE(store.output_body().empty());
@@ -291,16 +291,14 @@ BOOST_AUTO_TEST_CASE(query_archive__set_link_tx__null_input__expected)
291291
BOOST_REQUIRE_EQUAL(tx_hash, tx.hash(false));
292292

293293
// data_chunk store.
294-
tx_link link{};
295294
settings settings{};
296295
settings.tx_bits = 3;
297296
settings.point_bits = 3;
298297
settings.path = TEST_DIRECTORY;
299298
test::chunk_store store{ settings };
300299
test::query_accessor query{ store };
301300
BOOST_REQUIRE(!store.create(events_handler));
302-
BOOST_REQUIRE(!query.set_code(link, tx));
303-
BOOST_REQUIRE(!link.is_terminal());
301+
BOOST_REQUIRE(!query.set_code(tx));
304302
BOOST_REQUIRE(!store.close(events_handler));
305303

306304
BOOST_REQUIRE_EQUAL(store.tx_head(), expected_tx_head);

0 commit comments

Comments
 (0)