github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:45</date> 10 //</624450120179519488> 11 12 13 package storage 14 15 import ( 16 "context" 17 "path/filepath" 18 "sync" 19 20 "github.com/ethereum/go-ethereum/metrics" 21 "github.com/ethereum/go-ethereum/swarm/log" 22 "github.com/ethereum/go-ethereum/swarm/storage/mock" 23 ) 24 25 type LocalStoreParams struct { 26 *StoreParams 27 ChunkDbPath string 28 Validators []ChunkValidator `toml:"-"` 29 } 30 31 func NewDefaultLocalStoreParams() *LocalStoreParams { 32 return &LocalStoreParams{ 33 StoreParams: NewDefaultStoreParams(), 34 } 35 } 36 37 //这只能在所有配置选项(文件、命令行、env vars)之后最终设置。 38 //已经过评估 39 func (p *LocalStoreParams) Init(path string) { 40 if p.ChunkDbPath == "" { 41 p.ChunkDbPath = filepath.Join(path, "chunks") 42 } 43 } 44 45 //localstore是InMemory数据库与磁盘持久化数据库的组合 46 //使用任意2个chunkstore实现带有回退(缓存)逻辑的get/put 47 type LocalStore struct { 48 Validators []ChunkValidator 49 memStore *MemStore 50 DbStore *LDBStore 51 mu sync.Mutex 52 } 53 54 //此构造函数使用memstore和dbstore作为组件 55 func NewLocalStore(params *LocalStoreParams, mockStore *mock.NodeStore) (*LocalStore, error) { 56 ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) 57 dbStore, err := NewMockDbStore(ldbparams, mockStore) 58 if err != nil { 59 return nil, err 60 } 61 return &LocalStore{ 62 memStore: NewMemStore(params.StoreParams, dbStore), 63 DbStore: dbStore, 64 Validators: params.Validators, 65 }, nil 66 } 67 68 func NewTestLocalStoreForAddr(params *LocalStoreParams) (*LocalStore, error) { 69 ldbparams := NewLDBStoreParams(params.StoreParams, params.ChunkDbPath) 70 dbStore, err := NewLDBStore(ldbparams) 71 if err != nil { 72 return nil, err 73 } 74 localStore := &LocalStore{ 75 memStore: NewMemStore(params.StoreParams, dbStore), 76 DbStore: dbStore, 77 Validators: params.Validators, 78 } 79 return localStore, nil 80 } 81 82 //如果块通过任何本地存储验证程序,则isvalid返回true。 83 //如果localstore没有验证器,isvalid也返回true。 84 func (ls *LocalStore) isValid(chunk Chunk) bool { 85 //默认情况下,块是有效的。如果我们有0个验证器,那么所有的块都是有效的。 86 valid := true 87 88 //validators包含每个块类型一个validator的列表。 89 //如果一个验证器成功,那么块是有效的 90 for _, v := range ls.Validators { 91 if valid = v.Validate(chunk); valid { 92 break 93 } 94 } 95 return valid 96 } 97 98 //Put负责验证和存储块 99 //通过使用配置的chunkvalidator、memstore和ldbstore。 100 //如果区块无效,则其getErrored函数将 101 //返回errchunkinvalid。 102 //此方法将检查块是否已在memstore中 103 //如果是的话,它会退回的。如果出现错误 104 //memstore.get,将通过调用getErrored返回 105 //在块上。 106 //此方法负责关闭chunk.reqc通道 107 //当块存储在memstore中时。 108 //在ldbstore.put之后,确保memstore 109 //包含具有相同数据但没有reqc通道的块。 110 func (ls *LocalStore) Put(ctx context.Context, chunk Chunk) error { 111 if !ls.isValid(chunk) { 112 return ErrChunkInvalid 113 } 114 115 log.Trace("localstore.put", "key", chunk.Address()) 116 ls.mu.Lock() 117 defer ls.mu.Unlock() 118 119 _, err := ls.memStore.Get(ctx, chunk.Address()) 120 if err == nil { 121 return nil 122 } 123 if err != nil && err != ErrChunkNotFound { 124 return err 125 } 126 ls.memStore.Put(ctx, chunk) 127 err = ls.DbStore.Put(ctx, chunk) 128 return err 129 } 130 131 //get(chunk*chunk)在本地商店中查找一个chunk 132 //在获取块之前,此方法正在阻塞 133 //因此,如果 134 //chunkstore是远程的,可以有很长的延迟 135 func (ls *LocalStore) Get(ctx context.Context, addr Address) (chunk Chunk, err error) { 136 ls.mu.Lock() 137 defer ls.mu.Unlock() 138 139 return ls.get(ctx, addr) 140 } 141 142 func (ls *LocalStore) get(ctx context.Context, addr Address) (chunk Chunk, err error) { 143 chunk, err = ls.memStore.Get(ctx, addr) 144 145 if err != nil && err != ErrChunkNotFound { 146 metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) 147 return nil, err 148 } 149 150 if err == nil { 151 metrics.GetOrRegisterCounter("localstore.get.cachehit", nil).Inc(1) 152 go ls.DbStore.MarkAccessed(addr) 153 return chunk, nil 154 } 155 156 metrics.GetOrRegisterCounter("localstore.get.cachemiss", nil).Inc(1) 157 chunk, err = ls.DbStore.Get(ctx, addr) 158 if err != nil { 159 metrics.GetOrRegisterCounter("localstore.get.error", nil).Inc(1) 160 return nil, err 161 } 162 163 ls.memStore.Put(ctx, chunk) 164 return chunk, nil 165 } 166 167 func (ls *LocalStore) FetchFunc(ctx context.Context, addr Address) func(context.Context) error { 168 ls.mu.Lock() 169 defer ls.mu.Unlock() 170 171 _, err := ls.get(ctx, addr) 172 if err == nil { 173 return nil 174 } 175 return func(context.Context) error { 176 return err 177 } 178 } 179 180 func (ls *LocalStore) BinIndex(po uint8) uint64 { 181 return ls.DbStore.BinIndex(po) 182 } 183 184 func (ls *LocalStore) Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error { 185 return ls.DbStore.SyncIterator(from, to, po, f) 186 } 187 188 //关闭本地存储 189 func (ls *LocalStore) Close() { 190 ls.DbStore.Close() 191 } 192 193 //迁移检查数据存储架构与运行时架构并运行 194 //迁移如果不匹配 195 func (ls *LocalStore) Migrate() error { 196 actualDbSchema, err := ls.DbStore.GetSchema() 197 if err != nil { 198 log.Error(err.Error()) 199 return err 200 } 201 202 if actualDbSchema == CurrentDbSchema { 203 return nil 204 } 205 206 log.Debug("running migrations for", "schema", actualDbSchema, "runtime-schema", CurrentDbSchema) 207 208 if actualDbSchema == DbSchemaNone { 209 ls.migrateFromNoneToPurity() 210 actualDbSchema = DbSchemaPurity 211 } 212 213 if err := ls.DbStore.PutSchema(actualDbSchema); err != nil { 214 return err 215 } 216 217 if actualDbSchema == DbSchemaPurity { 218 if err := ls.migrateFromPurityToHalloween(); err != nil { 219 return err 220 } 221 actualDbSchema = DbSchemaHalloween 222 } 223 224 if err := ls.DbStore.PutSchema(actualDbSchema); err != nil { 225 return err 226 } 227 return nil 228 } 229 230 func (ls *LocalStore) migrateFromNoneToPurity() { 231 //删除无效的块,即不通过的块 232 //任何ls.validator 233 ls.DbStore.Cleanup(func(c *chunk) bool { 234 return !ls.isValid(c) 235 }) 236 } 237 238 func (ls *LocalStore) migrateFromPurityToHalloween() error { 239 return ls.DbStore.CleanGCIndex() 240 } 241