code: func (a *Archiver) doContains(out chan<- *PendingItem, items []*PendingItem) {
  	tmp := make([]*isolateservice.HandlersEndpointsV1Digest, len(items))
  	// No need to lock each item at that point, no mutation occurs on
  	// PendingItem.digestItem after stage 2.
  	for i, item := range items {
  		tmp[i] = &item.digestItem
  	}
  	states, err := a.c.Contains(a.ctx, tmp)
  	if err != nil {
  		err = fmt.Errorf("contains(%d) failed: %s", len(items), err)
  		// When an error occurs, early exit the process.
  		a.cancel()
  		for _, item := range items {
  			item.SetErr(err)
  			item.done()
  		}
  		return
  	}
  	a.progress.Update(groupLookup, groupLookupDone, int64(len(items)))
  	for index, state := range states {
  		size := items[index].digestItem.Size
  		if state == nil {
  			a.statsLock.Lock()
  			a.stats.Hits = append(a.stats.Hits, units.Size(size))
  			a.statsLock.Unlock()
  			items[index].done()
  		} else {
  			items[index].state = state
  			a.progress.Update(groupUpload, groupUploadTodo, 1)
  			a.progress.Update(groupUpload, groupUploadTodoSize, items[index].digestItem.Size)
  			out <- items[index]
  		}
  	}
  	logging.Infof(a.ctx, "Looked up %d items", len(items))
  }
docs: // doContains is called by stage 3.