consensus/p2pool/cache/legacy/legacy.go

117 lines
2.5 KiB
Go

package legacy
import (
"encoding/binary"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/p2p"
"git.gammaspectra.live/P2Pool/p2pool-observer/p2pool/sidechain"
"io"
"log"
"os"
"sync"
"sync/atomic"
"time"
)
const blockSize = 96 * 1024
const numBlocks = 4608
const cacheSize = blockSize * numBlocks
type Cache struct {
f *os.File
flushRunning atomic.Bool
storeIndex atomic.Uint32
loadingStarted sync.Once
loadingInProgress atomic.Bool
}
func NewCache(path string) (*Cache, error) {
if f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666); err != nil {
return nil, err
} else {
if _, err = f.Seek(cacheSize-1, io.SeekStart); err != nil {
_ = f.Close()
return nil, err
}
//create sparse file
if _, err = f.Write([]byte{0}); err != nil {
_ = f.Close()
return nil, err
}
return &Cache{
f: f,
}, nil
}
}
func (c *Cache) Store(block *sidechain.PoolBlock) {
if c.loadingInProgress.Load() {
return
}
if blob, err := block.MarshalBinary(); err != nil {
return
} else {
if (len(blob) + 4) > blockSize {
//block too big
return
}
storeIndex := (c.storeIndex.Add(1) % numBlocks) * blockSize
_, _ = c.f.WriteAt(binary.LittleEndian.AppendUint32(nil, uint32(len(blob))), int64(storeIndex))
_, _ = c.f.WriteAt(blob, int64(storeIndex)+4)
}
}
func (c *Cache) LoadAll(s *p2p.Server) {
c.loadingStarted.Do(func() {
c.loadingInProgress.Store(true)
defer c.loadingInProgress.Store(false)
log.Print("[Cache] Loading cached blocks")
var blobLen [4]byte
buf := make([]byte, 0, blockSize)
var blocksLoaded int
for i := 0; i < numBlocks; i++ {
storeIndex := (c.storeIndex.Add(1) % numBlocks) * blockSize
if _, err := c.f.ReadAt(blobLen[:], int64(storeIndex)); err != nil {
return
}
blobLength := binary.LittleEndian.Uint32(blobLen[:])
if (blobLength + 4) > blockSize {
//block too big
continue
}
if _, err := c.f.ReadAt(buf[:blobLength], int64(storeIndex)+4); err != nil {
continue
}
block := &sidechain.PoolBlock{
NetworkType: s.Consensus().NetworkType,
LocalTimestamp: uint64(time.Now().Unix()),
}
if err := block.UnmarshalBinary(buf[:blobLength]); err != nil {
continue
}
s.AddCachedBlock(block)
blocksLoaded++
}
log.Printf("[Cache] Loaded %d cached blocks", blocksLoaded)
})
}
func (c *Cache) Close() {
_ = c.f.Close()
}
func (c *Cache) Flush() {
if !c.flushRunning.Swap(true) {
defer c.flushRunning.Store(false)
_ = c.f.Sync()
}
}