github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/storage/localstore.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:49</date> 10 //</624342681564221440> 11 12 // 13 // 14 // 15 // 16 // 17 // 18 // 19 // 20 // 21 // 22 // 23 // 24 // 25 // 26 // 27 28 package storage 29 30 import ( 31 "context" 32 "encoding/binary" 33 "fmt" 34 "path/filepath" 35 "sync" 36 37 "github.com/ethereum/go-ethereum/metrics" 38 "github.com/ethereum/go-ethereum/swarm/log" 39 "github.com/ethereum/go-ethereum/swarm/storage/mock" 40 ) 41 42 type LocalStoreParams struct { 43 *StoreParams 44 ChunkDbPath string 45 Validators []ChunkValidator `toml:"-"` 46 } 47 48 func NewDefaultLocalStoreParams() *LocalStoreParams { 49 return &LocalStoreParams{ 50 StoreParams: NewDefaultStoreParams(), 51 } 52 } 53 54 // 55 // 56 func (p *LocalStoreParams) Init(path string) { 57 if p.ChunkDbPath == "" { 58 p.ChunkDbPath = filepath.Join(path, "chunks") 59 } 60 } 61 62 // 63 // 64 type LocalStore struct { 65 Validators []ChunkValidator 66 memStore *MemStore 67 DbStore *LDBStore 68 mu sync.Mutex 69 } 70 71 // 72 func NewLocalStore(params *LocalStoreParams, mockStore *mock.NodeStore) (*LocalStore, error) { 73 ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) 74 dbStore, err := NewMockDbStore(ldbparams, mockStore) 75 if err != nil { 76 return nil, err 77 } 78 return &LocalStore{ 79 memStore: NewMemStore(params.StoreParams, dbStore), 80 DbStore: dbStore, 81 Validators: params.Validators, 82 }, nil 83 } 84 85 func NewTestLocalStoreForAddr(params *LocalStoreParams) (*LocalStore, error) { 86 ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) 87 dbStore, err := NewLDBStore(ldbparams) 88 if err != nil { 89 return nil, err 90 } 91 localStore := &LocalStore{ 92 memStore: NewMemStore(params.StoreParams, dbStore), 93 DbStore: dbStore, 94 Validators: params.Validators, 95 } 96 return localStore, nil 97 } 98 99 // 100 // 101 // 102 // 103 // 104 // 105 // 106 // 107 // 108 // 109 // 110 // 111 func (ls *LocalStore) Put(ctx context.Context, chunk *Chunk) { 112 valid := true 113 // 114 // 115 for _, v := range ls.Validators { 116 if valid = v.Validate(chunk.Addr, chunk.SData); valid { 117 break 118 } 119 } 120 if !valid { 121 log.Trace("invalid chunk", "addr", chunk.Addr, "len", len(chunk.SData)) 122 chunk.SetErrored(ErrChunkInvalid) 123 chunk.markAsStored() 124 return 125 } 126 127 log.Trace("localstore.put", "addr", chunk.Addr) 128 129 ls.mu.Lock() 130 defer ls.mu.Unlock() 131 132 chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) 133 134 memChunk, err := ls.memStore.Get(ctx, chunk.Addr) 135 switch err { 136 case nil: 137 if memChunk.ReqC == nil { 138 chunk.markAsStored() 139 return 140 } 141 case ErrChunkNotFound: 142 default: 143 chunk.SetErrored(err) 144 return 145 } 146 147 ls.DbStore.Put(ctx, chunk) 148 149 // 150 newc := NewChunk(chunk.Addr, nil) 151 newc.SData = chunk.SData 152 newc.Size = chunk.Size 153 newc.dbStoredC = chunk.dbStoredC 154 155 ls.memStore.Put(ctx, newc) 156 157 if memChunk != nil && memChunk.ReqC != nil { 158 close(memChunk.ReqC) 159 } 160 } 161 162 // 163 // 164 // 165 // 166 func (ls *LocalStore) Get(ctx context.Context, addr Address) (chunk *Chunk, err error) { 167 ls.mu.Lock() 168 defer ls.mu.Unlock() 169 170 return ls.get(ctx, addr) 171 } 172 173 func (ls *LocalStore) get(ctx context.Context, addr Address) (chunk *Chunk, err error) { 174 chunk, err = ls.memStore.Get(ctx, addr) 175 if err == nil { 176 if chunk.ReqC != nil { 177 select { 178 case <-chunk.ReqC: 179 default: 180 metrics.GetOrRegisterCounter("localstore.get.errfetching", nil).Inc(1) 181 return chunk, ErrFetching 182 } 183 } 184 metrics.GetOrRegisterCounter("localstore.get.cachehit", nil).Inc(1) 185 return 186 } 187 metrics.GetOrRegisterCounter("localstore.get.cachemiss", nil).Inc(1) 188 chunk, err = ls.DbStore.Get(ctx, addr) 189 if err != nil { 190 metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) 191 return 192 } 193 chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) 194 ls.memStore.Put(ctx, chunk) 195 return 196 } 197 198 // 199 func (ls *LocalStore) GetOrCreateRequest(ctx context.Context, addr Address) (chunk *Chunk, created bool) { 200 metrics.GetOrRegisterCounter("localstore.getorcreaterequest", nil).Inc(1) 201 202 ls.mu.Lock() 203 defer ls.mu.Unlock() 204 205 var err error 206 chunk, err = ls.get(ctx, addr) 207 if err == nil && chunk.GetErrored() == nil { 208 metrics.GetOrRegisterCounter("localstore.getorcreaterequest.hit", nil).Inc(1) 209 log.Trace(fmt.Sprintf("LocalStore.GetOrRetrieve: %v found locally", addr)) 210 return chunk, false 211 } 212 if err == ErrFetching && chunk.GetErrored() == nil { 213 metrics.GetOrRegisterCounter("localstore.getorcreaterequest.errfetching", nil).Inc(1) 214 log.Trace(fmt.Sprintf("LocalStore.GetOrRetrieve: %v hit on an existing request %v", addr, chunk.ReqC)) 215 return chunk, false 216 } 217 // 218 metrics.GetOrRegisterCounter("localstore.getorcreaterequest.miss", nil).Inc(1) 219 log.Trace(fmt.Sprintf("LocalStore.GetOrRetrieve: %v not found locally. open new request", addr)) 220 chunk = NewChunk(addr, make(chan bool)) 221 ls.memStore.Put(ctx, chunk) 222 return chunk, true 223 } 224 225 // 226 func (ls *LocalStore) RequestsCacheLen() int { 227 return ls.memStore.requests.Len() 228 } 229 230 // 231 func (ls *LocalStore) Close() { 232 ls.DbStore.Close() 233 } 234