Skip to content

Commit cdbe373

Browse files
committed
add basic snapshot test, modify block log to support partial logs, fix several bugs that result from that concept
1 parent a4f7f85 commit cdbe373

File tree

11 files changed

+345
-187
lines changed

11 files changed

+345
-187
lines changed

libraries/chain/authorization_manager.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ namespace eosio { namespace chain {
5656
void authorization_manager::read_from_snapshot( const snapshot_reader_ptr& snapshot ) {
5757
authorization_index_set::walk_indices([this, &snapshot]( auto utils ){
5858
snapshot->read_section<typename decltype(utils)::index_t::value_type>([this]( auto& section ) {
59-
bool done = section.empty();
60-
while(!done) {
61-
decltype(utils)::create(_db, [&section]( auto &row ) {
62-
section.read_row(row);
59+
bool more = !section.empty();
60+
while(more) {
61+
decltype(utils)::create(_db, [&section, &more]( auto &row ) {
62+
more = section.read_row(row);
6363
});
6464
}
6565
});

libraries/chain/block_log.cpp

Lines changed: 85 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,15 @@
1212

1313
namespace eosio { namespace chain {
1414

15-
const uint32_t block_log::supported_version = 1;
15+
const uint32_t block_log::min_supported_version = 1;
16+
17+
/**
18+
* History:
19+
* Version 1: complete block log from genesis
20+
* Version 2: adds optional partial block log, cannot be used for replay without snapshot
21+
* this is in the form of an first_block_num that is written immediately after the version
22+
*/
23+
const uint32_t block_log::max_supported_version = 2;
1624

1725
namespace detail {
1826
class block_log_impl {
@@ -26,6 +34,8 @@ namespace eosio { namespace chain {
2634
bool block_write;
2735
bool index_write;
2836
bool genesis_written_to_block_log = false;
37+
uint32_t version = 0;
38+
uint32_t first_block_num = 0;
2939

3040
inline void check_block_read() {
3141
if (block_write) {
@@ -124,14 +134,21 @@ namespace eosio { namespace chain {
124134
ilog("Log is nonempty");
125135
my->check_block_read();
126136
my->block_stream.seekg( 0 );
127-
uint32_t version = 0;
128-
my->block_stream.read( (char*)&version, sizeof(version) );
129-
EOS_ASSERT( version > 0, block_log_exception, "Block log was not setup properly with genesis information." );
130-
EOS_ASSERT( version == block_log::supported_version, block_log_unsupported_version,
131-
"Unsupported version of block log. Block log version is ${version} while code supports version ${supported}",
132-
("version", version)("supported", block_log::supported_version) );
137+
my->version = 0;
138+
my->block_stream.read( (char*)&my->version, sizeof(my->version) );
139+
EOS_ASSERT( my->version > 0, block_log_exception, "Block log was not setup properly" );
140+
EOS_ASSERT( my->version >= min_supported_version && my->version <= max_supported_version, block_log_unsupported_version,
141+
"Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]",
142+
("version", my->version)("min", block_log::min_supported_version)("max", block_log::max_supported_version) );
143+
133144

134145
my->genesis_written_to_block_log = true; // Assume it was constructed properly.
146+
if (my->version > 1){
147+
my->first_block_num = 0;
148+
my->block_stream.read( (char*)&my->first_block_num, sizeof(my->first_block_num) );
149+
EOS_ASSERT(my->first_block_num > 0, block_log_exception, "Block log is malformed, first recorded block number is 0 but must be greater than or equal to 1");
150+
}
151+
135152
my->head = read_head();
136153
my->head_id = my->head->id();
137154

@@ -176,11 +193,11 @@ namespace eosio { namespace chain {
176193
my->check_index_write();
177194

178195
uint64_t pos = my->block_stream.tellp();
179-
EOS_ASSERT(my->index_stream.tellp() == sizeof(uint64_t) * (b->block_num() - 1),
196+
EOS_ASSERT(my->index_stream.tellp() == sizeof(uint64_t) * (b->block_num() - my->first_block_num),
180197
block_log_append_fail,
181198
"Append to index file occuring at wrong position.",
182199
("position", (uint64_t) my->index_stream.tellp())
183-
("expected", (b->block_num() - 1) * sizeof(uint64_t)));
200+
("expected", (b->block_num() - my->first_block_num) * sizeof(uint64_t)));
184201
auto data = fc::raw::pack(*b);
185202
my->block_stream.write(data.data(), data.size());
186203
my->block_stream.write((char*)&pos, sizeof(pos));
@@ -200,44 +217,50 @@ namespace eosio { namespace chain {
200217
my->index_stream.flush();
201218
}
202219

203-
uint64_t block_log::reset_to_genesis( const genesis_state& gs, const signed_block_ptr& genesis_block ) {
204-
if( my->block_stream.is_open() )
220+
void block_log::reset( const genesis_state& gs, const signed_block_ptr& first_block, uint32_t first_block_num ) {
221+
if (my->block_stream.is_open())
205222
my->block_stream.close();
206-
if( my->index_stream.is_open() )
223+
if (my->index_stream.is_open())
207224
my->index_stream.close();
208225

209-
fc::remove_all( my->block_file );
210-
fc::remove_all( my->index_file );
226+
fc::remove_all(my->block_file);
227+
fc::remove_all(my->index_file);
211228

212229
my->block_stream.open(my->block_file.generic_string().c_str(), LOG_WRITE);
213230
my->index_stream.open(my->index_file.generic_string().c_str(), LOG_WRITE);
214231
my->block_write = true;
215232
my->index_write = true;
216233

217-
auto data = fc::raw::pack( gs );
218-
uint32_t version = 0; // version of 0 is invalid; it indicates that the genesis was not properly written to the block log
219-
my->block_stream.write( (char*)&version, sizeof(version) );
220-
my->block_stream.write( data.data(), data.size() );
234+
auto data = fc::raw::pack(gs);
235+
my->version = 0; // version of 0 is invalid; it indicates that the genesis was not properly written to the block log
236+
my->first_block_num = first_block_num;
237+
my->block_stream.write((char*)&my->version, sizeof(my->version));
238+
my->block_stream.write((char*)&my->first_block_num, sizeof(my->first_block_num));
239+
my->block_stream.write(data.data(), data.size());
221240
my->genesis_written_to_block_log = true;
222241

223-
auto ret = append( genesis_block );
242+
// append a totem to indicate the division between blocks and header
243+
auto totem = npos;
244+
my->block_stream.write((char*)&totem, sizeof(totem));
245+
246+
if (first_block) {
247+
auto ret = append(first_block);
248+
}
224249

225250
auto pos = my->block_stream.tellp();
226251

227252
my->block_stream.close();
228253
my->block_stream.open(my->block_file.generic_string().c_str(), std::ios::in | std::ios::out | std::ios::binary ); // Bypass append-only writing just once
229254

230-
static_assert( block_log::supported_version > 0, "a version number of zero is not supported" );
231-
version = block_log::supported_version;
255+
static_assert( block_log::max_supported_version > 0, "a version number of zero is not supported" );
256+
my->version = block_log::max_supported_version;
232257
my->block_stream.seekp( 0 );
233-
my->block_stream.write( (char*)&version, sizeof(version) ); // Finally write actual version to disk.
258+
my->block_stream.write( (char*)&my->version, sizeof(my->version) );
234259
my->block_stream.seekp( pos );
235260
flush();
236261

237262
my->block_write = false;
238263
my->check_block_write(); // Reset to append-only writing.
239-
240-
return ret;
241264
}
242265

243266
std::pair<signed_block_ptr, uint64_t> block_log::read_block(uint64_t pos)const {
@@ -266,10 +289,9 @@ namespace eosio { namespace chain {
266289

267290
uint64_t block_log::get_block_pos(uint32_t block_num) const {
268291
my->check_index_read();
269-
270-
if (!(my->head && block_num <= block_header::num_from_id(my->head_id) && block_num > 0))
292+
if (!(my->head && block_num <= block_header::num_from_id(my->head_id) && block_num >= my->first_block_num))
271293
return npos;
272-
my->index_stream.seekg(sizeof(uint64_t) * (block_num - 1));
294+
my->index_stream.seekg(sizeof(uint64_t) * (block_num - my->first_block_num));
273295
uint64_t pos;
274296
my->index_stream.read((char*)&pos, sizeof(pos));
275297
return pos;
@@ -287,13 +309,21 @@ namespace eosio { namespace chain {
287309

288310
my->block_stream.seekg(-sizeof(pos), std::ios::end);
289311
my->block_stream.read((char*)&pos, sizeof(pos));
290-
return read_block(pos).first;
312+
if (pos != npos) {
313+
return read_block(pos).first;
314+
} else {
315+
return {};
316+
}
291317
}
292318

293319
const signed_block_ptr& block_log::head()const {
294320
return my->head;
295321
}
296322

323+
uint32_t block_log::first_block_num() const {
324+
return my->first_block_num;
325+
}
326+
297327
void block_log::construct_index() {
298328
ilog("Reconstructing Block Log Index...");
299329
my->index_stream.close();
@@ -308,7 +338,12 @@ namespace eosio { namespace chain {
308338
my->block_stream.read((char*)&end_pos, sizeof(end_pos));
309339
signed_block tmp;
310340

311-
uint64_t pos = 4; // Skip version which should have already been checked.
341+
uint64_t pos = 0;
342+
if (my->version == 1) {
343+
pos = 4; // Skip version which should have already been checked.
344+
} else {
345+
pos = 8; // Skip version and first block offset which should have already been checked
346+
}
312347
my->block_stream.seekg(pos);
313348

314349
genesis_state gs;
@@ -361,16 +396,23 @@ namespace eosio { namespace chain {
361396

362397
uint32_t version = 0;
363398
old_block_stream.read( (char*)&version, sizeof(version) );
364-
EOS_ASSERT( version > 0, block_log_exception, "Block log was not setup properly with genesis information." );
365-
EOS_ASSERT( version == block_log::supported_version, block_log_unsupported_version,
366-
"Unsupported version of block log. Block log version is ${version} while code supports version ${supported}",
367-
("version", version)("supported", block_log::supported_version) );
399+
EOS_ASSERT( version > 0, block_log_exception, "Block log was not setup properly" );
400+
EOS_ASSERT( version >= min_supported_version && version <= max_supported_version, block_log_unsupported_version,
401+
"Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]",
402+
("version", version)("min", block_log::min_supported_version)("max", block_log::max_supported_version) );
403+
404+
new_block_stream.write( (char*)&version, sizeof(version) );
405+
406+
uint32_t first_block_num = 1;
407+
if (version != 1) {
408+
old_block_stream.read ( (char*)&first_block_num, sizeof(first_block_num) );
409+
new_block_stream.write( (char*)&first_block_num, sizeof(first_block_num) );
410+
}
368411

369412
genesis_state gs;
370413
fc::raw::unpack(old_block_stream, gs);
371414

372415
auto data = fc::raw::pack( gs );
373-
new_block_stream.write( (char*)&version, sizeof(version) );
374416
new_block_stream.write( data.data(), data.size() );
375417

376418
std::exception_ptr except_ptr;
@@ -472,10 +514,15 @@ namespace eosio { namespace chain {
472514

473515
uint32_t version = 0;
474516
block_stream.read( (char*)&version, sizeof(version) );
475-
EOS_ASSERT( version > 0, block_log_exception, "Block log was not setup properly with genesis information." );
476-
EOS_ASSERT( version == block_log::supported_version, block_log_unsupported_version,
477-
"Unsupported version of block log. Block log version is ${version} while code supports version ${supported}",
478-
("version", version)("supported", block_log::supported_version) );
517+
EOS_ASSERT( version > 0, block_log_exception, "Block log was not setup properly." );
518+
EOS_ASSERT( version >= min_supported_version && version <= max_supported_version, block_log_unsupported_version,
519+
"Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]",
520+
("version", version)("min", block_log::min_supported_version)("max", block_log::max_supported_version) );
521+
522+
uint32_t first_block_num = 1;
523+
if (version != 1) {
524+
block_stream.read ( (char*)&first_block_num, sizeof(first_block_num) );
525+
}
479526

480527
genesis_state gs;
481528
fc::raw::unpack(block_stream, gs);

0 commit comments

Comments
 (0)