code: func (db *DB) collectGarbage() (collectedCount uint64, done bool, err error) {
  	batch := new(leveldb.Batch)
  	target := db.gcTarget()
  
  	// protect database from changing idexes and gcSize
  	db.batchMu.Lock()
  	defer db.batchMu.Unlock()
  
  	gcSize, err := db.gcSize.Get()
  	if err != nil {
  		return 0, true, err
  	}
  
  	done = true
  	err = db.gcIndex.Iterate(func(item shed.Item) (stop bool, err error) {
  		if gcSize-collectedCount <= target {
  			return true, nil
  		}
  		// delete from retrieve, pull, gc
  		db.retrievalDataIndex.DeleteInBatch(batch, item)
  		db.retrievalAccessIndex.DeleteInBatch(batch, item)
  		db.pullIndex.DeleteInBatch(batch, item)
  		db.gcIndex.DeleteInBatch(batch, item)
  		collectedCount++
  		if collectedCount >= gcBatchSize {
  			// bach size limit reached,
  			// another gc run is needed
  			done = false
  			return true, nil
  		}
  		return false, nil
  	}, nil)
  	if err != nil {
  		return 0, false, err
  	}
  
  	db.gcSize.PutInBatch(batch, gcSize-collectedCount)
  
  	err = db.shed.WriteBatch(batch)
  	if err != nil {
  		return 0, false, err
  	}
  	return collectedCount, done, nil
  }
docs: // collectGarbage removes chunks from retrieval and other
  // indexes if maximal number of chunks in database is reached.
  // This function returns the number of removed chunks. If done
  // is false, another call to this function is needed to collect
  // the rest of the garbage as the batch size limit is reached.
  // This function is called in collectGarbageWorker.