Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
sysio::chain::detail::block_log_impl Class Reference
Collaboration diagram for sysio::chain::detail::block_log_impl:

Public Member Functions

 block_log_impl (std::optional< block_log_prune_config > prune_conf)
 
void check_open_files ()
 
void reopen ()
 
void try_exit_vacuum ()
 
void close ()
 
template<typename T >
void reset (const T &t, const signed_block_ptr &genesis_block, uint32_t first_block_num)
 
void write (const genesis_state &gs)
 
void write (const chain_id_type &chain_id)
 
void flush ()
 
void append (const signed_block_ptr &b)
 
void prune (const fc::log_level &loglevel)
 
void vacuum ()
 
size_t convert_existing_header_to_vacuumed ()
 
uint64_t get_block_pos (uint32_t block_num)
 

Static Public Member Functions

template<typename ChainContext , typename Lambda >
static std::optional< ChainContext > extract_chain_context (const fc::path &data_dir, Lambda &&lambda)
 

Public Attributes

signed_block_ptr head
 
block_id_type head_id
 
fc::cfile block_file
 
fc::cfile index_file
 
bool open_files = false
 
bool genesis_written_to_block_log = false
 
uint32_t version = 0
 
uint32_t first_block_num = 0
 
uint32_t index_first_block_num = 0
 
std::optional< block_log_prune_configprune_config
 

Detailed Description

Definition at line 40 of file block_log.cpp.

Constructor & Destructor Documentation

◆ block_log_impl()

sysio::chain::detail::block_log_impl::block_log_impl ( std::optional< block_log_prune_config > prune_conf)
inline

Definition at line 53 of file block_log.cpp.

53 :
54 prune_config(prune_conf) {
55 if(prune_config) {
56 SYS_ASSERT(prune_config->prune_blocks, block_log_exception, "block log prune configuration requires at least one block");
57 SYS_ASSERT(__builtin_popcount(prune_config->prune_threshold) == 1, block_log_exception, "block log prune threshold must be power of 2");
58 //switch this over to the mask that will be used
59 prune_config->prune_threshold = ~(prune_config->prune_threshold-1);
60 }
61 }
#define SYS_ASSERT(expr, exc_type, FORMAT,...)
Definition exceptions.hpp:7
std::optional< block_log_prune_config > prune_config
Definition block_log.cpp:51

Member Function Documentation

◆ append()

void sysio::chain::detail::block_log_impl::append ( const signed_block_ptr & b)

Definition at line 362 of file block_log.cpp.

362 {
363 try {
364 SYS_ASSERT( genesis_written_to_block_log, block_log_append_fail, "Cannot append to block log until the genesis is first written" );
365
367
370 //if pruned log, rewind over count trailer if any block is already present
371 if(prune_config && head)
372 block_file.skip(-sizeof(uint32_t));
373 uint64_t pos = block_file.tellp();
374
375 SYS_ASSERT(index_file.tellp() == sizeof(uint64_t) * (b->block_num() - index_first_block_num),
376 block_log_append_fail,
377 "Append to index file occuring at wrong position.",
378 ("position", (uint64_t) index_file.tellp())
379 ("expected", (b->block_num() - index_first_block_num) * sizeof(uint64_t)));
380 auto data = fc::raw::pack(*b);
381 block_file.write(data.data(), data.size());
382 block_file.write((char*)&pos, sizeof(pos));
383 const uint64_t end = block_file.tellp();
384 index_file.write((char*)&pos, sizeof(pos));
385 head = b;
386 head_id = b->calculate_id();
387
388 if(prune_config) {
389 if((pos&prune_config->prune_threshold) != (end&prune_config->prune_threshold))
391
392 const uint32_t num_blocks_in_log = chain::block_header::num_from_id(head_id) - first_block_num + 1;
393 fc::raw::pack(block_file, num_blocks_in_log);
394 }
395
396 flush();
397 }
399 }
void seek_end(long loc)
Definition cfile.hpp:96
void skip(long loc)
Definition cfile.hpp:105
size_t tellp() const
Definition cfile.hpp:79
void write(const char *d, size_t n)
Definition cfile.hpp:127
void prune(const fc::log_level &loglevel)
#define FC_LOG_AND_RETHROW()
void pack(Stream &s, const std::deque< T > &value)
Definition raw.hpp:531
unsigned int uint32_t
Definition stdint.h:126
unsigned __int64 uint64_t
Definition stdint.h:136
static uint32_t num_from_id(const block_id_type &id)
Here is the call graph for this function:

◆ check_open_files()

void sysio::chain::detail::block_log_impl::check_open_files ( )
inline

Definition at line 63 of file block_log.cpp.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ close()

void sysio::chain::detail::block_log_impl::close ( )
inline

Definition at line 91 of file block_log.cpp.

91 {
92 if( block_file.is_open() )
94 if( index_file.is_open() )
96 open_files = false;
97 }
void close()
Definition cfile.hpp:202
bool is_open() const
Definition cfile.hpp:45
Here is the call graph for this function:

◆ convert_existing_header_to_vacuumed()

size_t sysio::chain::detail::block_log_impl::convert_existing_header_to_vacuumed ( )

Definition at line 435 of file block_log.cpp.

435 {
436 uint32_t old_version;
437 uint32_t old_first_block_num;
438 const auto totem = block_log::npos;
439
440 block_file.seek(0);
441 fc::raw::unpack(block_file, old_version);
442 fc::raw::unpack(block_file, old_first_block_num);
443 SYS_ASSERT(is_pruned_log_and_mask_version(old_version), block_log_exception, "Trying to vacuumed a non-pruned block log");
444
445 if(block_log::contains_genesis_state(old_version, old_first_block_num)) {
446 //we'll always write a v3 log, but need to possibly mutate the genesis_state to a chainid should we have pruned a log starting with a genesis_state
447 genesis_state gs;
449 fc::raw::unpack(ds, gs);
450
451 block_file.seek(0);
454 if(first_block_num == 1) {
455 SYS_ASSERT(old_first_block_num == 1, block_log_exception, "expected an old first blocknum of 1");
457 }
458 else
459 fc::raw::pack(block_file, gs.compute_chain_id());
461 }
462 else {
463 //read in the existing chainid, to parrot back out
464 fc::sha256 chainid;
465 fc::raw::unpack(block_file, chainid);
466
467 block_file.seek(0);
470 fc::raw::pack(block_file, chainid);
472 }
473
474 return block_file.tellp();
475 }
void seek(long loc)
Definition cfile.hpp:87
cfile_datastream create_datastream()
Definition cfile.hpp:249
static const uint64_t npos
Definition block_log.hpp:73
static bool contains_genesis_state(uint32_t version, uint32_t first_block_num)
static const uint32_t max_supported_version
Definition block_log.hpp:76
static const Segment gs(Segment::gs)
static const Segment ds(Segment::ds)
void unpack(Stream &s, std::deque< T > &value)
Definition raw.hpp:540
Here is the call graph for this function:

◆ extract_chain_context()

template<typename ChainContext , typename Lambda >
std::optional< ChainContext > sysio::chain::detail::block_log_impl::extract_chain_context ( const fc::path & data_dir,
Lambda && lambda )
static

Definition at line 942 of file block_log.cpp.

942 {
943 SYS_ASSERT( fc::is_directory(data_dir) && fc::is_regular_file(data_dir / "blocks.log"), block_log_not_found,
944 "Block log not found in '${blocks_dir}'", ("blocks_dir", data_dir) );
945
946 std::fstream block_stream;
947 block_stream.open( (data_dir / "blocks.log").generic_string().c_str(), LOG_READ );
948
949 uint32_t version = 0;
950 block_stream.read( (char*)&version, sizeof(version) );
951 is_pruned_log_and_mask_version(version);
953 "Unsupported version of block log. Block log version is ${version} while code supports version(s) [${min},${max}]",
955
957 if (version != 1) {
958 block_stream.read ( (char*)&first_block_num, sizeof(first_block_num) );
959 }
960
961 return lambda(block_stream, version, first_block_num);
962 }
#define LOG_READ
Definition block_log.cpp:9
static const uint32_t min_supported_version
Definition block_log.hpp:75
bool is_regular_file(const path &p)
bool is_directory(const path &p)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ flush()

void sysio::chain::detail::block_log_impl::flush ( )

Definition at line 430 of file block_log.cpp.

430 {
433 }
void flush()
Definition cfile.hpp:135
Here is the caller graph for this function:

◆ get_block_pos()

uint64_t sysio::chain::detail::block_log_impl::get_block_pos ( uint32_t block_num)

Definition at line 657 of file block_log.cpp.

657 {
659 if (!(head && block_num <= block_header::num_from_id(head_id) && block_num >= first_block_num))
660 return block_log::npos;
661 index_file.seek(sizeof(uint64_t) * (block_num - index_first_block_num));
662 uint64_t pos;
663 index_file.read((char*)&pos, sizeof(pos));
664 return pos;
665 }
void read(char *d, size_t n)
Definition cfile.hpp:114
Here is the call graph for this function:
Here is the caller graph for this function:

◆ prune()

void sysio::chain::detail::block_log_impl::prune ( const fc::log_level & loglevel)

Definition at line 401 of file block_log.cpp.

401 {
402 if(!head)
403 return;
405 if(head_num - first_block_num < prune_config->prune_blocks)
406 return;
407
408 const uint32_t prune_to_num = head_num - prune_config->prune_blocks + 1;
409
410 static_assert( block_log::max_supported_version == 3, "Code was written to support version 3 format, need to update this code for latest format." );
411 const genesis_state gs;
412 const size_t max_header_size_v1 = sizeof(uint32_t) + fc::raw::pack_size(gs) + sizeof(uint64_t);
413 const size_t max_header_size_v23 = sizeof(uint32_t) + sizeof(uint32_t) + sizeof(chain_id_type) + sizeof(uint64_t);
414 const auto max_header_size = std::max(max_header_size_v1, max_header_size_v23);
415
416 block_file.punch_hole(max_header_size, get_block_pos(prune_to_num));
417
418 first_block_num = prune_to_num;
420
421 if(auto l = fc::logger::get(); l.is_enabled(loglevel))
422 l.log(fc::log_message(fc::log_context(loglevel, __FILE__, __LINE__, __func__),
423 "blocks.log pruned to blocks ${b}-${e}", fc::mutable_variant_object()("b", first_block_num)("e", head_num)));
424 }
void punch_hole(size_t begin, size_t end)
Definition cfile.hpp:159
provides information about where and when a log message was generated.
aggregates a message along with the context and associated meta-information.
static logger get(const fc::string &name=DEFAULT_LOGGER)
Definition logger.cpp:88
bool is_enabled(log_level e) const
Definition logger.cpp:58
An order-preserving dictionary of variants.
uint64_t get_block_pos(uint32_t block_num)
#define __func__
size_t pack_size(const T &v)
Definition raw.hpp:671
size_t const max_header_size
Maximum size in bytes before rejecting an HTTP header as too big.
Definition constants.hpp:65
int l
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reopen()

void sysio::chain::detail::detail::block_log_impl::reopen ( )

Definition at line 130 of file block_log.cpp.

130 {
131 close();
132
133 // open to create files if they don't exist
134 //ilog("Opening block log at ${path}", ("path", my->block_file.generic_string()));
137
138 close();
139
142
143 open_files = true;
144 }
#define LOG_RW_C
Definition block_log.cpp:13
#define LOG_WRITE_C
Definition block_log.cpp:12
void open(const char *mode)
Definition cfile.hpp:65
Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset()

template<typename T >
void sysio::chain::detail::block_log_impl::reset ( const T & t,
const signed_block_ptr & genesis_block,
uint32_t first_block_num )

Definition at line 548 of file block_log.cpp.

548 {
549 close();
550
553
554 reopen();
555
556 version = 0; // version of 0 is invalid; it indicates that subsequent data was not properly written to the block log
558
560 block_file.write((char*)&version, sizeof(version));
562
563 write(t);
565
566 // append a totem to indicate the division between blocks and header
567 auto totem = block_log::npos;
568 block_file.write((char*)&totem, sizeof(totem));
569
570 if (first_block) {
571 append(first_block);
572 } else {
573 head.reset();
574 head_id = {};
575 if(prune_config)
577 }
578
579 auto pos = block_file.tellp();
580
581 static_assert( block_log::max_supported_version > 0, "a version number of zero is not supported" );
582
583 // going back to write correct version to indicate that all block log header data writes completed successfully
585 if(prune_config)
587 block_file.seek( 0 );
588 block_file.write( (char*)&version, sizeof(version) );
589 block_file.seek( pos );
590 flush();
591 }
fc::path get_file_path() const
Definition cfile.hpp:41
void write(const genesis_state &gs)
void append(const signed_block_ptr &b)
void remove_all(const path &p)
constexpr uint32_t pruned_version_flag
Here is the call graph for this function:

◆ try_exit_vacuum()

void sysio::chain::detail::block_log_impl::try_exit_vacuum ( )
inline

Definition at line 72 of file block_log.cpp.

72 {
73 //for a pruned log that has at least one block, see if we should vacuum it
74 if( block_file.is_open() && index_file.is_open() && prune_config && prune_config->vacuum_on_close) {
75 if(!head) {
76 //disregard vacuum_on_close size if there isn't even a block and just do it silently anyways
77 vacuum();
78 }
79 else {
80 const size_t first_data_pos = get_block_pos(first_block_num);
82 const size_t last_data_pos = block_file.tellp();
83 if(last_data_pos - first_data_pos < prune_config->vacuum_on_close) {
84 ilog("Vacuuming pruned block log");
85 vacuum();
86 }
87 }
88 }
89 }
#define ilog(FORMAT,...)
Definition logger.hpp:118
Here is the call graph for this function:

◆ vacuum()

void sysio::chain::detail::block_log_impl::vacuum ( )

Definition at line 477 of file block_log.cpp.

477 {
478 //go ahead and write a new valid header now. if the vacuum fails midway, at least this means maybe the
479 // block recovery can get through some blocks.
480 size_t copy_to_pos = convert_existing_header_to_vacuumed();
481
483 prune_config.reset();
484
485 //if there is no head block though, bail now, otherwise first_block_num won't actually be available
486 // and it'll mess this all up. Be sure to still remove the 4 byte trailer though.
487 if(!head) {
490 return;
491 }
492
493 size_t copy_from_pos = get_block_pos(first_block_num);
494 block_file.seek_end(-sizeof(uint32_t));
495 size_t copy_sz = block_file.tellp() - copy_from_pos;
496 const uint32_t num_blocks_in_log = chain::block_header::num_from_id(head_id) - first_block_num + 1;
497
498 const size_t offset_bytes = copy_from_pos - copy_to_pos;
499 const size_t offset_blocks = first_block_num - index_first_block_num;
500
501 std::vector<char> buff;
502 buff.resize(4*1024*1024);
503
504 auto tick = std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now());
505 while(copy_sz) {
506 const size_t copy_this_round = std::min(buff.size(), copy_sz);
507 block_file.seek(copy_from_pos);
508 block_file.read(buff.data(), copy_this_round);
509 block_file.punch_hole(copy_to_pos, copy_from_pos+copy_this_round);
510 block_file.seek(copy_to_pos);
511 block_file.write(buff.data(), copy_this_round);
512
513 copy_from_pos += copy_this_round;
514 copy_to_pos += copy_this_round;
515 copy_sz -= copy_this_round;
516
517 const auto tock = std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now());
518 if(tick < tock - std::chrono::seconds(5)) {
519 ilog("Vacuuming pruned block log, ${b} bytes remaining", ("b", copy_sz));
520 tick = tock;
521 }
522 }
525
527 {
528 boost::interprocess::mapped_region index_mapped(index_file, boost::interprocess::read_write);
529 uint64_t* index_ptr = (uint64_t*)index_mapped.get_address();
530
531 for(uint32_t new_block_num = 0; new_block_num < num_blocks_in_log; ++new_block_num) {
532 const uint64_t new_pos = index_ptr[new_block_num + offset_blocks] - offset_bytes;
533 index_ptr[new_block_num] = new_pos;
534
535 if(new_block_num + 1 != num_blocks_in_log)
536 block_file.seek(index_ptr[new_block_num + offset_blocks + 1] - offset_bytes - sizeof(uint64_t));
537 else
538 block_file.seek_end(-sizeof(uint64_t));
539 block_file.write((char*)&new_pos, sizeof(new_pos));
540 }
541 }
542 fc::resize_file(index_file.get_file_path(), num_blocks_in_log*sizeof(uint64_t));
543
545 }
uint64_t file_size(const path &p)
void resize_file(const path &file, size_t s)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ write() [1/2]

void sysio::chain::detail::block_log_impl::write ( const chain_id_type & chain_id)

Definition at line 608 of file block_log.cpp.

608 {
609 block_file << chain_id;
610 }

◆ write() [2/2]

void sysio::chain::detail::block_log_impl::write ( const genesis_state & gs)

Definition at line 603 of file block_log.cpp.

603 {
604 auto data = fc::raw::pack(gs);
605 block_file.write(data.data(), data.size());
606 }
Here is the call graph for this function:

Member Data Documentation

◆ block_file

fc::cfile sysio::chain::detail::block_log_impl::block_file

Definition at line 44 of file block_log.cpp.

◆ first_block_num

uint32_t sysio::chain::detail::block_log_impl::first_block_num = 0

Definition at line 49 of file block_log.cpp.

◆ genesis_written_to_block_log

bool sysio::chain::detail::block_log_impl::genesis_written_to_block_log = false

Definition at line 47 of file block_log.cpp.

◆ head

signed_block_ptr sysio::chain::detail::block_log_impl::head

Definition at line 42 of file block_log.cpp.

◆ head_id

block_id_type sysio::chain::detail::block_log_impl::head_id

Definition at line 43 of file block_log.cpp.

◆ index_file

fc::cfile sysio::chain::detail::block_log_impl::index_file

Definition at line 45 of file block_log.cpp.

◆ index_first_block_num

uint32_t sysio::chain::detail::block_log_impl::index_first_block_num = 0

Definition at line 50 of file block_log.cpp.

◆ open_files

bool sysio::chain::detail::block_log_impl::open_files = false

Definition at line 46 of file block_log.cpp.

◆ prune_config

std::optional<block_log_prune_config> sysio::chain::detail::block_log_impl::prune_config

Definition at line 51 of file block_log.cpp.

◆ version

uint32_t sysio::chain::detail::block_log_impl::version = 0

Definition at line 48 of file block_log.cpp.


The documentation for this class was generated from the following file: