@@ -175,9 +175,9 @@ func apiMirrorsDrop(c *gin.Context) {
175175 name := c .Params .ByName ("name" )
176176 force := c .Request .URL .Query ().Get ("force" ) == "1"
177177
178+ // Phase 1: Pre-task validation (shallow load for 404 check only)
178179 collectionFactory := context .NewCollectionFactory ()
179180 mirrorCollection := collectionFactory .RemoteRepoCollection ()
180- snapshotCollection := collectionFactory .SnapshotCollection ()
181181
182182 repo , err := mirrorCollection .ByName (name )
183183 if err != nil {
@@ -187,21 +187,34 @@ func apiMirrorsDrop(c *gin.Context) {
187187
188188 resources := []string {string (repo .Key ())}
189189 taskName := fmt .Sprintf ("Delete mirror %s" , name )
190+
190191 maybeRunTaskInBackground (c , taskName , resources , func (_ aptly.Progress , _ * task.Detail ) (* task.ProcessReturnValue , error ) {
191- err := repo .CheckLock ()
192+ // Phase 2: Inside task lock - create fresh collections
193+ taskCollectionFactory := context .NewCollectionFactory ()
194+ taskMirrorCollection := taskCollectionFactory .RemoteRepoCollection ()
195+ taskSnapshotCollection := taskCollectionFactory .SnapshotCollection ()
196+
197+ // Fresh load after lock acquired
198+ repo , err := taskMirrorCollection .ByName (name )
199+ if err != nil {
200+ return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to drop: %v" , err )
201+ }
202+
203+ err = repo .CheckLock ()
192204 if err != nil {
193205 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to drop: %v" , err )
194206 }
195207
196208 if ! force {
197- snapshots := snapshotCollection .ByRemoteRepoSource (repo )
209+ // Fresh checks with current collections
210+ snapshots := taskSnapshotCollection .ByRemoteRepoSource (repo )
198211
199212 if len (snapshots ) > 0 {
200213 return & task.ProcessReturnValue {Code : http .StatusForbidden , Value : nil }, fmt .Errorf ("won't delete mirror with snapshots, use 'force=1' to override" )
201214 }
202215 }
203216
204- err = mirrorCollection .Drop (repo )
217+ err = taskMirrorCollection .Drop (repo )
205218 if err != nil {
206219 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to drop: %v" , err )
207220 }
@@ -232,6 +245,7 @@ func apiMirrorsShow(c *gin.Context) {
232245 err = collection .LoadComplete (repo )
233246 if err != nil {
234247 AbortWithJSONError (c , 500 , fmt .Errorf ("unable to show: %s" , err ))
248+ return
235249 }
236250
237251 c .JSON (200 , repo )
@@ -369,7 +383,8 @@ func apiMirrorsUpdate(c *gin.Context) {
369383 collectionFactory := context .NewCollectionFactory ()
370384 collection := collectionFactory .RemoteRepoCollection ()
371385
372- remote , err = collection .ByName (c .Params .ByName ("name" ))
386+ name := c .Params .ByName ("name" )
387+ remote , err = collection .ByName (name )
373388 if err != nil {
374389 AbortWithJSONError (c , 404 , err )
375390 return
@@ -384,6 +399,7 @@ func apiMirrorsUpdate(c *gin.Context) {
384399 return
385400 }
386401
402+ // Pre-task validation of new name if provided
387403 if b .Name != remote .Name {
388404 _ , err = collection .ByName (b .Name )
389405 if err == nil {
@@ -400,9 +416,26 @@ func apiMirrorsUpdate(c *gin.Context) {
400416
401417 resources := []string {string (remote .Key ())}
402418 maybeRunTaskInBackground (c , "Update mirror " + b .Name , resources , func (out aptly.Progress , detail * task.Detail ) (* task.ProcessReturnValue , error ) {
419+ // Phase 2: Inside task lock - create fresh factory
420+ taskCollectionFactory := context .NewCollectionFactory ()
421+ taskCollection := taskCollectionFactory .RemoteRepoCollection ()
422+
423+ // Fresh load after lock acquired (use captured `name` variable, not gin context)
424+ remote , err := taskCollection .ByName (name )
425+ if err != nil {
426+ return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to update: %s" , err )
427+ }
428+
429+ // Fresh rename check inside lock (if renaming)
430+ if b .Name != remote .Name {
431+ _ , err := taskCollection .ByName (b .Name )
432+ if err == nil {
433+ return & task.ProcessReturnValue {Code : http .StatusConflict , Value : nil }, fmt .Errorf ("unable to rename: mirror %s already exists" , b .Name )
434+ }
435+ }
403436
404437 downloader := context .NewDownloader (out )
405- err : = remote .Fetch (downloader , verifier , b .IgnoreSignatures )
438+ err = remote .Fetch (downloader , verifier , b .IgnoreSignatures )
406439 if err != nil {
407440 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to update: %s" , err )
408441 }
@@ -414,7 +447,7 @@ func apiMirrorsUpdate(c *gin.Context) {
414447 }
415448 }
416449
417- err = remote .DownloadPackageIndexes (out , downloader , verifier , collectionFactory , b .IgnoreSignatures , remote .SkipComponentCheck )
450+ err = remote .DownloadPackageIndexes (out , downloader , verifier , taskCollectionFactory , b .IgnoreSignatures , remote .SkipComponentCheck )
418451 if err != nil {
419452 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to update: %s" , err )
420453 }
@@ -433,8 +466,8 @@ func apiMirrorsUpdate(c *gin.Context) {
433466 }
434467 }
435468
436- queue , downloadSize , err := remote .BuildDownloadQueue (context .PackagePool (), collectionFactory .PackageCollection (),
437- collectionFactory .ChecksumCollection (nil ), b .SkipExistingPackages )
469+ queue , downloadSize , err := remote .BuildDownloadQueue (context .PackagePool (), taskCollectionFactory .PackageCollection (),
470+ taskCollectionFactory .ChecksumCollection (nil ), b .SkipExistingPackages )
438471 if err != nil {
439472 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to update: %s" , err )
440473 }
@@ -444,12 +477,12 @@ func apiMirrorsUpdate(c *gin.Context) {
444477 e := context .ReOpenDatabase ()
445478 if e == nil {
446479 remote .MarkAsIdle ()
447- _ = collection .Update (remote )
480+ _ = taskCollection .Update (remote )
448481 }
449482 }()
450483
451484 remote .MarkAsUpdating ()
452- err = collection .Update (remote )
485+ err = taskCollection .Update (remote )
453486 if err != nil {
454487 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to update: %s" , err )
455488 }
@@ -553,7 +586,7 @@ func apiMirrorsUpdate(c *gin.Context) {
553586 }
554587
555588 // and import it back to the pool
556- task .File .PoolPath , err = context .PackagePool ().Import (task .TempDownPath , task .File .Filename , & task .File .Checksums , true , collectionFactory .ChecksumCollection (nil ))
589+ task .File .PoolPath , err = context .PackagePool ().Import (task .TempDownPath , task .File .Filename , & task .File .Checksums , true , taskCollectionFactory .ChecksumCollection (nil ))
557590 if err != nil {
558591 //return &task.ProcessReturnValue{Code: http.StatusInternalServerError, Value: nil}, fmt.Errorf("unable to import file: %s", err)
559592 pushError (err )
@@ -606,8 +639,8 @@ func apiMirrorsUpdate(c *gin.Context) {
606639 }
607640
608641 log .Info ().Msgf ("%s: Finalizing download..." , b .Name )
609- _ = remote .FinalizeDownload (collectionFactory , out )
610- err = collectionFactory . RemoteRepoCollection () .Update (remote )
642+ _ = remote .FinalizeDownload (taskCollectionFactory , out )
643+ err = taskCollection .Update (remote )
611644 if err != nil {
612645 return & task.ProcessReturnValue {Code : http .StatusInternalServerError , Value : nil }, fmt .Errorf ("unable to update: %s" , err )
613646 }
0 commit comments