// BatchOrLegacy calls the Batch API and falls back on the Legacy API // This is for simplicity, legacy route is not most optimal (serial) // TODO LEGACY API: remove when legacy API removed func BatchOrLegacy(objects []*ObjectResource, operation string, transferAdapters []string) (objs []*ObjectResource, transferAdapter string, e error) { if !config.Config.BatchTransfer() { objs, err := Legacy(objects, operation) return objs, "", err } objs, adapterName, err := Batch(objects, operation, transferAdapters) if err != nil { if errutil.IsNotImplementedError(err) { git.Config.SetLocal("", "lfs.batch", "false") objs, err := Legacy(objects, operation) return objs, "", err } return nil, "", err } return objs, adapterName, nil }
// batchApiRoutine processes the queue of transfers using the batch endpoint, // making only one POST call for all objects. The results are then handed // off to the transfer workers. func (q *TransferQueue) batchApiRoutine() { var startProgress sync.Once transferAdapterNames := transfer.GetAdapterNames(q.direction) for { batch := q.batcher.Next() if batch == nil { break } tracerx.Printf("tq: sending batch of size %d", len(batch)) transfers := make([]*api.ObjectResource, 0, len(batch)) for _, i := range batch { t := i.(Transferable) transfers = append(transfers, &api.ObjectResource{Oid: t.Oid(), Size: t.Size()}) } if len(transfers) == 0 { continue } objs, adapterName, err := api.Batch(transfers, q.transferKind(), transferAdapterNames) if err != nil { if errutil.IsNotImplementedError(err) { git.Config.SetLocal("", "lfs.batch", "false") go q.legacyFallback(batch) return } if q.canRetry(err) { for _, t := range batch { q.retry(t.(Transferable)) } } else { q.errorc <- err } q.wait.Add(-len(transfers)) continue } q.useAdapter(adapterName) startProgress.Do(q.meter.Start) for _, o := range objs { if o.Error != nil { q.errorc <- errutil.Errorf(o.Error, "[%v] %v", o.Oid, o.Error.Message) q.Skip(o.Size) q.wait.Done() continue } if _, ok := o.Rel(q.transferKind()); ok { // This object needs to be transferred q.trMutex.Lock() transfer, ok := q.transferables[o.Oid] q.trMutex.Unlock() if ok { transfer.SetObject(o) q.meter.Add(transfer.Name()) q.addToAdapter(transfer) } else { q.Skip(transfer.Size()) q.wait.Done() } } else { q.Skip(o.Size) q.wait.Done() } } } }