太坊ソース解読データベースethdb


Ethernetデータベースethdb


ソースの場所:ethereum/go-ethereum/ethdb
. ├── database.go//leveldbパッケージ├——database_js.go//├-database_はしばらくサポートされていませんjs_test.go ├── database_test.go//試験用例├——interface.go//データベースインタフェース定義├——memory_database.go//メモリデータベース、├をテストするために使用する-table.go//テーブル操作パッケージbatch.go//テーブル操作パッケージ
エーテル坊のデータストレージはeveldb,nosql key-valueデータベースで使用されます.
leveldbの特徴:
  • keyとvalueはいずれも任意の長さのバイト配列である.
  • entry(すなわちK-Vレコード)のデフォルトはkeyの辞書順に格納され、もちろん開発者もこのソート関数を再ロードすることができる.
  • が提供する基本操作インタフェース:Put()、Delete()、Get()、Batch()
  • は、原子操作で一括操作をサポートする.
  • は、データパノラマのsnapshot(スナップショット)を作成し、スナップショット内のデータの検索を許可することができる.
  • は、順方向(または後方向)反復器によってデータを巡回することができる(反復器はsnapshotを暗黙的に作成する).
  • Snappyを使用してデータを自動的に圧縮します.
  • 移植性;

  • memory_database.go


    太坊テストでメモリデータベースを使用し、ソースコードでmemory_を実現database.go中です.mapをカプセル化し、ロックを使用して安全なアクセスを行います.
    type MemDatabase struct {
       db   map[string][]byte
        //  lock 
       lock sync.RWMutex
    }
    //  
    func NewMemDatabaseWithCap(size int) *MemDatabase {
    	return &MemDatabase{
    		db: make(map[string][]byte, size),
    	}
    }
    //  , 
    func (db *MemDatabase) Put(key []byte, value []byte) error {
    	db.lock.Lock()
    	defer db.lock.Unlock()
    	db.db[string(key)] = common.CopyBytes(value)
    	return nil
    }
    
    func (db *MemDatabase) Has(key []byte) (bool, error) {
    	...
    }
    
    func (db *MemDatabase) Get(key []byte) ([]byte, error) {
    	...
    }
    
    func (db *MemDatabase) Len() int { return len(db.db) }
    
    

    bathロット操作同様
    type memBatch struct {
       db     *MemDatabase
       writes []kv
       size   int
    }
    

    interface.go


    データベースを定義した操作を削除して閉じるなど
    package ethdb
    
    //  .
    const IdealBatchSize = 100 * 1024
    
    // 
    type Putter interface {
       Put(key []byte, value []byte) error
    }
    
    // .
    type Deleter interface {
       Delete(key []byte) error
    }
    // Database wraps all database operations. All methods are safe for concurrent use.
    //  , 、 、 。 
    type Database interface {
       Putter
       Deleter
       Get(key []byte) ([]byte, error)
       Has(key []byte) (bool, error)
       Close()
       NewBatch() Batch
    }
    
    // Batch is a write-only database that commits changes to its host database
    // when Write is called. Batch cannot be used concurrently.
    //  
    type Batch interface {
       Putter
       Deleter
       ValueSize() int // amount of data in the batch
       Write() error
       // Reset resets the batch for reuse
       Reset()
    }
    

    database.go


    パッケージlevelDB、leveldbソースコードhttps://github.com/syndtr/goleveldb.太坊でmeterシステムを使用してデータベースのパフォーマンス統計を行う
    type LDBDatabase struct {
       fn string      // filename for reporting
       db *leveldb.DB // LevelDB instance
    	// metter 
       compTimeMeter    metrics.Meter // Meter for measuring the total time spent in database 		// 
       quitLock sync.Mutex      // Mutex protecting the quit channel access
        //  meter
       quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
    
       //  
       log log.Logger // Contextual logger tracking the database path
    }
    
    // NewLDBDatabase returns a LevelDB wrapped object.
    //  db  file db 
    func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error) {
       logger := log.New("database", file)
    
       // Ensure we have some minimal caching and file guarantees
       if cache < 16 {
          cache = 16
       }
       if handles < 16 {
          handles = 16
       }
       logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024), "handles", handles)
    
       // Open the db and recover any potential corruptions
        //  , 
       db, err := leveldb.OpenFile(file, &opt.Options{
          OpenFilesCacheCapacity: handles,
          BlockCacheCapacity:     cache / 2 * opt.MiB,
          WriteBuffer:            cache / 4 * opt.MiB, // Two of these are used internally
          Filter:                 filter.NewBloomFilter(10),
       })
       
       if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
          db, err = leveldb.RecoverFile(file, nil)
       }
       // (Re)check for errors and abort if opening of the db failed
        //  , nil
       if err != nil {
          return nil, err
       }
       return &LDBDatabase{
          fn:  file,
          db:  db,
          log: logger,
       }, nil
    }
    

    leveldb内部ではマルチスレッドアクセスがサポートされているため、ここではlock制御を必要とせずに直接呼び出すことができます.
    //  
    func (db *LDBDatabase) Put(key []byte, value []byte) error {
       return db.db.Put(key, value, nil)
    }
    //  
    func (db *LDBDatabase) Has(key []byte) (bool, error) {
       return db.db.Has(key, nil)
    }
    
    // 
    func (db *LDBDatabase) Get(key []byte) ([]byte, error) {
       dat, err := db.db.Get(key, nil)
       if err != nil {
          return nil, err
       }
       return dat, nil
    }
    
    //  
    func (db *LDBDatabase) Delete(key []byte) error {
       return db.db.Delete(key, nil)
    }
    //  
    func (db *LDBDatabase) NewIterator() iterator.Iterator {
       return db.db.NewIterator(nil, nil)
    }
    

    受信した接頭辞に基づいてコレクタを初期化し、quitchainを作成します.
    // Meter configures the database metrics collectors and
    func (db *LDBDatabase) Meter(prefix string) {
    	// Initialize all the metrics collector at the requested prefix
    	db.compTimeMeter = metrics.NewRegisteredMeter(prefix+"compact/time", nil)
    	db.compReadMeter = metrics.NewRegisteredMeter(prefix+"compact/input", nil)
    	db.compWriteMeter = metrics.NewRegisteredMeter(prefix+"compact/output", nil)
    	db.diskReadMeter = metrics.NewRegisteredMeter(prefix+"disk/read", nil)
    	db.diskWriteMeter = metrics.NewRegisteredMeter(prefix+"disk/write", nil)
    	db.writeDelayMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/duration", nil)
    	db.writeDelayNMeter = metrics.NewRegisteredMeter(prefix+"compact/writedelay/counter", nil)
    
    	// Create a quit channel for the periodic collector and run it
    	db.quitLock.Lock()
    	db.quitChan = make(chan chan error)
    	db.quitLock.Unlock()
    
        //  3 
    	go db.meter(3 * time.Second)
    }
    
    //  metrics 
    //  
    // This is how a stats table look like (currently):
    //   Compactions
    //    Level |   Tables   |    Size(MB)   |    Time(sec)  |    Read(MB)   |   Write(MB)
    //   -------+------------+---------------+---------------+---------------+---------------
    //      0   |          0 |       0.00000 |       1.27969 |       0.00000 |      12.31098
    //      1   |         85 |     109.27913 |      28.09293 |     213.92493 |     214.26294
    //      2   |        523 |    1000.37159 |       7.26059 |      66.86342 |      66.77884
    //      3   |        570 |    1113.18458 |       0.00000 |       0.00000 |       0.00000
    //
    // This is how the write delay look like (currently):
    //  
    // DelayN:5 Delay:406.604657ms Paused: false
    //
    // This is how the iostats look like (currently):
    // io 
    // Read(MB):3895.04860 Write(MB):3654.64712