@@ -208,7 +208,7 @@ type (
208208 pending sync.Map // [wid => *basewi]
209209 abortedWIDs sync.Map // wid => error from DT
210210 xact.DemandBase
211- activeWG sync.WaitGroup // when pending
211+ activeWG sync.WaitGroup // active asm()
212212 lastLog atomic.Int64 // last log timestamp (sparse)
213213 advNextCheck atomic.Int64
214214 pendingCnt atomic.Int64
@@ -350,12 +350,12 @@ func (r *XactMoss) housekeep(now int64) time.Duration {
350350
351351func (* XactMoss ) Run (* sync.WaitGroup ) { debug .Assert (false ) }
352352
353- func (r * XactMoss ) IncPending () {
353+ func (r * XactMoss ) incPending () {
354354 r .DemandBase .IncPending ()
355355 r .activeWG .Add (1 )
356356}
357357
358- func (r * XactMoss ) DecPending () {
358+ func (r * XactMoss ) decPending () {
359359 r .DemandBase .DecPending ()
360360 r .activeWG .Done ()
361361}
@@ -371,23 +371,8 @@ func (r *XactMoss) Abort(err error) bool {
371371
372372 nlog .Infoln (r .Name (), "aborting:" , err )
373373
374- // best-effort wait for pending WIs to drain; never block indefinitely
375- const (
376- pollIval = 100 * time .Millisecond
377- )
378- {
379- var (
380- total time.Duration
381- maxWait = max (cmn .Rom .MaxKeepalive (), 8 * time .Second )
382- )
383- for r .pendingCnt .Load () > 0 && total < maxWait {
384- time .Sleep (pollIval )
385- total += pollIval
386- }
387- if r .pendingCnt .Load () > 0 {
388- nlog .Warningln (r .Name (), "abort: still" , r .pendingCnt .Load (), "pending after" , maxWait , "- proceeding anyway" )
389- }
390- }
374+ r .activeWG .Wait ()
375+ r ._abortQuiesce ()
391376
392377 r .pending .Range (r .cleanup )
393378 r .pending .Clear ()
@@ -401,6 +386,22 @@ func (r *XactMoss) Abort(err error) bool {
401386 return true
402387}
403388
389+ // best-effort (and extremely unlikely): quiesce prior to cleanups
390+ func (r * XactMoss ) _abortQuiesce () {
391+ const pollIval = cos .PollSleepShort // 100ms
392+ var (
393+ total time.Duration
394+ maxWait = max (cmn .Rom .MaxKeepalive (), 8 * time .Second )
395+ )
396+ for r .Pending () > 0 && total < maxWait {
397+ time .Sleep (pollIval )
398+ total += pollIval
399+ }
400+ if p := r .Pending (); p > 0 {
401+ nlog .Warningln (r .Name (), "abort: still" , p , "demand-pending after" , maxWait , "- proceeding anyway" )
402+ }
403+ }
404+
404405// (Abort, fini) => pending (sync.Map's) callback to cleanup all pending work items
405406func (* XactMoss ) cleanup (_ , value any ) bool {
406407 wi := value .(* basewi )
@@ -674,11 +675,20 @@ func (r *XactMoss) Assemble(req *apc.MossReq, w http.ResponseWriter, wid string)
674675 return err
675676 }
676677
678+ if r .IsAborted () || r .IsDone () {
679+ wi .owned .CAS (wiownASM , wiownNone ) // Abort/fini owns final cleanup
680+ return nil
681+ }
682+
677683 // asm() path owns wi; DecPending below
678- debug .Assert (wid == wi .wid )
679- r .IncPending ()
680- defer r .DecPending ()
684+ r .incPending ()
685+ defer r .decPending ()
686+ if r .IsAborted () || r .IsDone () {
687+ wi .owned .CAS (wiownASM , wiownNone ) // ditto
688+ return nil
689+ }
681690
691+ debug .Assert (wid == wi .wid )
682692 err := r .asm (req , w , wi )
683693 if err != nil {
684694 if r .shouldAbortWI (wi ) {
0 commit comments