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