这一节讲解AppInitParameterInteraction 函数。
本来计划上周写的,结果由于自己的心态不是很好,有点抗拒,可能是研读难度加大,再加上最近比较忙,不自觉产生了逃避的想法,结果拖到今天才调节好心态重新面对。遇到困难很多人都会选择躲避,这是基因决定的,正如我们的祖先在外遇到野兽都会选择撒腿就跑,因为保命要紧,这样想就释然了不是,哈哈。或者,换个思路想,一眼就看懂的简单事情还有必要浪费时间去钻研吗? 另外,要想长期坚持做一件事,还得赋予其重大的意义。
好了,开始今天的研读。AppInitParameterInteraction这个函数包括Step 2和Step 3,主要是一些参数设置。
(1)区块修剪与区块索引设置
首先看第一个判断,通过注释,我们得出区块pruning与txindex 不兼容,如鱼和熊掌一般,二者只能取其一。
// if using block pruning, then disallow txindex
if (GetArg("-prune", 0)) {
if (GetBoolArg("-txindex", DEFAULT_TXINDEX))
return InitError(_("Prune mode is incompatible with -txindex."));
}
那么什么是block pruning?翻译过来就是区块修剪。这也是在0.11版本后面才实现的功能,根据bitcoin release-note文档说明:
翻译:一旦raw block 和 undo data已经被验证并且已经更新到数据库了, 区块修剪允许比特币核心系统删除这些数据。此时这些原始数据之后被用来转发区块到其他节点,处理区块的重组,查找旧交易(假如启用了-txindex 交易索引,或者通过调用 RPC/REST 接口的方式),或者重新扫描钱包。 块索引继续保留区块链上所有区块的元数据。
我们知道,比特币系统中存在四种数据类型:
1. raw blocks:从网络中接收到的原始区块文件,对应文件blk???.dat
2. undo data:在进行chain reorganization时使用的数据,对应文件名rev???.dat
3. block index:区块索引,每个区块都有一个唯一的索引,可以在~/.bitcoin/blocks/index目录下找到xxx.ldb文件,即level db数据库。
4. UTXO set:Unspent transaction output.,表示所有未花费的交易。可以在~/.bitcoin/blockstate目录下看到xxx.ldb文件。
这里需要修剪的就是raw block以及undo data这两种数据。有人要问,为什么要用修剪这个词呢?因为修剪是针对默克尔树而言的,所以使用修剪这个词恰到好处。修剪的作用在于节省存储空间。
至于txindex参数,则是维护一个全交易索引。
看完下面这段话,你就知道了,之所以不能同时指定这两个参数,因为一个是删除文件,另一个则是重新建立全交易索引,下载整个完整区块链数据,这完全是相反的做法。
Once you have pruned blocks, going back to unpruned state requires re-downloading the entire blockchain. To do this, re-start the node with -reindex. Note also that any problem that would cause a user to reindex (e.g., disk corruption) will cause a pruned node to redownload the entire blockchain. Finally, note that when a pruned node reindexes, it will delete any blk???.dat and rev???.dat files in the data directory prior to restarting the download.
(2)监听与绑定设置
继续看下一个判断:
// -bind and -whitebind can't be set when not listening
size_t nUserBind = gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size();
if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) {
return InitError("Cannot set -bind or -whitebind together with -listen=0");
}
这个比较好理解: 如果没有设置监听,就不能设置-bind and -whitebind这两个参数。 bind和whitebind是绑定监听地址。
(3)最大连接数设置
// Make sure enough file descriptors are available
int nBind = std::max(nUserBind, size_t(1));
nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS);
nMaxConnections = std::max(nUserMaxConnections, 0);
// Trim requested connection counts, to fit into system limitations
nMaxConnections = std::max(std::min(nMaxConnections, (int)(FD_SETSIZE - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS)), 0);
nFD = RaiseFileDescriptorLimit(nMaxConnections + MIN_CORE_FILEDESCRIPTORS + MAX_ADDNODE_CONNECTIONS);
if (nFD < MIN_CORE_FILEDESCRIPTORS)
return InitError(_("Not enough file descriptors available."));
nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections);
if (nMaxConnections < nUserMaxConnections)
InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections));
注释是说要确保有足够的文件描述符可用,那么什么是文件描述符呢?这里通过一篇文章科普下:
转载自:http://blog.csdn.net/cywosp/article/details/38965239
在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。文件描述符(file descriptor)是内核为了高效管理已被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符。程序刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。如果此时去打开一个新的文件,它的文件描述符会是3。POSIX标准要求每次打开文件时(含socket)必须使用当前进程中*最小可用的文件描述符号码,因此,在网络通信过程中稍不注意就有可能造成串话*。
在编写文件操作的或者网络通信的软件时,初学者一般可能会遇到“Too many open files”的问题。这主要是因为文件描述符是系统的一个重要资源,虽然说系统内存有多少就可以打开多少的文件描述符,但是在实际实现过程中内核是会做相应的处理的,一般最大打开文件数会是系统内存的10%(以KB来计算)(称之为系统级限制)转载: http://blog.csdn.net/cywosp/article/details/38965239
在Web服务器中,通过更改系统默认值文件描述符的最大值来优化服务器是最常见的方式之一,具体优化方式请查看http://blog.csdn.net/kumu_linux/article/details/7877770。
文件描述符是系统的一个重要资源,而系统资源是有限的,所以必须对连接数加以限制。
这里,nUserBind就是统计绑定地址的数量。
DEFAULT_MAX_PEER_CONNECTIONS:定义于src/net.h中,代表了最大可维护的节点连接数量,默认是125个。
/** The maximum number of peer connections to maintain. */
static const unsigned intDEFAULT_MAX_PEER_CONNECTIONS = 125;
然后开始计算最大连接数,以下是代码用到的变量以及解释:
#define FD_SETSIZE 1024 // max number of fds in fd_set
代表系统对单个进程的用户级限制,值为1024。
#ifdef WIN32
// Win32 LevelDB doesn't use filedescriptors, and the ones used for
// accessing block files don't count towards the fd_set size limit
// anyway.
#define MIN_CORE_FILEDESCRIPTORS 0
#else
#define MIN_CORE_FILEDESCRIPTORS 150 #endif
最小核心文件描述符数量,window下为0,其他系统为150.
/** Maximum number of addnode outgoing nodes */
static const int MAX_ADDNODE_CONNECTIONS = 8;
最大的增加节点连接数量,默认值为8.
今天就不讲太多了, 理由你懂的。不懂的话继续关注,你会从中找到答案的。
下次继续讲AppInitParameterInteraction 函数的 step3.
作者:区块链研习社比特币源码研读班 Jacky
网友评论