github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/sync/types.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package sync 22 23 import ( 24 gocontext "context" 25 "time" 26 27 "github.com/m3db/m3/src/x/context" 28 "github.com/m3db/m3/src/x/instrument" 29 ) 30 31 // Work is a unit of item to be worked on. 32 type Work func() 33 34 // PooledWorkerPool provides a pool for goroutines, but unlike WorkerPool, 35 // the actual goroutines themselves are re-used. This can be useful from a 36 // performance perspective in scenarios where the allocation and growth of 37 // the new goroutine and its stack is a bottleneck. Specifically, if the 38 // work function being performed has a very deep call-stack, calls to 39 // runtime.morestack can dominate the workload. Re-using existing goroutines 40 // allows the stack to be grown once, and then re-used for many invocations. 41 // 42 // In order to prevent abnormally large goroutine stacks from persisting over 43 // the life-cycle of an application, the PooledWorkerPool will randomly kill 44 // existing goroutines and spawn a new one. 45 // 46 // The PooledWorkerPool also implements sharding of its underlying worker channels 47 // to prevent excessive lock contention. 48 type PooledWorkerPool interface { 49 // Init initializes the pool. 50 Init() 51 52 // Go assign the Work to be executed by a Goroutine. Whether or not 53 // it waits for an existing Goroutine to become available or not 54 // is determined by the GrowOnDemand() option. If GrowOnDemand is not 55 // set then the call to Go() will block until a goroutine is available. 56 // If GrowOnDemand() is set then it will expand the pool of goroutines to 57 // accommodate the work. The newly allocated goroutine will temporarily 58 // participate in the pool in an effort to amortize its allocation cost, but 59 // will eventually be killed. This allows the pool to dynamically respond to 60 // workloads without causing excessive memory pressure. The pool will grow in 61 // size when the workload exceeds its capacity and shrink back down to its 62 // original size if/when the burst subsides. 63 Go(work Work) 64 65 // GoWithTimeout waits up to the given timeout for a worker to become 66 // available, returning true if a worker becomes available, or false 67 // otherwise. 68 GoWithTimeout(work Work, timeout time.Duration) bool 69 70 // GoWithContext waits until a worker is available or the provided ctx is 71 // canceled. 72 GoWithContext(ctx gocontext.Context, work Work) bool 73 74 // FastContextCheck returns a wrapper worker pool that only checks the context deadline every batchSize calls. 75 // This is useful for tight looping code that wants to amortize the cost of the ctx deadline check over batchSize 76 // iterations. 77 // This should only be used for code that can guarantee the wait time for a worker is low since if the ctx is not 78 // checked the calling goroutine blocks waiting for a worker. 79 FastContextCheck(batchSize int) PooledWorkerPool 80 } 81 82 // NewPooledWorkerOptions is a set of new instrument worker pool options. 83 type NewPooledWorkerOptions struct { 84 InstrumentOptions instrument.Options 85 } 86 87 // NewPooledWorkerFn returns a pooled worker pool that Init must be called on. 88 type NewPooledWorkerFn func(opts NewPooledWorkerOptions) (PooledWorkerPool, error) 89 90 // WorkerPool provides a pool for goroutines. 91 type WorkerPool interface { 92 // Init initializes the pool. 93 Init() 94 95 // Go waits until the next worker becomes available and executes it. 96 Go(work Work) 97 98 // GoInstrument instruments Go with timing information. 99 GoInstrument(work Work) ScheduleResult 100 101 // GoIfAvailable performs the work inside a worker if one is available and 102 // returns true, or false otherwise. 103 GoIfAvailable(work Work) bool 104 105 // GoWithTimeout waits up to the given timeout for a worker to become 106 // available, returning true if a worker becomes available, or false 107 // otherwise. 108 GoWithTimeout(work Work, timeout time.Duration) bool 109 110 // GoWithTimeoutInstrument instruments GoWithTimeout with timing information. 111 GoWithTimeoutInstrument(work Work, timeout time.Duration) ScheduleResult 112 113 // GoWithContext waits until a worker is available or the provided ctx is canceled. 114 GoWithContext(ctx context.Context, work Work) ScheduleResult 115 116 // FastContextCheck returns a wrapper worker pool that only checks the context deadline every batchSize calls. 117 // This is useful for tight looping code that wants to amortize the cost of the ctx deadline check over batchSize 118 // iterations. 119 // This should only be used for code that can guarantee the wait time for a worker is low since if the ctx is not 120 // checked the calling goroutine blocks waiting for a worker. 121 FastContextCheck(batchSize int) WorkerPool 122 123 // Size returns the size of the worker pool. 124 Size() int 125 } 126 127 // ScheduleResult is the result of scheduling a goroutine in the worker pool. 128 type ScheduleResult struct { 129 // Available is true if the goroutine was scheduled in the worker pool. False if the request timed out before a 130 // worker became available. 131 Available bool 132 // WaitTime is how long the goroutine had to wait before receiving a worker from the pool or timing out. 133 WaitTime time.Duration 134 } 135 136 // PooledWorkerPoolOptions is the options for a PooledWorkerPool. 137 type PooledWorkerPoolOptions interface { 138 // SetGrowOnDemand sets whether the GrowOnDemand feature is enabled. 139 SetGrowOnDemand(value bool) PooledWorkerPoolOptions 140 141 // GrowOnDemand returns whether the GrowOnDemand feature is enabled. 142 GrowOnDemand() bool 143 144 // SetNumShards sets the number of worker channel shards. 145 SetNumShards(value int64) PooledWorkerPoolOptions 146 147 // NumShards returns the number of worker channel shards. 148 NumShards() int64 149 150 // SetKillWorkerProbability sets the probability to kill a worker. 151 SetKillWorkerProbability(value float64) PooledWorkerPoolOptions 152 153 // KillWorkerProbability returns the probability to kill a worker. 154 KillWorkerProbability() float64 155 156 // SetNowFn sets the now function. 157 SetNowFn(value NowFn) PooledWorkerPoolOptions 158 159 // NowFn returns the now function. 160 NowFn() NowFn 161 162 // SetInstrumentOptions sets the instrument options. 163 SetInstrumentOptions(value instrument.Options) PooledWorkerPoolOptions 164 165 // InstrumentOptions returns the now function. 166 InstrumentOptions() instrument.Options 167 }