0x01 appinitmain Step 7:load block chain
Calculate Cache Size
Freindex = Gargs.getboolarg ("-reindex", false);
BOOL Freindexchainstate = Gargs.getboolarg ("-reindex-chainstate", false);
Cache size Calculations Int64_t Ntotalcache = (Gargs.getarg ("-dbcache", Ndefaultdbcache) << 20); Ntotalcache = Std::max (Ntotalcache, Nmindbcache << 20); Total cache cannot to less than nmindbcache Ntotalcache = Std::min (Ntotalcache, Nmaxdbcache << 20);
Total cache cannot to be greater than nmaxdbcache int64_t Nblocktreedbcache = NTOTALCACHE/8; Nblocktreedbcache = Std::min (Nblocktreedbcache, Gargs.getboolarg ("-txindex", Default_txindex)?
Nmaxblockdbandtxindexcache:nmaxblockdbcache) << 20);
Ntotalcache-= Nblocktreedbcache; int64_t Ncoindbcache = Std::min (NTOTALCACHE/2, (NTOTALCACHE/4) + (1 << 23)); Use 25%-50% of the remainder for disk cache Ncoindbcache = Std::min (Ncoindbcache, Nmaxcoinsdbcache << 20);
Cap total coins db cache ntotalcache-= Ncoindbcache; NCoincacheusage = Ntotalcache; The rest goes to in-memory cache int64_t Nmempoolsizemax = Gargs.getarg ("-maxmempool", default_max_mempool_size) *
1000000;
logprintf ("Cache configuration:\n");
logprintf ("* Using%.1FMIB for block index database\n", Nblocktreedbcache * (1.0/1024/1024));
logprintf ("* Using%.1fmib for chain State database\n", Ncoindbcache * (1.0/1024/1024)); logprintf ("* Using%.1fmib for in-memory Utxo set (plus up to%.1fmib of unused mempool spaces) \ n", Ncoincacheusage * (1.0
/1024/1024), Nmempoolsizemax * (1.0/1024/1024));
-reindex: Rebuilds chain State and block index from Blk*.dat on disk.
-reindex-chainstate: Establishes chain state from the current block index.
-dbcache: Set the database Cache size in megabytes (MB) and the default value is 450.
-txindex: Maintains the complete transaction index, mainly is getrawtransaction this RPC to use, does not enable by default.
-maxmempool: Sets the maximum size of the trading memory pool in megabytes (MB) and the default value is 300.
First get two parameters from the command line, both of which are not enabled by default. The next step is to calculate the size of the cache, first, the total cache size is represented by Ntotalcache, set by the-dbcache parameter, and then the value is taken between Nmindbcache and Nmaxdbcache. Next compute Nblocktreedbcache and Ncoindbcache as well as ncoincacheusage, and Ntotalcache = Nblocktreedbcache +ncoindbcache + Ncoincacheusage. Load Chunk Index
Next is a very long while loop statement, which we use to analyze at 1.1 o ' time.
BOOL floaded = false;
while (!floaded &&!frequestshutdown) {
bool freset = Freindex;
std::string Strloaderror;
Uiinterface.initmessage (_ ("Loading block Index ...");
Nstart = Gettimemillis ();
Do {
try {
unloadblockindex ();
Delete Pcoinstip;
Delete Pcoinsdbview;
Delete Pcoinscatcher;
Delete Pblocktree;
First set a tag variable floaded to indicate if the index load was successful, and if the loop body found the variable to be false and did not request to close the program, execute it again. Since this loop body may execute more than once, call Unloadblockindex () first to clear some of the variables that the last loop might have set, which is implemented as follows Unloadblockindex
May is used after any connections are up as much
//of the peer-processing logic assumes a consistent
/BL Ock index State
void Unloadblockindex ()
{
LOCK (cs_main);//thread safe Access
setblockindexcandidates.clear ();
Chainactive.settip (nullptr);
Pindexbestinvalid = nullptr;
Pindexbestheader = nullptr;
Mempool.clear ();
Mapblocksunlinked.clear ();
Vinfoblockfile.clear ();
Nlastblockfile = 0;
Nblocksequenceid = 1;
Setdirtyblockindex.clear ();
Setdirtyfileinfo.clear ();
Versionbitscache. Clear ();
for (int b = 0; b < versionbits_num_bits; b++) {
warningcache[b].clear ();
}
for (blockmap::value_type& entry:mapblockindex) {
delete entry.second;
}
Mapblockindex.clear (); Maintain all block indices
//mapblockindex type unordered_map<uint256, cblockindex*, blockhasher>
fhavepruned = false;
}
writing to a heavy index
Pblocktree = new Cblocktreedb (Nblocktreedbcache, False, Freset);
if (freset) {
pblocktree->writereindexing (true);
If we ' re reindexing in prune mode, wipe away unusable blocks files and all undo data Files
if (fprunemode)
Cleanu Pblockrevfiles ();
}
if (frequestshutdown) break;
Next, create a Cblocktreedb class, which is used to read and write to the files below/blocks/index/*. Then determine if Freset is true, and this variable is-reindex used to set whether all indexes are recreated, and if true, then call the writereindexing in Cblocktreedb to write the data to the database. The specific invocation process is as follows:
BOOL Cblocktreedb::writereindexing (bool freindexing) {
if (freindexing) return
Write (Db_reindex_flag, ' 1 ');
else return
Erase (db_reindex_flag);
}
Writereindexing then invokes the Write
template <typename K, typename v>
bool (const k& key) inherited from the Cdbwrapper. Const v& value, BOOL Fsync = False)
{
cdbbatch batch (*this);
Batch. Write (key, value);
return Writebatch (batch, fsync);
}
Write again invokes the Writebatch implementation of the same class to write data to the LEVELDB database
//The PDB is the LEVELDB database pointer
bool Cdbwrapper::writebatch ( cdbbatch& batch, bool Fsync)
{
Leveldb::status Status = Pdb->write (fsync? syncoptions:writeoptions, & Amp;batch.batch);
Dbwrapper_private::handleerror (status);
return true;
}
The following Fprunemode parameters have been introduced in http://blog.csdn.net/pure_lady/article/details/77982837#t1, which is used to trim the identified blocks, if the re-indexing is enabled, Then you have to delete the validated chunk information first. The implementation of Cleanupblockrevfiles () is as follows:
If we ' re using-prune with-reindex, then delete block of files that'll be ignored by the//Reindex. Since reindexing works by starting in block file 0 and looping until a blockfile//are missing, do the same this to delete Any later blocks files after a gap. Also Delete all//Rev files since they ' ll be rewritten by the reindex anyway. This ensures that vinfoblockfile//are in sync with what's actually on disk by the time we start downloading
ing//works correctly.
void Cleanupblockrevfiles () {std::map<std::string, fs::p ath> mapblockfiles; Glob All Blk?????. DAT and Rev?????.
DAT files from the blocks directory.
Remove the Rev files immediately and insert the blk file paths into a//ordered map keyed by block file index. logprintf ("Removing unusable blk?????. DAT and Rev?????.
DAT files For-reindex with-prune\n ");
FS::p ath Blocksdir = Getdatadir ()/"blocks"; For (fs::d irectory_iterator it (blocksdir); it!= fs::d irectory_iteRator (); it++) {if Is_regular_file (*it) && it->path (). FileName (). String (). Length () = = &&
; It->path (). FileName (). String (). substr (8,4) = ". Dat") {if (It->path (). FileName (). String (). Subst
R (0,3) = = "Blk") Mapblockfiles[it->path (). FileName (). String (). substr (3,5)] = It->path ();
else if (It->path (). FileName (). String (). substr (0,3) = = "Rev") Remove (It->path ()); }//Remove all blocks files that aren ' t part of a contiguous set starting at//zero by walking the ordered Map (keys are block file indices) by//keeping a separate counter.
Once we hit a gap (or if 0 doesn ' t exist)//start removing block files.
int ncontigcounter = 0; for (const std::p air<std::string, fs::p ath>& item:mapblockfiles) {if (atoi (item.first) = = Ncontigcoun
ter) {ncontigcounter++;
Continue
} Remove (Item.second); }
}
First explain the comments at the beginning, if we use-reindex and-prune, then delete some chunk files that are not considered when the index is indexed. Because a heavy index is a continuous read from block No. 0, it stops reading until a chunk of information is missing, and all blocks are deleted immediately after the missing block. Also need to delete rev file, because these files will be regenerated when the index is indexed, the introduction of Rev file, can refer to the http://blog.csdn.net/pure_lady/article/details/77982837#t1 mentioned before. according to the contents of the annotation, the function is to delete all the chunk data after a missing block, and the file at the beginning of Rev. Then the next code is easier to read: First, all the files and corresponding paths are saved to a map, and then use a variable Ncontigcounter starting from 0 count, until the first inconsistent file name is encountered, from this start to delete. Loadblockindex
Loadblockindex'll load Ftxindex from the DB, or set it if
//we ' re reindexing. It'll also load fhavepruned if we ' ve
//ever removed a block file from disk.
Note This It also sets Freindex based on the disk flag!
From the out freindex and freset mean something different!
if (! Loadblockindex (Chainparams)) {
Strloaderror = _ ("Error Loading Block Database");
break;
Explanation: loadblockindex First loads the Ftxindex variable from the database and reads the Ftxindex value from the command line if it is being indexed. In addition, if we have deleted the block file before, then there will be a shelf AH fhavepruned variable, but also according to the disk on the tag to set the Freindex variable, and then Freindex and Freset will represent different meanings. Let's take a look at the implementation of Loadblockindex:
bool loadblockindex (const cchainparams& chainparams) {//Load block index from databases
bool Needs_init = Freindex;
if (!freindex) {BOOL ret = LOADBLOCKINDEXDB (chainparams);
if (!ret) return false;
Needs_init = Mapblockindex.empty (); } if (Needs_init) {//Everything is for *new* Reindex/dbs. Thus, though//LOADBLOCKINDEXDB may have set freindex if we shut down//Mid-reindex Previously, we don ' t
Check freindex and//instead only check it prior to loadblockindexdb to set//Needs_init.
logprintf ("Initializing databases...\n"); Use the provided setting For-txindex the new database Ftxindex = Gargs.getboolarg ("-txindex", Default_txind
EX);
Pblocktree->writeflag ("Txindex", Ftxindex);
return true; }
First parameter chainparams is described before, which sets statically written parameters based on different network main,regtest,testnet three different parameters. Then check the Freindex variable, if the variable is set, then the index will be indexed, there is no need to load the index first, if not set Freindex, then this is the first load is the only place to load the index. The so-called load index, is to load the files in the/blocks/index/* into memory, the implementation is through the LOADBLOCKINDEXDB () and the results are saved in the variable mapblockindex, if the load is successful, then Mapblockindex is not empty , Needs_init is false. legality detection
Check if the Mapblockindex is loaded in the Genesis block if (!mapblockindex.empty () && Mapblockindex.count (Chai Nparams. Getconsensus (). hashgenesisblock) = = 0) return Initerror (_ ("Incorrect or no Genesis block found.")
Wrong datadir for network? ")); Check the state of the Txindex, because if Reindex is set in the previous function (Loadblockindex), then Ftxindex will also be reset if (Ftxindex!= Gargs.getboolarg ("-txindex", Default_txindex)) {Strloaderror = _ ("You need to rebuild the database us
Ing-reindex to Change-txindex ");
Break //Check the status of the-prune, because the user may manually delete some files and/or now want to run if (fhavepruned &am in a mode that is not deleted) p;&!fprunemode) {Strloaderror = _ ("You need to rebuild the database Using-reindex unpruned mode.
This would redownload the entire blockchain ");
Break //If no initialization is set, andFailure to load the Genesis block if (!freindex &&!)
Loadgenesisblock (Chainparams)) {Strloaderror = _ ("Error Initializing Block Database");
Break }