github.com/m3db/m3@v1.5.0/src/dbnode/persist/fs/commitlog/options.go (about) 1 // Copyright (c) 2016 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 commitlog 22 23 import ( 24 "errors" 25 "fmt" 26 "runtime" 27 "time" 28 29 "github.com/m3db/m3/src/dbnode/persist/fs" 30 "github.com/m3db/m3/src/x/clock" 31 "github.com/m3db/m3/src/x/ident" 32 "github.com/m3db/m3/src/x/instrument" 33 "github.com/m3db/m3/src/x/pool" 34 ) 35 36 const ( 37 // defaultStrategy is the default commit log write strategy 38 defaultStrategy = StrategyWriteBehind 39 40 // defaultFailureStrategy is the default commit log failure strategy 41 defaultFailureStrategy = FailureStrategyPanic 42 43 // defaultFlushInterval is the default commit log flush interval 44 defaultFlushInterval = time.Second 45 46 // defaultFlushSize is the default commit log flush size 47 defaultFlushSize = 65536 48 49 // defaultBlockSize is the default commit log block size 50 defaultBlockSize = 15 * time.Minute 51 52 // defaultReadConcurrency is the default read concurrency 53 defaultReadConcurrency = 4 54 55 // MaximumQueueSizeQueueChannelSizeRatio is the maximum ratio between the 56 // backlog queue size and backlog queue channel size. 57 MaximumQueueSizeQueueChannelSizeRatio = 8.0 58 ) 59 60 var ( 61 // defaultBacklogQueueSize is the default commit log backlog queue size. 62 defaultBacklogQueueSize = 1024 * runtime.GOMAXPROCS(0) 63 64 // defaultBacklogQueueChannelSize is the default commit log backlog queue channel size. 65 defaultBacklogQueueChannelSize = int(float64(defaultBacklogQueueSize) / MaximumQueueSizeQueueChannelSizeRatio) 66 ) 67 68 var ( 69 errFlushIntervalNonNegative = errors.New("flush interval must be non-negative") 70 errBlockSizePositive = errors.New("block size must be a positive duration") 71 errReadConcurrencyPositive = errors.New("read concurrency must be a positive integer") 72 errMissingFailureCallback = errors.New("failure callback must be non-nil if FailureStrategyCallback is used") 73 ) 74 75 // FailureCallback is used in the FailureStrategyCallback failure mode. 76 // If this function returns false, the error will be treated as fatal. 77 // This function MUST exit quickly 78 type FailureCallback func(err error) bool 79 80 type options struct { 81 clockOpts clock.Options 82 instrumentOpts instrument.Options 83 blockSize time.Duration 84 fsOpts fs.Options 85 strategy Strategy 86 flushSize int 87 flushInterval time.Duration 88 backlogQueueSize int 89 backlogQueueChannelSize int 90 bytesPool pool.CheckedBytesPool 91 identPool ident.Pool 92 readConcurrency int 93 failureMode FailureStrategy 94 failureCallback FailureCallback 95 } 96 97 type optionsInput struct { 98 fsOptions fs.Options 99 // allows differentiating between explicitly nil and unset 100 fsOptionsSet bool 101 102 identPoolOpts ident.PoolOptions 103 bytePoolOptions pool.ObjectPoolOptions 104 } 105 106 // OptionSetter is a function that modifies the behavior of NewOptions 107 type OptionSetter func(o *optionsInput) 108 109 // WithFileSystemOptions is an OptionsSetter that provides custom fs.Options 110 // Passing nil will be equivalent to calling Options.SetFilesystemOptions(nil) 111 func WithFileSystemOptions(o fs.Options) OptionSetter { 112 return func(input *optionsInput) { 113 input.fsOptions = o 114 input.fsOptionsSet = true 115 } 116 } 117 118 // WithIdentPoolOptions is an OptionsSetter that provides options to the IdentifierPool 119 func WithIdentPoolOptions(o ident.PoolOptions) OptionSetter { 120 return func(input *optionsInput) { 121 input.identPoolOpts = o 122 } 123 } 124 125 // WithBytesPoolOptions is an OptionsSetter that provides options to BytesPool 126 func WithBytesPoolOptions(o pool.ObjectPoolOptions) OptionSetter { 127 return func(input *optionsInput) { 128 input.bytePoolOptions = o 129 } 130 } 131 132 // NewOptions creates new commit log options 133 func NewOptions(setters ...OptionSetter) Options { 134 presetOptions := optionsInput{} 135 for _, setter := range setters { 136 setter(&presetOptions) 137 } 138 139 if !presetOptions.fsOptionsSet && presetOptions.fsOptions == nil { 140 presetOptions.fsOptions = fs.NewOptions() 141 } 142 143 o := &options{ 144 clockOpts: clock.NewOptions(), 145 instrumentOpts: instrument.NewOptions(), 146 blockSize: defaultBlockSize, 147 fsOpts: presetOptions.fsOptions, 148 strategy: defaultStrategy, 149 failureMode: defaultFailureStrategy, 150 flushSize: defaultFlushSize, 151 flushInterval: defaultFlushInterval, 152 backlogQueueSize: defaultBacklogQueueSize, 153 backlogQueueChannelSize: defaultBacklogQueueChannelSize, 154 bytesPool: pool.NewCheckedBytesPool(nil, presetOptions.bytePoolOptions, func(s []pool.Bucket) pool.BytesPool { 155 return pool.NewBytesPool(s, presetOptions.bytePoolOptions) 156 }), 157 readConcurrency: defaultReadConcurrency, 158 failureCallback: nil, 159 } 160 161 o.bytesPool.Init() 162 o.identPool = ident.NewPool(o.bytesPool, presetOptions.identPoolOpts) 163 return o 164 } 165 166 func (o *options) Validate() error { 167 if o.FlushInterval() < 0 { 168 return errFlushIntervalNonNegative 169 } 170 171 if o.BlockSize() <= 0 { 172 return errBlockSizePositive 173 } 174 175 if o.ReadConcurrency() <= 0 { 176 return errReadConcurrencyPositive 177 } 178 179 if float64(o.BacklogQueueSize())/float64(o.BacklogQueueChannelSize()) > MaximumQueueSizeQueueChannelSizeRatio { 180 return fmt.Errorf( 181 "BacklogQueueSize / BacklogQueueChannelSize ratio must be at most: %f, but was: %f", 182 MaximumQueueSizeQueueChannelSizeRatio, float64(o.BacklogQueueSize())/float64(o.BacklogQueueChannelSize())) 183 } 184 185 if o.FailureStrategy() == FailureStrategyCallback && o.FailureCallback() == nil { 186 return errMissingFailureCallback 187 } 188 189 return nil 190 } 191 192 func (o *options) SetClockOptions(value clock.Options) Options { 193 opts := *o 194 opts.clockOpts = value 195 return &opts 196 } 197 198 func (o *options) ClockOptions() clock.Options { 199 return o.clockOpts 200 } 201 202 func (o *options) SetInstrumentOptions(value instrument.Options) Options { 203 opts := *o 204 opts.instrumentOpts = value 205 return &opts 206 } 207 208 func (o *options) InstrumentOptions() instrument.Options { 209 return o.instrumentOpts 210 } 211 212 func (o *options) SetBlockSize(value time.Duration) Options { 213 opts := *o 214 opts.blockSize = value 215 return &opts 216 } 217 218 func (o *options) BlockSize() time.Duration { 219 return o.blockSize 220 } 221 222 func (o *options) SetFilesystemOptions(value fs.Options) Options { 223 opts := *o 224 opts.fsOpts = value 225 return &opts 226 } 227 228 func (o *options) FilesystemOptions() fs.Options { 229 return o.fsOpts 230 } 231 232 func (o *options) SetStrategy(value Strategy) Options { 233 opts := *o 234 opts.strategy = value 235 return &opts 236 } 237 238 func (o *options) Strategy() Strategy { 239 return o.strategy 240 } 241 242 func (o *options) SetFlushSize(value int) Options { 243 opts := *o 244 opts.flushSize = value 245 return &opts 246 } 247 248 func (o *options) FlushSize() int { 249 return o.flushSize 250 } 251 252 func (o *options) SetFlushInterval(value time.Duration) Options { 253 opts := *o 254 opts.flushInterval = value 255 return &opts 256 } 257 258 func (o *options) FlushInterval() time.Duration { 259 return o.flushInterval 260 } 261 262 func (o *options) SetBacklogQueueSize(value int) Options { 263 opts := *o 264 opts.backlogQueueSize = value 265 return &opts 266 } 267 268 func (o *options) BacklogQueueSize() int { 269 return o.backlogQueueSize 270 } 271 272 func (o *options) SetBacklogQueueChannelSize(value int) Options { 273 opts := *o 274 opts.backlogQueueChannelSize = value 275 return &opts 276 } 277 278 func (o *options) BacklogQueueChannelSize() int { 279 return o.backlogQueueChannelSize 280 } 281 282 func (o *options) SetBytesPool(value pool.CheckedBytesPool) Options { 283 opts := *o 284 opts.bytesPool = value 285 return &opts 286 } 287 288 func (o *options) BytesPool() pool.CheckedBytesPool { 289 return o.bytesPool 290 } 291 292 func (o *options) SetReadConcurrency(concurrency int) Options { 293 opts := *o 294 opts.readConcurrency = concurrency 295 return &opts 296 } 297 298 func (o *options) ReadConcurrency() int { 299 return o.readConcurrency 300 } 301 302 func (o *options) SetIdentifierPool(value ident.Pool) Options { 303 opts := *o 304 opts.identPool = value 305 return &opts 306 } 307 308 func (o *options) IdentifierPool() ident.Pool { 309 return o.identPool 310 } 311 312 func (o *options) SetFailureStrategy(value FailureStrategy) Options { 313 opts := *o 314 opts.failureMode = value 315 return &opts 316 } 317 318 func (o *options) FailureStrategy() FailureStrategy { 319 return o.failureMode 320 } 321 322 func (o *options) SetFailureCallback(value FailureCallback) Options { 323 opts := *o 324 opts.failureCallback = value 325 return &opts 326 } 327 328 func (o *options) FailureCallback() FailureCallback { 329 return o.failureCallback 330 }