github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/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 12:09:50</date>
    10  //</624342684219215872>
    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  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum/swarm/log"
    35  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    36  	opentracing "github.com/opentracing/opentracing-go"
    37  )
    38  
    39  var (
    40  //
    41  //
    42  //
    43  	netStoreRetryTimeout = 30 * time.Second
    44  //
    45  //
    46  //
    47  	netStoreMinRetryDelay = 3 * time.Second
    48  //
    49  //
    50  //
    51  	searchTimeout = 10 * time.Second
    52  )
    53  
    54  //
    55  //
    56  //
    57  //
    58  type NetStore struct {
    59  	localStore *LocalStore
    60  	retrieve   func(ctx context.Context, chunk *Chunk) error
    61  }
    62  
    63  func NewNetStore(localStore *LocalStore, retrieve func(ctx context.Context, chunk *Chunk) error) *NetStore {
    64  	return &NetStore{localStore, retrieve}
    65  }
    66  
    67  //
    68  //
    69  //
    70  //
    71  //
    72  //
    73  func (ns *NetStore) Get(ctx context.Context, addr Address) (chunk *Chunk, err error) {
    74  
    75  	var sp opentracing.Span
    76  	ctx, sp = spancontext.StartSpan(
    77  		ctx,
    78  		"netstore.get.global")
    79  	defer sp.Finish()
    80  
    81  	timer := time.NewTimer(netStoreRetryTimeout)
    82  	defer timer.Stop()
    83  
    84  //
    85  //
    86  	type result struct {
    87  		chunk *Chunk
    88  		err   error
    89  	}
    90  	resultC := make(chan result)
    91  
    92  //
    93  //
    94  	quitC := make(chan struct{})
    95  	defer close(quitC)
    96  
    97  //
    98  //
    99  	go func() {
   100  //
   101  //
   102  //
   103  //
   104  		limiter := time.NewTimer(netStoreMinRetryDelay)
   105  		defer limiter.Stop()
   106  
   107  		for {
   108  			chunk, err := ns.get(ctx, addr, 0)
   109  			if err != ErrChunkNotFound {
   110  //
   111  //
   112  				select {
   113  				case <-quitC:
   114  //
   115  //
   116  //
   117  				case resultC <- result{chunk: chunk, err: err}:
   118  //
   119  				}
   120  				return
   121  
   122  			}
   123  			select {
   124  			case <-quitC:
   125  //
   126  //
   127  //
   128  				return
   129  			case <-limiter.C:
   130  			}
   131  //
   132  			limiter.Reset(netStoreMinRetryDelay)
   133  			log.Debug("NetStore.Get retry chunk", "key", addr)
   134  		}
   135  	}()
   136  
   137  	select {
   138  	case r := <-resultC:
   139  		return r.chunk, r.err
   140  	case <-timer.C:
   141  		return nil, ErrChunkNotFound
   142  	}
   143  }
   144  
   145  //
   146  func (ns *NetStore) GetWithTimeout(ctx context.Context, addr Address, timeout time.Duration) (chunk *Chunk, err error) {
   147  	return ns.get(ctx, addr, timeout)
   148  }
   149  
   150  func (ns *NetStore) get(ctx context.Context, addr Address, timeout time.Duration) (chunk *Chunk, err error) {
   151  	if timeout == 0 {
   152  		timeout = searchTimeout
   153  	}
   154  
   155  	var sp opentracing.Span
   156  	ctx, sp = spancontext.StartSpan(
   157  		ctx,
   158  		"netstore.get")
   159  	defer sp.Finish()
   160  
   161  	if ns.retrieve == nil {
   162  		chunk, err = ns.localStore.Get(ctx, addr)
   163  		if err == nil {
   164  			return chunk, nil
   165  		}
   166  		if err != ErrFetching {
   167  			return nil, err
   168  		}
   169  	} else {
   170  		var created bool
   171  		chunk, created = ns.localStore.GetOrCreateRequest(ctx, addr)
   172  
   173  		if chunk.ReqC == nil {
   174  			return chunk, nil
   175  		}
   176  
   177  		if created {
   178  			err := ns.retrieve(ctx, chunk)
   179  			if err != nil {
   180  //
   181  				chunk.SetErrored(ErrChunkUnavailable)
   182  				return nil, err
   183  			}
   184  		}
   185  	}
   186  
   187  	t := time.NewTicker(timeout)
   188  	defer t.Stop()
   189  
   190  	select {
   191  	case <-t.C:
   192  //
   193  		chunk.SetErrored(ErrChunkNotFound)
   194  		return nil, ErrChunkNotFound
   195  	case <-chunk.ReqC:
   196  	}
   197  	chunk.SetErrored(nil)
   198  	return chunk, nil
   199  }
   200  
   201  //
   202  func (ns *NetStore) Put(ctx context.Context, chunk *Chunk) {
   203  	ns.localStore.Put(ctx, chunk)
   204  }
   205  
   206  //
   207  func (ns *NetStore) Close() {
   208  	ns.localStore.Close()
   209  }
   210