code: func (n *NetStore) getOrCreateFetcher(ctx context.Context, ref Address) *fetcher {
  	if f := n.getFetcher(ref); f != nil {
  		return f
  	}
  
  	// no fetcher for the given address, we have to create a new one
  	key := hex.EncodeToString(ref)
  	// create the context during which fetching is kept alive
  	cctx, cancel := context.WithTimeout(ctx, fetcherTimeout)
  	// destroy is called when all requests finish
  	destroy := func() {
  		// remove fetcher from fetchers
  		n.fetchers.Remove(key)
  		// stop fetcher by cancelling context called when
  		// all requests cancelled/timedout or chunk is delivered
  		cancel()
  	}
  	// peers always stores all the peers which have an active request for the chunk. It is shared
  	// between fetcher and the NewFetchFunc function. It is needed by the NewFetchFunc because
  	// the peers which requested the chunk should not be requested to deliver it.
  	peers := &sync.Map{}
  
  	cctx, sp := spancontext.StartSpan(
  		cctx,
  		"netstore.fetcher",
  	)
  
  	sp.LogFields(olog.String("ref", ref.String()))
  	fetcher := newFetcher(sp, ref, n.NewNetFetcherFunc(cctx, ref, peers), destroy, peers, n.closeC)
  	n.fetchers.Add(key, fetcher)
  
  	return fetcher
  }
docs: // getOrCreateFetcher attempts at retrieving an existing fetchers
  // if none exists, creates one and saves it in the fetchers cache
  // caller must hold the lock