Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tbcd: move block header cache from items to size #360

Merged
merged 18 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 11 additions & 10 deletions cmd/tbcd/tbcd.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Hemi Labs, Inc.
// Copyright (c) 2024-2025 Hemi Labs, Inc.
// Use of this source code is governed by the MIT License,
// which can be found in the LICENSE file.

Expand All @@ -25,7 +25,8 @@ const (
defaultLogLevel = daemonName + "=INFO;tbc=INFO;level=INFO"
defaultNetwork = "testnet3" // XXX make this mainnet
defaultHome = "~/." + daemonName
bhsDefault = int(1e6) // enough for mainnet
bDefaultSize = "1gb" // ~640 blocks on mainnet
bhsDefaultSize = "128mb" // enough for mainnet
)

var (
Expand All @@ -46,16 +47,16 @@ var (
Help: "enable auto utxo and tx indexes",
Print: config.PrintAll,
},
"TBC_BLOCK_CACHE": config.Config{
Value: &cfg.BlockCache,
DefaultValue: 250,
Help: "number of cached blocks",
"TBC_BLOCK_CACHE_SIZE": config.Config{
Value: &cfg.BlockCacheSize,
DefaultValue: bDefaultSize,
Help: "size of block cache",
Print: config.PrintAll,
},
"TBC_BLOCKHEADER_CACHE": config.Config{
Value: &cfg.BlockheaderCache,
DefaultValue: bhsDefault,
Help: "number of cached blockheaders",
"TBC_BLOCKHEADER_CACHE_SIZE": config.Config{
Value: &cfg.BlockheaderCacheSize,
DefaultValue: bhsDefaultSize,
Help: "size of blockheader cache",
Print: config.PrintAll,
},
"TBC_BLOCK_SANITY": config.Config{
Expand Down
13 changes: 12 additions & 1 deletion database/tbcd/database.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2024 Hemi Labs, Inc.
// Copyright (c) 2024-2025 Hemi Labs, Inc.
// Use of this source code is governed by the MIT License,
// which can be found in the LICENSE file.

Expand Down Expand Up @@ -91,6 +91,7 @@ type Database interface {
BlockHeaderBest(ctx context.Context) (*BlockHeader, error) // return canonical
BlockHeaderByHash(ctx context.Context, hash *chainhash.Hash) (*BlockHeader, error)
BlockHeaderGenesisInsert(ctx context.Context, wbh *wire.BlockHeader, height uint64, diff *big.Int) error
BlockHeaderCacheStats() CacheStats

// Block headers
BlockHeadersByHeight(ctx context.Context, height uint64) ([]BlockHeader, error)
Expand All @@ -103,6 +104,7 @@ type Database interface {
BlockInsert(ctx context.Context, b *btcutil.Block) (int64, error)
// BlocksInsert(ctx context.Context, bs []*btcutil.Block) (int64, error)
BlockByHash(ctx context.Context, hash *chainhash.Hash) (*btcutil.Block, error)
BlockCacheStats() CacheStats

// Transactions
BlockUtxoUpdate(ctx context.Context, direction int, utxos map[Outpoint]CacheOutput) error
Expand Down Expand Up @@ -413,3 +415,12 @@ func TxIdBlockHashFromTxKey(txKey TxKey) (*chainhash.Hash, *chainhash.Hash, erro
}
return txId, blockHash, nil
}

// Cache
type CacheStats struct {
Hits int
Misses int
Purges int
Size int
marcopeereboom marked this conversation as resolved.
Show resolved Hide resolved
Items int
}
117 changes: 117 additions & 0 deletions database/tbcd/level/blockcache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) 2025 Hemi Labs, Inc.
// Use of this source code is governed by the MIT License,
// which can be found in the LICENSE file.

package level

import (
"container/list"
"fmt"
"sync"

"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/chaincfg/chainhash"

"github.com/hemilabs/heminetwork/database/tbcd"
)

var blockSize = 1677721 // ~1.6MB rough size of a mainnet block as of Jan 2025

type blockElement struct {
element *list.Element
block []byte
}

type lowIQLRU struct {
mtx sync.Mutex

size int // this is the approximate max size

m map[chainhash.Hash]blockElement
totalSize int

// lru list, when used move to back of the list
l *list.List

// stats
c tbcd.CacheStats
}

func (l *lowIQLRU) Put(v *btcutil.Block) {
l.mtx.Lock()
defer l.mtx.Unlock()

hash := v.Hash()
if _, ok := l.m[*hash]; ok {
return
}

block, err := v.Bytes()
if err != nil {
// data corruption, panic
panic(err)
}

// evict first element in list
if l.totalSize+len(block) > l.size {
// LET THEM EAT PANIC
re := l.l.Front()
rha := l.l.Remove(re)
rh := rha.(*chainhash.Hash)
l.totalSize -= len(l.m[*rh].block)
delete(l.m, *rh)
l.c.Purges++
}

// block lookup and lru append
l.m[*hash] = blockElement{element: l.l.PushBack(hash), block: block}
l.totalSize += len(block)

l.c.Size = l.totalSize
}

func (l *lowIQLRU) Get(k *chainhash.Hash) (*btcutil.Block, bool) {
l.mtx.Lock()
defer l.mtx.Unlock()

be, ok := l.m[*k]
if !ok {
l.c.Misses++
return nil, false
}
b, err := btcutil.NewBlockFromBytes(be.block)
if err != nil {
// panic for diagnostics at this time
panic(err)
}

// update access
l.l.MoveToBack(be.element)

l.c.Hits++

return b, true
}

func (l *lowIQLRU) Stats() tbcd.CacheStats {
l.mtx.Lock()
defer l.mtx.Unlock()
l.c.Items = len(l.m)
return l.c
}

func lowIQLRUSizeNew(size int) (*lowIQLRU, error) {
if size <= 0 {
return nil, fmt.Errorf("invalid size: %v", size)
}
// approximate number of blocks
count := size / blockSize
if count <= 0 {
return nil, fmt.Errorf("invalid count: %v", count)
}
return &lowIQLRU{
size: size,
m: make(map[chainhash.Hash]blockElement, count),
l: list.New(),
}, nil
}
Loading
Loading