太坊ソース解読データベースethdb
30538 ワード
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の特徴:
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