btcd中database代码详解
在btcd.go文件中,函数loadBlockDB根据配置初始化了相应的数据库
func loadBlockDB() (database.DB, error) { // The memdb backend does not have a file path associated with it, so // handle it uniquely. We also don't want to worry about the multiple // database type warnings when running with the memory database. if cfg.DbType == "memdb" { btcdLog.Infof("Creating block database in memory.") db, err := database.Create(cfg.DbType) if err != nil { return nil, err } return db, nil } warnMultipleDBs() // The database name is based on the database type. dbPath := blockDbPath(cfg.DbType) // The regression test is special in that it needs a clean database for // each run, so remove it now if it already exists. removeRegressionDB(dbPath) btcdLog.Infof("Loading block database from '%s'", dbPath) db, err := database.Open(cfg.DbType, dbPath, activeNetParams.Net) if err != nil { // Return the error if it's not because the database doesn't // exist. if dbErr, ok := err.(database.Error); !ok || dbErr.ErrorCode != database.ErrDbDoesNotExist { return nil, err } // Create the db if it does not exist. err = os.MkdirAll(cfg.DataDir, 0700) if err != nil { return nil, err } db, err = database.Create(cfg.DbType, dbPath, activeNetParams.Net) if err != nil { return nil, err } } btcdLog.Info("Block database loaded") return db, nil }
在btcdMain函数中,调用loadBlockDB()获得数据库的句柄,通过newservre配置blockchain对象
server, err := newServer(cfg.Listeners, db, activeNetParams.Params,interrupt)
loadBlockDB()返回的是btcd中定义的数据库的接口,接口的定义如下:
// DB provides a generic interface that is used to store bitcoin blocks and // related metadata. This interface is intended to be agnostic to the actual // mechanism used for backend data storage. The RegisterDriver function can be // used to add a new backend data storage method. // // This interface is divided into two distinct categories of functionality. // // The first category is atomic metadata storage with bucket support. This is // accomplished through the use of database transactions. // // The second category is generic block storage. This functionality is // intentionally separate because the mechanism used for block storage may or // may not be the same mechanism used for metadata storage. For example, it is // often more efficient to store the block data as flat files while the metadata // is kept in a database. However, this interface aims to be generic enough to // support blocks in the database too, if needed by a particular backend. type DB interface { // Type returns the database driver type the current database instance // was created with. Type() string // Begin starts a transaction which is either read-only or read-write // depending on the specified flag. Multiple read-only transactions // can be started simultaneously while only a single read-write // transaction can be started at a time. The call will block when // starting a read-write transaction when one is already open. // // NOTE: The transaction must be closed by calling Rollback or Commit on // it when it is no longer needed. Failure to do so can result in // unclaimed memory and/or inablity to close the database due to locks // depending on the specific database implementation. Begin(writable bool) (Tx, error) // View invokes the passed function in the context of a managed // read-only transaction. Any errors returned from the user-supplied // function are returned from this function. // // Calling Rollback or Commit on the transaction passed to the // user-supplied function will result in a panic. View(fn func(tx Tx) error) error // Update invokes the passed function in the context of a managed // read-write transaction. Any errors returned from the user-supplied // function will cause the transaction to be rolled back and are // returned from this function. Otherwise, the transaction is committed // when the user-supplied function returns a nil error. // // Calling Rollback or Commit on the transaction passed to the // user-supplied function will result in a panic. Update(fn func(tx Tx) error) error // Close cleanly shuts down the database and syncs all data. It will // block until all database transactions have been finalized (rolled // back or committed). Close() error }
函数处理收到的block
func (b *BlockChain) ProcessBlock(block *btcutil.Block, flags BehaviorFlags) (bool, bool, error)
该函数会检查block的合法性,并且确认该block和该block之前的block是否也存在在数据库中。如果都满足要求则写入到数据库,写入数据库的代码函数如下:
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, flags BehaviorFlags) (bool, error)
函数dbStoreBlock把block信息放入pendingBlockData数组,
在transaction的commit方法中,把block信息写进数据库,一个transaction可以存放多个block,然后一次写入文件。
在transcation的writePendingAndCommit()方法中,把数据写入数据库
在这个函数中打开leveldb数据库
func openDB(dbPath string, network wire.BitcoinNet, create bool) (database.DB, error) {
transcation 的commit方法
在writePendingAndCommit()中有写数据库
最后调用到这个函数