@@ -534,10 +534,19 @@ func (u *Uploader) processDurableUploadTask(
534534 u .ensureUploadDataSet (ctx , task , version , bucket , uploadID , copyIndex , logger )
535535 return
536536 }
537- if err := u .ensureReplicaRepairTask (ctx , binding , task .MaxRetries ); err != nil {
537+ if binding .Status == model .StorageDataSetStatusReady {
538+ u .processStagedTask (ctx , task , version , bucket , stage , logger )
539+ return
540+ }
541+ queued , err := ensureReplicaRepairTask (ctx , u .repos , binding , task .MaxRetries )
542+ if err != nil {
538543 u .handleTaskFailure (ctx , task , logger , "handoff durable upload repair" , err )
539544 return
540545 }
546+ if ! queued {
547+ u .waitForStorageDependency (ctx , task , logger , "Waiting for in-place replica recovery" )
548+ return
549+ }
541550 completeWorkerTask (ctx , u .repos , task , "uploader" , logger )
542551}
543552
@@ -989,23 +998,40 @@ func (u *Uploader) ensureBucketProviderBindings(ctx context.Context, bucket *mod
989998 targetCopies = boundedTargetCopies (targetCopies )
990999 selected := make ([]model.StorageDataSet , 0 , targetCopies )
9911000 excluded := make ([]sdktypes.BigInt , 0 , len (bindings ))
992- for _ , binding := range bindings {
1001+ inFlight := 0
1002+ for i := range bindings {
1003+ binding := bindings [i ]
9931004 existing [binding .CopyIndex ] = binding
9941005 excluded = append (excluded , binding .ProviderID .SDK ())
995- }
996- missingIndexes := make ([]int , 0 , targetCopies )
997- for copyIndex := range targetCopies {
998- if binding , ok := existing [copyIndex ]; ok {
999- selected = append (selected , binding )
1000- } else {
1001- missingIndexes = append (missingIndexes , copyIndex )
1006+ if dataSetBindingCanOccupyUploadSlot (uploadID , & binding ) {
1007+ if len (selected ) < targetCopies {
1008+ selected = append (selected , binding )
1009+ }
1010+ continue
1011+ }
1012+ if dataSetBindingInFlightForOtherUpload (uploadID , & binding ) {
1013+ inFlight ++
10021014 }
10031015 }
1004- if len (missingIndexes ) == 0 {
1016+ if len (selected ) >= targetCopies {
10051017 plan := newBucketBindingPlan (selected , uploadID )
10061018 plan .complete = true
10071019 return plan , nil
10081020 }
1021+ if inFlight > 0 {
1022+ return newBucketBindingPlan (selected , uploadID ), nil
1023+ }
1024+ need := targetCopies - len (selected )
1025+ missingIndexes := make ([]int , 0 , need )
1026+ for copyIndex := 0 ; len (missingIndexes ) < need && copyIndex < model .StorageCopiesMax ; copyIndex ++ {
1027+ if _ , occupied := existing [copyIndex ]; occupied {
1028+ continue
1029+ }
1030+ missingIndexes = append (missingIndexes , copyIndex )
1031+ }
1032+ if len (missingIndexes ) == 0 {
1033+ return newBucketBindingPlan (selected , uploadID ), nil
1034+ }
10091035 contexts , err := u .storage .CreateContexts (ctx , & storage.CreateContextsOptions {
10101036 Copies : len (missingIndexes ),
10111037 ExcludeProviderIDs : excluded ,
@@ -1313,23 +1339,6 @@ func (u *Uploader) ensureUploadDataSet(ctx context.Context, task *model.Task, ve
13131339 }
13141340 }
13151341 }
1316- if durableObjectState (version .State ) {
1317- bindingID := binding .ID
1318- binding , err = u .repos .Uploads .GetDataSetBindingByID (ctx , bindingID )
1319- if err != nil || binding == nil {
1320- if err == nil {
1321- err = fmt .Errorf ("dataset binding %d not found" , bindingID )
1322- }
1323- u .handleTaskFailure (ctx , task , logger , "reload durable upload data set" , err )
1324- return
1325- }
1326- if err := u .ensureReplicaRepairTask (ctx , binding , task .MaxRetries ); err != nil {
1327- u .handleTaskFailure (ctx , task , logger , "handoff durable upload repair" , err )
1328- return
1329- }
1330- completeWorkerTask (ctx , u .repos , task , "uploader" , logger )
1331- return
1332- }
13331342 nextStage := uploadStagePeerPull
13341343 if copyRow .TransferMethod == model .StorageCopyTransferMethodIngress {
13351344 nextStage = uploadStageIngressStore
@@ -2002,6 +2011,18 @@ func (u *Uploader) finishPeerCopy(ctx context.Context, task *model.Task, version
20022011 if ! u .repairReadableBinding (ctx , task , version , uploadID , logger , "repair readable binding" ) {
20032012 return
20042013 }
2014+ ref := repository.ObjectVersionRef {ObjectID : version .ObjectID , VersionID : version .VersionID }
2015+ _ , needsPreparation , err := u .scheduleRemainingPeerCopies (ctx , ref , version .BucketID , uploadID , task .MaxRetries )
2016+ if err != nil {
2017+ u .handleTaskFailure (ctx , task , logger , "schedule remaining upload copies" , err )
2018+ return
2019+ }
2020+ if needsPreparation {
2021+ if err := u .enqueueRepairUploadForVersion (ctx , ref , task .MaxRetries , uploadID ); err != nil {
2022+ u .handleTaskFailure (ctx , task , logger , "schedule upload preparation" , err )
2023+ return
2024+ }
2025+ }
20052026 if _ , _ , err := u .repos .Uploads .FinalizeUploadIfTargetCopiesMet (ctx , u .finalizeUploadInput (uploadID )); err != nil {
20062027 u .handleTaskFailure (ctx , task , logger , "finalize upload" , err )
20072028 return
@@ -2820,6 +2841,34 @@ func uploadCanUseDataSetBinding(uploadID int64, binding *model.StorageDataSet) b
28202841 dataSetBindingCanEnsureWrite (binding )
28212842}
28222843
2844+ func dataSetBindingCanOccupyUploadSlot (uploadID int64 , binding * model.StorageDataSet ) bool {
2845+ if binding == nil {
2846+ return false
2847+ }
2848+ switch binding .Status {
2849+ case model .StorageDataSetStatusReady :
2850+ return true
2851+ case model .StorageDataSetStatusUnavailable :
2852+ return dataSetBindingEstablished (binding )
2853+ case model .StorageDataSetStatusPending , model .StorageDataSetStatusCreating , model .StorageDataSetStatusFailed :
2854+ return uploadCanUseDataSetBinding (uploadID , binding )
2855+ default :
2856+ return false
2857+ }
2858+ }
2859+
2860+ func dataSetBindingInFlightForOtherUpload (uploadID int64 , binding * model.StorageDataSet ) bool {
2861+ if binding == nil || dataSetBindingCanOccupyUploadSlot (uploadID , binding ) {
2862+ return false
2863+ }
2864+ switch binding .Status {
2865+ case model .StorageDataSetStatusPending , model .StorageDataSetStatusCreating :
2866+ return true
2867+ default :
2868+ return false
2869+ }
2870+ }
2871+
28232872func uploadTracksDataSetBinding (uploadID int64 , binding * model.StorageDataSet ) bool {
28242873 if binding == nil {
28252874 return false
0 commit comments