git.gammaspectra.live/P2Pool/consensus/v3@v3.8.0/p2pool/cache/legacy/legacy.go (about) 1 package legacy 2 3 import ( 4 "encoding/binary" 5 "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/cache" 6 "git.gammaspectra.live/P2Pool/consensus/v3/p2pool/sidechain" 7 "git.gammaspectra.live/P2Pool/consensus/v3/utils" 8 "io" 9 "os" 10 "sync" 11 "sync/atomic" 12 "time" 13 ) 14 15 const blockSize = 96 * 1024 16 const NumBlocks = 4608 17 const cacheSize = blockSize * NumBlocks 18 19 type Cache struct { 20 f *os.File 21 flushRunning atomic.Bool 22 storeIndex atomic.Uint32 23 loadingStarted sync.Once 24 loadingInProgress atomic.Bool 25 consensus *sidechain.Consensus 26 } 27 28 func NewCache(consensus *sidechain.Consensus, path string) (*Cache, error) { 29 if f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0666); err != nil { 30 return nil, err 31 } else { 32 if _, err = f.Seek(cacheSize-1, io.SeekStart); err != nil { 33 _ = f.Close() 34 return nil, err 35 } 36 //create sparse file 37 if _, err = f.Write([]byte{0}); err != nil { 38 _ = f.Close() 39 return nil, err 40 } 41 42 return &Cache{ 43 f: f, 44 consensus: consensus, 45 }, nil 46 } 47 } 48 49 func (c *Cache) Store(block *sidechain.PoolBlock) { 50 if c.loadingInProgress.Load() { 51 return 52 } 53 if blob, err := block.AppendBinaryFlags(make([]byte, 0, block.BufferLength()), false, false); err != nil { 54 return 55 } else { 56 if (len(blob) + 4) > blockSize { 57 //block too big 58 return 59 } 60 storeIndex := (c.storeIndex.Add(1) % NumBlocks) * blockSize 61 _, _ = c.f.WriteAt(binary.LittleEndian.AppendUint32(nil, uint32(len(blob))), int64(storeIndex)) 62 _, _ = c.f.WriteAt(blob, int64(storeIndex)+4) 63 } 64 } 65 66 func (c *Cache) LoadAll(l cache.Loadee) { 67 c.loadingStarted.Do(func() { 68 c.loadingInProgress.Store(true) 69 defer c.loadingInProgress.Store(false) 70 utils.Logf("Cache", "Loading cached blocks") 71 72 var blobLen [4]byte 73 buf := make([]byte, 0, blockSize) 74 75 var blocksLoaded int 76 for i := 0; i < NumBlocks; i++ { 77 storeIndex := (c.storeIndex.Add(1) % NumBlocks) * blockSize 78 79 if _, err := c.f.ReadAt(blobLen[:], int64(storeIndex)); err != nil { 80 return 81 } 82 blobLength := binary.LittleEndian.Uint32(blobLen[:]) 83 if (blobLength + 4) > blockSize { 84 //block too big 85 continue 86 } 87 if _, err := c.f.ReadAt(buf[:blobLength], int64(storeIndex)+4); err != nil { 88 continue 89 } 90 91 block := &sidechain.PoolBlock{ 92 Metadata: sidechain.PoolBlockReceptionMetadata{ 93 LocalTime: time.Now().UTC(), 94 }, 95 } 96 97 if err := block.UnmarshalBinary(c.consensus, &sidechain.NilDerivationCache{}, buf[:blobLength]); err != nil { 98 continue 99 } 100 101 l.AddCachedBlock(block) 102 103 blocksLoaded++ 104 } 105 106 utils.Logf("Cache", "Loaded %d cached blocks", blocksLoaded) 107 }) 108 } 109 110 func (c *Cache) Close() { 111 _ = c.f.Close() 112 } 113 114 func (c *Cache) Flush() { 115 if !c.flushRunning.Swap(true) { 116 defer c.flushRunning.Store(false) 117 _ = c.f.Sync() 118 } 119 }