github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/storage/netstore.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 //</624450121240678400> 11 12 13 package storage 14 15 import ( 16 "context" 17 "encoding/hex" 18 "fmt" 19 "sync" 20 "sync/atomic" 21 "time" 22 23 "github.com/ethereum/go-ethereum/p2p/enode" 24 "github.com/ethereum/go-ethereum/swarm/log" 25 lru "github.com/hashicorp/golang-lru" 26 ) 27 28 type ( 29 NewNetFetcherFunc func(ctx context.Context, addr Address, peers *sync.Map) NetFetcher 30 ) 31 32 type NetFetcher interface { 33 Request(ctx context.Context, hopCount uint8) 34 Offer(ctx context.Context, source *enode.ID) 35 } 36 37 //NetStore是本地存储的扩展 38 //它实现chunkstore接口 39 //根据请求,它使用获取器启动远程云检索 40 //取数器对块是唯一的,并存储在取数器的LRU内存缓存中。 41 //fetchfuncFactory是为特定块地址创建提取函数的工厂对象 42 type NetStore struct { 43 mu sync.Mutex 44 store SyncChunkStore 45 fetchers *lru.Cache 46 NewNetFetcherFunc NewNetFetcherFunc 47 closeC chan struct{} 48 } 49 50 var fetcherTimeout = 2 * time.Minute //即使请求正在传入,也要超时以取消获取程序 51 52 //NewNetStore使用给定的本地存储创建新的NetStore对象。newfetchfunc是一个 53 //可以为特定块地址创建提取函数的构造函数函数。 54 func NewNetStore(store SyncChunkStore, nnf NewNetFetcherFunc) (*NetStore, error) { 55 fetchers, err := lru.New(defaultChunkRequestsCacheCapacity) 56 if err != nil { 57 return nil, err 58 } 59 return &NetStore{ 60 store: store, 61 fetchers: fetchers, 62 NewNetFetcherFunc: nnf, 63 closeC: make(chan struct{}), 64 }, nil 65 } 66 67 //将块存储在localstore中,并使用存储在 68 //取数器缓存 69 func (n *NetStore) Put(ctx context.Context, ch Chunk) error { 70 n.mu.Lock() 71 defer n.mu.Unlock() 72 73 //放到存储区的块中,应该没有错误 74 err := n.store.Put(ctx, ch) 75 if err != nil { 76 return err 77 } 78 79 //如果块现在放在存储区中,请检查是否有活动的获取程序并调用传递。 80 //(这将通过获取器将块传递给请求者) 81 if f := n.getFetcher(ch.Address()); f != nil { 82 f.deliver(ctx, ch) 83 } 84 return nil 85 } 86 87 //get同步从netstore dpa中检索区块。 88 //它调用netstore.get,如果块不在本地存储中 89 //它调用带有请求的fetch,该请求将一直阻塞到块 90 //到达或上下文完成 91 func (n *NetStore) Get(rctx context.Context, ref Address) (Chunk, error) { 92 chunk, fetch, err := n.get(rctx, ref) 93 if err != nil { 94 return nil, err 95 } 96 if chunk != nil { 97 return chunk, nil 98 } 99 return fetch(rctx) 100 } 101 102 func (n *NetStore) BinIndex(po uint8) uint64 { 103 return n.store.BinIndex(po) 104 } 105 106 func (n *NetStore) Iterator(from uint64, to uint64, po uint8, f func(Address, uint64) bool) error { 107 return n.store.Iterator(from, to, po, f) 108 } 109 110 //如果存储包含给定地址,则fetchfunc返回nil。否则返回一个等待函数, 111 //在块可用或上下文完成后返回 112 func (n *NetStore) FetchFunc(ctx context.Context, ref Address) func(context.Context) error { 113 chunk, fetch, _ := n.get(ctx, ref) 114 if chunk != nil { 115 return nil 116 } 117 return func(ctx context.Context) error { 118 _, err := fetch(ctx) 119 return err 120 } 121 } 122 123 //关闭区块存储 124 func (n *NetStore) Close() { 125 close(n.closeC) 126 n.store.Close() 127 //TODO:循环访问获取器以取消它们 128 } 129 130 //获取从localstore检索区块的尝试 131 //如果未找到,则使用getorcreatefetcher: 132 //1。或者已经有一个获取器来检索它 133 //2。将创建一个新的回迁器并将其保存在回迁器缓存中。 134 //从这里开始,所有GET都将命中这个获取器,直到块被传递为止。 135 //或者所有获取器上下文都已完成。 136 //它返回一个块、一个获取函数和一个错误 137 //如果chunk为nil,则需要使用上下文调用返回的fetch函数来返回chunk。 138 func (n *NetStore) get(ctx context.Context, ref Address) (Chunk, func(context.Context) (Chunk, error), error) { 139 n.mu.Lock() 140 defer n.mu.Unlock() 141 142 chunk, err := n.store.Get(ctx, ref) 143 if err != nil { 144 if err != ErrChunkNotFound { 145 log.Debug("Received error from LocalStore other than ErrNotFound", "err", err) 146 } 147 //块在localstore中不可用,让我们为它获取取数器,或者创建一个新的取数器。 148 //如果它还不存在 149 f := n.getOrCreateFetcher(ref) 150 //如果调用者需要块,它必须使用返回的fetch函数来获取块。 151 return nil, f.Fetch, nil 152 } 153 154 return chunk, nil, nil 155 } 156 157 //GetOrCreateFetcher尝试检索现有的获取程序 158 //如果不存在,则创建一个并将其保存在提取缓存中。 159 //呼叫方必须持有锁 160 func (n *NetStore) getOrCreateFetcher(ref Address) *fetcher { 161 if f := n.getFetcher(ref); f != nil { 162 return f 163 } 164 165 //没有给定地址的回信器,我们必须创建一个新地址 166 key := hex.EncodeToString(ref) 167 //创建保持提取活动的上下文 168 ctx, cancel := context.WithTimeout(context.Background(), fetcherTimeout) 169 //当所有请求完成时调用destroy 170 destroy := func() { 171 //从回卷器中移除回卷器 172 n.fetchers.Remove(key) 173 //通过取消在以下情况下调用的上下文来停止提取程序 174 //所有请求已取消/超时或块已传递 175 cancel() 176 } 177 //对等方总是存储对块有活动请求的所有对等方。它是共享的 178 //在fetchfunc函数和fetchfunc函数之间。它是NewFetchFunc所需要的,因为 179 //不应请求请求块的对等方来传递它。 180 peers := &sync.Map{} 181 182 fetcher := newFetcher(ref, n.NewNetFetcherFunc(ctx, ref, peers), destroy, peers, n.closeC) 183 n.fetchers.Add(key, fetcher) 184 185 return fetcher 186 } 187 188 //getfetcher从fetchers缓存中检索给定地址的fetcher(如果存在), 189 //否则返回零 190 func (n *NetStore) getFetcher(ref Address) *fetcher { 191 key := hex.EncodeToString(ref) 192 f, ok := n.fetchers.Get(key) 193 if ok { 194 return f.(*fetcher) 195 } 196 return nil 197 } 198 199 //requestscachelen返回当前存储在缓存中的传出请求数 200 func (n *NetStore) RequestsCacheLen() int { 201 return n.fetchers.Len() 202 } 203 204 //一个获取器对象负责为一个地址获取一个块,并跟踪所有 205 //已请求但尚未收到的同龄人。 206 type fetcher struct { 207 addr Address //区块地址 208 chunk Chunk //获取器可以在获取器上设置块 209 deliveredC chan struct{} //chan向请求发送块传递信号 210 cancelledC chan struct{} //通知回迁器已取消的chan(从netstore的回迁器中删除) 211 netFetcher NetFetcher //使用从上下文获取的请求源调用的远程提取函数 212 cancel func() //当调用所有上游上下文时,远程获取程序调用的清除函数 213 peers *sync.Map //要求分块的同龄人 214 requestCnt int32 //此区块上的请求数。如果所有请求都已完成(已传递或上下文已完成),则调用cancel函数 215 deliverOnce *sync.Once //保证我们只关闭一次交货 216 } 217 218 //new fetcher为fiven addr创建一个新的fetcher对象。fetch是一个函数,实际上 219 //是否进行检索(在非测试情况下,这是来自网络包)。取消功能是 220 //要么调用 221 //1。当提取到块时,所有对等方都已收到通知或其上下文已完成。 222 //2。尚未提取块,但已完成所有请求中的所有上下文 223 //对等映射存储已请求块的所有对等。 224 func newFetcher(addr Address, nf NetFetcher, cancel func(), peers *sync.Map, closeC chan struct{}) *fetcher { 225 cancelOnce := &sync.Once{} //只应调用一次Cancel 226 return &fetcher{ 227 addr: addr, 228 deliveredC: make(chan struct{}), 229 deliverOnce: &sync.Once{}, 230 cancelledC: closeC, 231 netFetcher: nf, 232 cancel: func() { 233 cancelOnce.Do(func() { 234 cancel() 235 }) 236 }, 237 peers: peers, 238 } 239 } 240 241 //fetch同步获取块,由netstore调用。get是块不可用 242 //局部地。 243 func (f *fetcher) Fetch(rctx context.Context) (Chunk, error) { 244 atomic.AddInt32(&f.requestCnt, 1) 245 defer func() { 246 //如果所有请求都完成了,则可以取消提取程序。 247 if atomic.AddInt32(&f.requestCnt, -1) == 0 { 248 f.cancel() 249 } 250 }() 251 252 //请求块的对等机。存储在共享对等映射中,但在请求后删除 253 //已交付 254 peer := rctx.Value("peer") 255 if peer != nil { 256 f.peers.Store(peer, time.Now()) 257 defer f.peers.Delete(peer) 258 } 259 260 //如果上下文中有一个源,那么它是一个提供,否则是一个请求 261 sourceIF := rctx.Value("source") 262 263 hopCount, _ := rctx.Value("hopcount").(uint8) 264 265 if sourceIF != nil { 266 var source enode.ID 267 if err := source.UnmarshalText([]byte(sourceIF.(string))); err != nil { 268 return nil, err 269 } 270 f.netFetcher.Offer(rctx, &source) 271 } else { 272 f.netFetcher.Request(rctx, hopCount) 273 } 274 275 //等待块被传递或上下文完成 276 select { 277 case <-rctx.Done(): 278 return nil, rctx.Err() 279 case <-f.deliveredC: 280 return f.chunk, nil 281 case <-f.cancelledC: 282 return nil, fmt.Errorf("fetcher cancelled") 283 } 284 } 285 286 //传递由NetStore调用。Put通知所有挂起的请求 287 func (f *fetcher) deliver(ctx context.Context, ch Chunk) { 288 f.deliverOnce.Do(func() { 289 f.chunk = ch 290 //关闭deliveredc通道将终止正在进行的请求 291 close(f.deliveredC) 292 }) 293 } 294