github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/xact/demand.go (about) 1 // Package xact provides core functionality for the AIStore eXtended Actions (xactions). 2 /* 3 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package xact 6 7 import ( 8 "time" 9 10 "github.com/NVIDIA/aistore/cmn" 11 "github.com/NVIDIA/aistore/cmn/atomic" 12 "github.com/NVIDIA/aistore/cmn/cos" 13 "github.com/NVIDIA/aistore/cmn/debug" 14 "github.com/NVIDIA/aistore/cmn/mono" 15 "github.com/NVIDIA/aistore/core" 16 "github.com/NVIDIA/aistore/core/meta" 17 "github.com/NVIDIA/aistore/hk" 18 ) 19 20 const ( 21 IdleDefault = time.Minute // hk -> idle tick 22 ) 23 24 type ( 25 // xaction that self-terminates after staying idle for a while 26 // with an added capability to renew itself and ref-count its pending work 27 Demand interface { 28 core.Xact 29 IdleTimer() <-chan struct{} 30 IncPending() 31 DecPending() 32 SubPending(n int) 33 } 34 DemandBase struct { 35 hkName string 36 idle struct { 37 ticks cos.StopCh 38 d time.Duration // hk idle 39 last atomic.Int64 // mono.NanoTime 40 } 41 42 Base 43 44 pending atomic.Int64 45 hkReg atomic.Bool // mono.NanoTime 46 } 47 ) 48 49 //////////////// 50 // DemandBase // 51 //////////////// 52 53 // NOTE: override `Base.IsIdle` 54 func (r *DemandBase) IsIdle() bool { 55 last := r.idle.last.Load() 56 return last != 0 && mono.Since(last) >= max(cmn.Rom.MaxKeepalive(), 2*time.Second) 57 } 58 59 func (r *DemandBase) Init(uuid, kind string, bck *meta.Bck, idleDur time.Duration) { 60 r.hkName = kind + "/" + uuid 61 r.idle.d = IdleDefault 62 if idleDur > 0 { 63 r.idle.d = idleDur 64 } 65 r.idle.ticks.Init() 66 r.InitBase(uuid, kind, bck) 67 68 r.idle.last.Store(mono.NanoTime()) 69 r.hkReg.Store(true) 70 hk.Reg(r.hkName+hk.NameSuffix, r.hkcb, 0 /*time.Duration*/) 71 } 72 73 // (e.g. usage: listed last page) 74 func (r *DemandBase) Reset(idleTime time.Duration) { r.idle.d = idleTime } 75 76 func (r *DemandBase) hkcb() time.Duration { 77 last := r.idle.last.Load() 78 if last != 0 && mono.Since(last) >= r.idle.d { 79 // signal parent xaction to finish and exit (via `IdleTimer` chan) 80 r.idle.ticks.Close() 81 } 82 return r.idle.d 83 } 84 85 func (r *DemandBase) IdleTimer() <-chan struct{} { return r.idle.ticks.Listen() } 86 func (r *DemandBase) Pending() (cnt int64) { return r.pending.Load() } 87 func (r *DemandBase) DecPending() { r.SubPending(1) } 88 89 func (r *DemandBase) IncPending() { 90 debug.Assert(r.hkReg.Load()) 91 r.pending.Inc() 92 r.idle.last.Store(0) 93 } 94 95 func (r *DemandBase) SubPending(n int) { 96 if n == 0 { 97 return 98 } 99 pending := r.pending.Sub(int64(n)) 100 debug.Assert(pending >= 0) 101 if pending == 0 { 102 r.idle.last.Store(mono.NanoTime()) 103 } 104 } 105 106 func (r *DemandBase) Stop() { 107 hk.Unreg(r.hkName + hk.NameSuffix) 108 r.idle.ticks.Close() 109 } 110 111 func (r *DemandBase) Abort(err error) (ok bool) { 112 if err == nil && !r.IsIdle() { 113 err = cmn.NewErrAborted(r.Name(), "aborting non-idle", nil) 114 } 115 if ok = r.Base.Abort(err); ok { 116 r.Finish() 117 } 118 return 119 }