Hook RPC call and record DB read operation count

This commit is contained in:
celo.choi 2024-03-22 16:03:46 +09:00
parent 0809c46266
commit 522c63cc3a
4 changed files with 159 additions and 3 deletions

View file

@ -19,6 +19,7 @@ package rawdb
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/hook"
"math"
"os"
"path/filepath"
@ -186,7 +187,13 @@ func (f *Freezer) Close() error {
// in the freezer.
func (f *Freezer) HasAncient(kind string, number uint64) (bool, error) {
if table := f.tables[kind]; table != nil {
return table.has(number), nil
if table.has(number) {
bytes, err := table.Retrieve(number)
if len(bytes) > 0 && err != nil {
hook.Gr.CountAncientDbRead(bytes)
}
return true, nil
}
}
return false, nil
}
@ -194,7 +201,11 @@ func (f *Freezer) HasAncient(kind string, number uint64) (bool, error) {
// Ancient retrieves an ancient binary blob from the append-only immutable files.
func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) {
if table := f.tables[kind]; table != nil {
return table.Retrieve(number)
bytes, err := table.Retrieve(number)
if len(bytes) > 0 && err != nil {
hook.Gr.CountAncientDbRead(bytes)
}
return bytes, err
}
return nil, errUnknownTable
}

View file

@ -22,6 +22,7 @@ package leveldb
import (
"fmt"
"github.com/ethereum/go-ethereum/hook"
"strings"
"sync"
"time"
@ -185,11 +186,13 @@ func (db *Database) Close() error {
// Has retrieves if a key is present in the key-value store.
func (db *Database) Has(key []byte) (bool, error) {
hook.Gr.CountLevelDbRead(key)
return db.db.Has(key, nil)
}
// Get retrieves the given key if it's present in the key-value store.
func (db *Database) Get(key []byte) ([]byte, error) {
hook.Gr.CountLevelDbRead(key)
dat, err := db.db.Get(key, nil)
if err != nil {
return nil, err
@ -469,12 +472,14 @@ type snapshot struct {
// Has retrieves if a key is present in the snapshot backing by a key-value
// data store.
func (snap *snapshot) Has(key []byte) (bool, error) {
hook.Gr.CountLevelDbSnapshotRead(key)
return snap.db.Has(key, nil)
}
// Get retrieves the given key if it's present in the snapshot backing by
// key-value data store.
func (snap *snapshot) Get(key []byte) ([]byte, error) {
hook.Gr.CountLevelDbSnapshotRead(key)
return snap.db.Get(key, nil)
}

132
hook/record.go Normal file
View file

@ -0,0 +1,132 @@
package hook
import "sync"
type Record struct {
ancientDbReadCnt int // ancient DB 접근 횟수
levelDbReadCnt int // level DB 접근 횟수
levelDbSnapshotReadCnt int // level DB 스냅샷 접근 횟수
duplicatedReadCnt int // 중복 디비 접근 횟수
duplicatedSnapshotReadCnt int // 중복 스냅샷 접근 횟수
readDbKeySet *map[string]bool
readDbKeySetLock sync.RWMutex
readSnapshotDbKeySet *map[string]bool
readSnapshotDbKeySetLock sync.RWMutex
rpcLock sync.Mutex
}
var Gr = Record{
ancientDbReadCnt: 0,
levelDbReadCnt: 0,
levelDbSnapshotReadCnt: 0,
duplicatedReadCnt: 0,
duplicatedSnapshotReadCnt: 0,
readDbKeySet: &map[string]bool{},
readDbKeySetLock: sync.RWMutex{},
readSnapshotDbKeySet: &map[string]bool{},
readSnapshotDbKeySetLock: sync.RWMutex{},
rpcLock: sync.Mutex{},
}
func (gr *Record) Lock() {
gr.rpcLock.Lock()
}
func (gr *Record) Unlock() {
gr.rpcLock.Unlock()
}
func (gr *Record) Reset() {
gr.ancientDbReadCnt = 0
gr.levelDbReadCnt = 0
gr.levelDbSnapshotReadCnt = 0
gr.duplicatedReadCnt = 0
gr.duplicatedSnapshotReadCnt = 0
gr.readDbKeySet = &map[string]bool{}
gr.readSnapshotDbKeySet = &map[string]bool{}
}
func (gr *Record) addReadKeySet(key string) {
gr.readDbKeySetLock.Lock()
defer gr.readDbKeySetLock.Unlock()
(*gr.readDbKeySet)[key] = true
}
func (gr *Record) addReadSnapshotKeySet(key string) {
gr.readSnapshotDbKeySetLock.Lock()
defer gr.readSnapshotDbKeySetLock.Unlock()
(*gr.readSnapshotDbKeySet)[key] = true
}
func (gr *Record) isAlreadyRead(key string) bool {
gr.readDbKeySetLock.RLock()
defer gr.readDbKeySetLock.RUnlock()
if (*gr.readDbKeySet)[key] == true {
return true
}
return false
}
func (gr *Record) countDuplicatedKey(key []byte) {
keyStr := string(key[:])
if gr.isAlreadyRead(keyStr) {
gr.duplicatedReadCnt++
} else {
gr.addReadKeySet(keyStr)
}
}
func (gr *Record) isAlreadyReadSnapshot(key string) bool {
gr.readSnapshotDbKeySetLock.RLock()
defer gr.readSnapshotDbKeySetLock.RUnlock()
if (*gr.readSnapshotDbKeySet)[key] == true {
return true
}
return false
}
func (gr *Record) countDuplicatedSnapshotKey(key []byte) {
keyStr := string(key[:])
if gr.isAlreadyReadSnapshot(keyStr) {
gr.duplicatedSnapshotReadCnt++
} else {
gr.addReadSnapshotKeySet(keyStr)
}
}
func (gr *Record) CountAncientDbRead(key []byte) {
gr.countDuplicatedKey(key)
gr.ancientDbReadCnt++
}
func (gr *Record) CountLevelDbRead(key []byte) {
gr.countDuplicatedKey(key)
gr.levelDbReadCnt++
}
func (gr *Record) CountLevelDbSnapshotRead(key []byte) {
gr.countDuplicatedSnapshotKey(key)
gr.levelDbSnapshotReadCnt++
}
func (gr *Record) AncientDbReadCnt() int {
return gr.ancientDbReadCnt
}
func (gr *Record) LevelDbReadCnt() int {
return gr.levelDbReadCnt
}
func (gr *Record) LevelDbSnapshotReadCnt() int {
return gr.levelDbSnapshotReadCnt
}
func (gr *Record) DuplicatedReadCnt() int {
return gr.duplicatedReadCnt
}
func (gr *Record) DuplicatedSnapshotReadCnt() int {
return gr.duplicatedSnapshotReadCnt
}

View file

@ -19,6 +19,7 @@ package rpc
import (
"context"
"encoding/json"
"github.com/ethereum/go-ethereum/hook"
"reflect"
"strconv"
"strings"
@ -509,8 +510,15 @@ func (h *handler) handleCall(cp *callProc, msg *jsonrpcMessage) *jsonrpcMessage
return msg.errorResponse(&invalidParamsError{err.Error()})
}
start := time.Now()
answer := h.runMethod(cp.ctx, msg, callb, args)
hook.Gr.Lock()
hook.Gr.Reset()
h.log.Error("Before runMethod", "msg.Method", msg.Method, "args", args)
answer := h.runMethod(cp.ctx, msg, callb, args)
h.log.Error("Result", "levelDb", hook.Gr.LevelDbReadCnt(), "levelDb duplicated", hook.Gr.DuplicatedReadCnt(), "levelDbSnapshot", hook.Gr.LevelDbSnapshotReadCnt(), "levelDbSnapshot duplicated", hook.Gr.DuplicatedSnapshotReadCnt(), "ancientDb", hook.Gr.AncientDbReadCnt())
h.log.Error("Statistics", "levelDbNewRead", hook.Gr.LevelDbReadCnt()-hook.Gr.DuplicatedReadCnt(), "levelDbSnapshotNewRead", hook.Gr.LevelDbSnapshotReadCnt()-hook.Gr.DuplicatedSnapshotReadCnt(), "ancientDbRead", hook.Gr.AncientDbReadCnt())
h.log.Error("After runMethod", "msg.Method", msg.Method, "args", args)
hook.Gr.Unlock()
// Collect the statistics for RPC calls if metrics is enabled.
// We only care about pure rpc call. Filter out subscription.
if callb != h.unsubscribeCb {