github.com/FUSIONFoundation/efsn@v3.6.2-0.20200916075423-dbb5dd5d2cc7+incompatible/swarm/storage/localstore.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package storage 18 19 import ( 20 "context" 21 "path/filepath" 22 "sync" 23 24 "github.com/FusionFoundation/efsn/metrics" 25 "github.com/FusionFoundation/efsn/swarm/log" 26 "github.com/FusionFoundation/efsn/swarm/storage/mock" 27 ) 28 29 type LocalStoreParams struct { 30 *StoreParams 31 ChunkDbPath string 32 Validators []ChunkValidator `toml:"-"` 33 } 34 35 func NewDefaultLocalStoreParams() *LocalStoreParams { 36 return &LocalStoreParams{ 37 StoreParams: NewDefaultStoreParams(), 38 } 39 } 40 41 //this can only finally be set after all config options (file, cmd line, env vars) 42 //have been evaluated 43 func (p *LocalStoreParams) Init(path string) { 44 if p.ChunkDbPath == "" { 45 p.ChunkDbPath = filepath.Join(path, "chunks") 46 } 47 } 48 49 // LocalStore is a combination of inmemory db over a disk persisted db 50 // implements a Get/Put with fallback (caching) logic using any 2 ChunkStores 51 type LocalStore struct { 52 Validators []ChunkValidator 53 memStore *MemStore 54 DbStore *LDBStore 55 mu sync.Mutex 56 } 57 58 // This constructor uses MemStore and DbStore as components 59 func NewLocalStore(params *LocalStoreParams, mockStore *mock.NodeStore) (*LocalStore, error) { 60 ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) 61 dbStore, err := NewMockDbStore(ldbparams, mockStore) 62 if err != nil { 63 return nil, err 64 } 65 return &LocalStore{ 66 memStore: NewMemStore(params.StoreParams, dbStore), 67 DbStore: dbStore, 68 Validators: params.Validators, 69 }, nil 70 } 71 72 func NewTestLocalStoreForAddr(params *LocalStoreParams) (*LocalStore, error) { 73 ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) 74 dbStore, err := NewLDBStore(ldbparams) 75 if err != nil { 76 return nil, err 77 } 78 localStore := &LocalStore{ 79 memStore: NewMemStore(params.StoreParams, dbStore), 80 DbStore: dbStore, 81 Validators: params.Validators, 82 } 83 return localStore, nil 84 } 85 86 // Put is responsible for doing validation and storage of the chunk 87 // by using configured ChunkValidators, MemStore and LDBStore. 88 // If the chunk is not valid, its GetErrored function will 89 // return ErrChunkInvalid. 90 // This method will check if the chunk is already in the MemStore 91 // and it will return it if it is. If there is an error from 92 // the MemStore.Get, it will be returned by calling GetErrored 93 // on the chunk. 94 // This method is responsible for closing Chunk.ReqC channel 95 // when the chunk is stored in memstore. 96 // After the LDBStore.Put, it is ensured that the MemStore 97 // contains the chunk with the same data, but nil ReqC channel. 98 func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error { 99 valid := true 100 // ls.Validators contains a list of one validator per chunk type. 101 // if one validator succeeds, then the chunk is valid 102 for _, v := range ls.Validators { 103 if valid = v.Validate(chunk.Address(), chunk.Data()); valid { 104 break 105 } 106 } 107 if !valid { 108 return ErrChunkInvalid 109 } 110 111 log.Trace("localstore.put", "key", chunk.Address()) 112 ls.mu.Lock() 113 defer ls.mu.Unlock() 114 115 _, err := ls.memStore.Get(ctx, chunk.Address()) 116 if err == nil { 117 return nil 118 } 119 if err != nil && err != ErrChunkNotFound { 120 return err 121 } 122 ls.memStore.Put(ctx, chunk) 123 err = ls.DbStore.Put(ctx, chunk) 124 return err 125 } 126 127 // Get(chunk *Chunk) looks up a chunk in the local stores 128 // This method is blocking until the chunk is retrieved 129 // so additional timeout may be needed to wrap this call if 130 // ChunkStores are remote and can have long latency 131 func (ls *LocalStore) Get(ctx context.Context, addr Address) (chunk Chunk, err error) { 132 ls.mu.Lock() 133 defer ls.mu.Unlock() 134 135 return ls.get(ctx, addr) 136 } 137 138 func (ls *LocalStore) get(ctx context.Context, addr Address) (chunk Chunk, err error) { 139 chunk, err = ls.memStore.Get(ctx, addr) 140 141 if err != nil && err != ErrChunkNotFound { 142 metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) 143 return nil, err 144 } 145 146 if err == nil { 147 metrics.GetOrRegisterCounter("localstore.get.cachehit", nil).Inc(1) 148 return chunk, nil 149 } 150 151 metrics.GetOrRegisterCounter("localstore.get.cachemiss", nil).Inc(1) 152 chunk, err = ls.DbStore.Get(ctx, addr) 153 if err != nil { 154 metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) 155 return nil, err 156 } 157 158 ls.memStore.Put(ctx, chunk) 159 return chunk, nil 160 } 161 162 func (ls *LocalStore) FetchFunc(ctx context.Context, addr Address) func(context.Context) error { 163 ls.mu.Lock() 164 defer ls.mu.Unlock() 165 166 _, err := ls.get(ctx, addr) 167 if err == nil { 168 return nil 169 } 170 return func(context.Context) error { 171 return err 172 } 173 } 174 175 func (ls *LocalStore) BinIndex(po uint8) uint64 { 176 return ls.DbStore.BinIndex(po) 177 } 178 179 func (ls *LocalStore) Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error { 180 return ls.DbStore.SyncIterator(from, to, po, f) 181 } 182 183 // Close the local store 184 func (ls *LocalStore) Close() { 185 ls.DbStore.Close() 186 }