Go-ethereum 源碼解析之 go-ethereum/ethdb/database.go

Go-ethereum 源碼解析之 go-ethereum/ethdb/database.go


Source code

// Copyright 2017 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.


Appendix A. 總體批注

實現(xiàn)了底層數(shù)據(jù)庫 LevelDB 的抽象層 LDBDatabase,用于生產(chǎn)環(huán)境。

ethdb.LDBDatabase 實現(xiàn)了接口 ethdb.Database完箩,并且將實際的操作轉(zhuǎn)發(fā)給 LevelDB 的接口泵喘。同時,基于 metrics.Meter 測試各操作的性能秆乳。

ethdb.ldbBatch 在 ethdb.LDBDatabase 的基礎(chǔ)上提供了批處理能力懦鼠。

暫時不深入與性能相關(guān)的實現(xiàn) metrics.Meter钻哩。


Appendix B. 詳細批注

1. const

  • writePauseWarningThrottler = 1 * time.Minute: ??? 性能相關(guān)指標

2. var

  • var OpenFileLimit = 64: ??? LevelDB 一次能打開的文件數(shù)量上限?

3. type LDBDatabase struct

數(shù)據(jù)結(jié)構(gòu) LDBDatabase 實現(xiàn)了接口 ethdb.Database肛冶,并且將實際的操作轉(zhuǎn)發(fā)給 LevelDB 的接口街氢。同時,基于 metrics.Meter 測試各操作的性能睦袖。

  • fn string: 文件名珊肃。??? 干什么的文件名呢?

  • db *leveldb.DB: LevelDB 實例

  • compTimeMeter metrics.Meter // Meter for measuring the total time spent in database compaction

  • compReadMeter metrics.Meter // Meter for measuring the data read during compaction

  • compWriteMeter metrics.Meter // Meter for measuring the data written during compaction

  • writeDelayNMeter metrics.Meter // Meter for measuring the write delay number due to database compaction

  • writeDelayMeter metrics.Meter // Meter for measuring the write delay duration due to database compaction

  • diskReadMeter metrics.Meter // Meter for measuring the effective amount of data read

  • diskWriteMeter metrics.Meter // Meter for measuring the effective amount of data written

  • quitLock sync.Mutex // Mutex protecting the quit channel access

  • quitChan chan chan error // Quit channel to stop the metrics collection before closing the database

  • log log.Logger // Contextual logger tracking the database path

3.1 func NewLDBDatabase(file string, cache int, handles int) (*LDBDatabase, error)

構(gòu)造函數(shù) NewLDBDatabase() 創(chuàng)建 LDBDatabase 的一個實例扣泊,該實例是 LevelDB 的包裝器近范。

參數(shù):

  • file string: 文件名
  • cache int: ??? 緩存?
  • handles int: ??? 處理器延蟹?

返回值:

  • LDBDatabase 實例
  • 出錯返回錯誤消息 error评矩,否則返回 nil

主要實現(xiàn):

  • 構(gòu)建日志器 logger

    • logger := log.New("database", file)
  • 調(diào)整 cache,確保其最小值為 16

  • 調(diào)整 handles阱飘,確保其最小值為 16

  • 輸出日志信息:logger.Info("Allocated cache and file handles", "cache", cache, "handles", handles)

  • 打開 LevelDB斥杜,并從可能的錯誤恢復(fù)

    • db, err := leveldb.OpenFile(file, ...)
    • corrupted := err.(*errors.ErrCorrupted)
    • db, err = leveldb.RecoverFile(file, nil)
  • 如果 err 不為 nil,則直接退出

    • return nil, err
  • 構(gòu)建 LDBDatabase 的實例并返回

    • return &LDBDatabase{fn: file, db: db, log: logger}, nil

注意沥匈,這里并沒有初始化任何性能計時器蔗喂。

3.2 func (db *LDBDatabase) Path() string

方法 Path() 返回數(shù)據(jù)庫目錄的路徑。

3.3 func (db *LDBDatabase) Put(key []byte, value []byte) error

方法 Put() 實現(xiàn)了接口 ethdb.Putter 和接口 ethdb.Database高帖,將 key & value 寫入數(shù)據(jù)庫缰儿。

參數(shù):

  • key []byte: key
  • value []byte: value

返回值:

  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 LevelDB 的方法 Put()
    • return db.db.Put(key, value, nil)

3.4 func (db *LDBDatabase) Has(key []byte) (bool, error)

方法 Has() 實現(xiàn)了接口 ethdb.Database散址,查詢給定的 key 是否存在于數(shù)據(jù)庫乖阵。

參數(shù):

  • key []byte: key

返回值:

  • 存在返回 true,否則返回 false
  • 出錯返回錯誤消息 error预麸,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 LevelDB 的方法 Has()
    • return db.db.Has(key, nil)

3.5 func (db *LDBDatabase) Get(key []byte) ([]byte, error)

方法 Get() 實現(xiàn)了接口 ethdb.Database瞪浸,從數(shù)據(jù)庫中獲取給定 key 對應(yīng)的 value蕾殴。

參數(shù):

  • key []byte: key

返回值:

  • 存在返回 key 對應(yīng)的 value
  • 出錯返回錯誤消息 error闹丐,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 LevelDB 的方法 Get()
    • dat, err := db.db.Get(key, nil)

3.6 func (db *LDBDatabase) Delete(key []byte) error

方法 Delete() 實現(xiàn)了接口 ethdb.Database,從數(shù)據(jù)庫中刪除指定的 key川蒙。

參數(shù):

  • key []byte: key

返回值:

  • 出錯返回錯誤消息 error贡翘,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 LevelDB 的方法 Delete()
    • return db.db.Delete(key, nil)

3.7 func (db *LDBDatabase) NewIterator() iterator.Iterator

方法 NewIterator() 返回 LevelDB 的迭代器 iterator.Iterator蹈矮。

返回值:

  • LevelDB 的迭代器 iterator.Iterator

主要實現(xiàn):

  • return db.db.NewIterator(nil, nil)

3.8 func (db *LDBDatabase) NewIteratorWithPrefix(prefix []byte) iterator.Iterator

方法 NewIteratorWithPrefix() 返回 LevelDB 的迭代器 iterator.Iterator,這個迭代器指向具有指定前綴的數(shù)據(jù)庫子集床估。

參數(shù):

  • prefix []byte: 前綴

返回值:

  • LevelDB 的迭代器 iterator.Iterator

主要實現(xiàn):

  • return db.db.NewIterator(util.BytesPrefix(prefix), nil)

3.9 func (db *LDBDatabase) Close()

方法 Close() 實現(xiàn)了接口 ethdb.Database含滴。

主要實現(xiàn):

  • ??? 停止性能指標器
  • 將實際的關(guān)閉操作轉(zhuǎn)發(fā)給 LevelDB 的方法 Close()
    • err := db.db.Close()
    • 如果 err == nil
      • db.log.Info("Database closed")
    • 否則
      • db.log.Error("Failed to close database", "err", err)

3.10 func (db *LDBDatabase) LDB() *leveldb.DB

方法 LDB() 返回 LDBDatabase 中的底層 LevelDB 數(shù)據(jù)庫。

返回值:

  • LDBDatabase 中的底層 LevelDB 數(shù)據(jù)庫丐巫。

主要實現(xiàn):

  • return db.db

3.11 func (db *LDBDatabase) Meter(prefix string)

性能指標相關(guān)內(nèi)容谈况,暫時不關(guān)注勺美。

3.12 func (db *LDBDatabase) meter(refresh time.Duration)

性能指標相關(guān)內(nèi)容,暫時不關(guān)注碑韵。

3.13 func (db *LDBDatabase) NewBatch() Batch

方法 NewBatch() 返回批處理器赡茸。

返回值:

  • 批處理器 ldbBatch

主要實現(xiàn):

  • return &ldbBatch{db: db.db, b: new(leveldb.Batch)}

4. type ldbBatch struct

數(shù)據(jù)結(jié)構(gòu) ldbBatch 在 LevelDB 的基礎(chǔ)上提供批處理能力。

  • db *leveldb.DB: 底層的 LevelDB
  • b *leveldb.Batch: LevelDB 的批處理器
  • size int: 字節(jié)數(shù)

4.1 func (b *ldbBatch) Put(key, value []byte) error

方法 Put() 實現(xiàn)了接口 ethdb.Putter 和接口 ethdb.Batch祝闻,將 key & value 寫入數(shù)據(jù)庫占卧。

參數(shù):

  • key []byte: key
  • value []byte: value

返回值:

  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 leveldb.Batch 的方法 Put()
    • b.b.Put(key, value)
  • 更新字節(jié)數(shù)
    • b.size += len(value)

4.2 func (b *ldbBatch) Delete(key []byte) error

方法 Delete() 實現(xiàn)了接口 ethdb.Deleter 和接口 ethdb.Batch联喘,從數(shù)據(jù)庫中刪除指定的 key华蜒。

參數(shù):

  • key []byte: key

返回值:

  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 leveldb.Batch 的方法 Delete()
    • b.b.Delete(key)
  • 更新字節(jié)數(shù)
    • b.size += 1

4.3 func (b *ldbBatch) Write() error

方法 Write() 實現(xiàn)了接口 ethdb.Batch豁遭,將批量數(shù)據(jù)一次性寫入數(shù)據(jù)庫叭喜。

返回值:

  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • return b.db.Write(b.b, nil)

4.4 func (b *ldbBatch) ValueSize() int

方法 ValueSize() 實現(xiàn)了接口 ethdb.Batch蓖谢,返回批量字節(jié)數(shù)捂蕴。

返回值:

  • 批量字節(jié)數(shù)

主要實現(xiàn):

  • return b.size

4.5 func (b *ldbBatch) Reset()

方法 Reset() 實現(xiàn)了接口 ethdb.Batch,重置數(shù)據(jù)庫闪幽。

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 leveldb.Batch 的方法 Reset()
    • b.b.Reset()
  • 更新字節(jié)數(shù)
    • b.size = 0

5. type table struct

數(shù)據(jù)結(jié)構(gòu) table 封裝了數(shù)據(jù)庫 Database啥辨,描述 Database 中的 key 具有相同的前綴 prefix。

  • db Database: 數(shù)據(jù)庫
  • prefix string: 前綴

5.1 func NewTable(db Database, prefix string) Database

構(gòu)造函數(shù) NewTable() 創(chuàng)建數(shù)據(jù)庫盯腌,同時數(shù)據(jù)庫中的 key 具有相同的前綴 prefix溉知。

參數(shù):

  • db Database: 數(shù)據(jù)庫
  • prefix string: 前綴

返回值:

  • 數(shù)據(jù)庫

主要實現(xiàn):

  • return &table{db: db, prefix: prefix,}

5.2 func (dt *table) Put(key []byte, value []byte) error

方法 Put() 實現(xiàn)了接口 ethdb.Putter 和接口 ethdb.Database。

參數(shù):

  • key []byte: key
  • value []byte: value

返回值:

  • 出錯返回錯誤消息 error腕够,否則返回 nil

主要實現(xiàn):

  • 給 key 加上前綴 prefix着倾,同時轉(zhuǎn)發(fā)給 Database 的方法 Put()
    • dt.db.Put(append([]byte(dt.prefix), key...), value)

5.3 func (dt *table) Has(key []byte) (bool, error)

方法 Has() 實現(xiàn)了接口 ethdb.Database。

參數(shù):

  • key []byte: key

返回值:

  • 存在返回 true燕少,否則返回 false
  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 給 key 加上前綴 prefix蒿囤,同時轉(zhuǎn)發(fā)給 Database 的方法 Has()
    • dt.db.Has(append([]byte(dt.prefix), key...))

5.4 func (dt *table) Get(key []byte) ([]byte, error)

方法 Get() 實現(xiàn)了接口 ethdb.Database客们。

參數(shù):

  • key []byte: key

返回值:

  • 存在返回 key 對應(yīng)的 value
  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 給 key 加上前綴 prefix材诽,同時轉(zhuǎn)發(fā)給 Database 的方法 Get()
    • dt.db.Get(append([]byte(dt.prefix), key...))

5.5 func (dt *table) Delete(key []byte) error

方法 Delete() 實現(xiàn)了接口 ethdb.Deleter 和接口 ethdb.Database底挫。

參數(shù):

  • key []byte: key

返回值:

  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 給 key 加上前綴 prefix脸侥,同時轉(zhuǎn)發(fā)給 Database 的方法 Delete()
    • dt.db.Delete(append([]byte(dt.prefix), key...))

5.6 func (dt *table) Close()

方法 Close() 不執(zhí)行任何操作建邓。注意,這里并不會關(guān)閉底層數(shù)據(jù)庫睁枕。

5.7 func (dt *table) NewBatch() Batch

方法 NewBatch() 返回具有批處理能力的 ethdb.table官边。

返回值:

  • 具有批處理能力的 ethdb.tableBatch

主要實現(xiàn):

  • return &tableBatch{dt.db.NewBatch(), dt.prefix}

6. type tableBatch struct

數(shù)據(jù)結(jié)構(gòu) tableBatch 封裝了數(shù)據(jù)庫 Database沸手,描述 Database 中的 key 具有相同的前綴 prefix。同時注簿,提供批處理能力契吉。

  • batch Batch: 批處理
  • prefix string: 前綴

6.1 func NewTableBatch(db Database, prefix string) Batch

構(gòu)造函數(shù) NewTableBatch() 創(chuàng)建具有批處理能力的數(shù)據(jù)庫,同時數(shù)據(jù)庫中的 key 具有相同的前綴 prefix诡渴。

參數(shù):

  • db Database: 數(shù)據(jù)庫
  • prefix string: 前綴

返回值:

  • 具有批處理能力數(shù)據(jù)庫

主要實現(xiàn):

  • return &tableBatch{db.NewBatch(), prefix}

6.2 func (tb *tableBatch) Put(key, value []byte) error

方法 Put() 實現(xiàn)了接口 ethdb.Putter 和接口 ethdb.Batch捐晶,將 key & value 插入數(shù)據(jù)庫。

參數(shù):

  • key []byte: key
  • value []byte: value

返回值:

  • 出錯返回錯誤消息 error妄辩,否則返回 nil

主要實現(xiàn):

  • 給 key 加上前綴 prefix惑灵,同時轉(zhuǎn)發(fā)給 ethdb.Batch 的方法 Put()
    • return tb.batch.Put(append([]byte(tb.prefix), key...), value)

6.3 func (tb *tableBatch) Delete(key []byte) error

方法 Delete() 實現(xiàn)了接口 ethdb.Deleter 和接口 ethdb.Batch,從數(shù)據(jù)庫中刪除給定的 key眼耀。

參數(shù):

  • key []byte: key

返回值:

  • 出錯返回錯誤消息 error英支,否則返回 nil

主要實現(xiàn):

  • 給 key 加上前綴 prefix,同時轉(zhuǎn)發(fā)給 ethdb.Batch 的方法 Delete()
    • return tb.batch.Delete(append([]byte(tb.prefix), key...))

6.4 func (tb *tableBatch) Write() error

方法 Write() 實現(xiàn)了接口 ethdb.Batch畔塔,將批處理數(shù)據(jù)一次性寫入數(shù)據(jù)庫潭辈。

返回值:

  • 出錯返回錯誤消息 error,否則返回 nil

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 ethdb.Batch 的方法 Write()
    • return tb.batch.Write()

6.5 func (tb *tableBatch) ValueSize() int

方法 ValueSize() 實現(xiàn)了接口 ethdb.Batch澈吨,返回批處理數(shù)據(jù)的字節(jié)數(shù)把敢。

返回值:

  • 批處理數(shù)據(jù)字節(jié)數(shù)

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 ethdb.Batch 的方法 ValueSize()
    • return tb.batch.ValueSize()

6.6 func (tb *tableBatch) Reset()

方法 Reset() 實現(xiàn)了接口 ethdb.Batch谅辣,清空批處理數(shù)據(jù)修赞。

主要實現(xiàn):

  • 轉(zhuǎn)發(fā)給 ethdb.Batch 的方法 Reset()
    • tb.batch.Reset()

Reference

  1. https://github.com/ethereum/go-ethereum/blob/master/ethdb/database.go

Contributor

  1. Windstamp, https://github.com/windstamp
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末柏副,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蚣录,更是在濱河造成了極大的恐慌割择,老刑警劉巖萎河,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異虐杯,居然都是意外死亡玛歌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門擎椰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人值朋,你說我怎么就攤上這事⊥碳撸” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵稽坤,是天一觀的道長糯俗。 經(jīng)常有香客問我,道長得湘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任摆马,我火速辦了婚禮鸿吆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘惩淳。我一直安慰自己,他們只是感情好代虾,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布激蹲。 她就那樣靜靜地躺著,像睡著了一般学辱。 火紅的嫁衣襯著肌膚如雪含蓉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天项郊,我揣著相機與錄音,去河邊找鬼着降。 笑死,一個胖子當(dāng)著我的面吹牛任洞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播交掏,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼盅弛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了挪鹏?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤解取,失蹤者是張志新(化名)和其女友劉穎返顺,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體遂鹊,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年昆码,在試婚紗的時候發(fā)現(xiàn)自己被綠了邻储。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡脓匿,死狀恐怖宦赠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情勾扭,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布桅滋,位于F島的核電站,受9級特大地震影響芍碧,放射性物質(zhì)發(fā)生泄漏号俐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一踪危、第九天 我趴在偏房一處隱蔽的房頂上張望找岖。 院中可真熱鬧,春花似錦许布、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颖榜,卻和暖如春掩完,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背且蓬。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诈胜,地道東北人冯事。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像缓熟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子荚虚,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容