github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/aggregator/client/config.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 client 22 23 import ( 24 "errors" 25 "fmt" 26 "time" 27 28 "github.com/m3db/m3/src/aggregator/sharding" 29 m3clusterclient "github.com/m3db/m3/src/cluster/client" 30 "github.com/m3db/m3/src/cluster/kv" 31 "github.com/m3db/m3/src/cluster/placement" 32 "github.com/m3db/m3/src/metrics/encoding/protobuf" 33 producerconfig "github.com/m3db/m3/src/msg/producer/config" 34 "github.com/m3db/m3/src/x/clock" 35 "github.com/m3db/m3/src/x/instrument" 36 xio "github.com/m3db/m3/src/x/io" 37 "github.com/m3db/m3/src/x/pool" 38 "github.com/m3db/m3/src/x/retry" 39 40 "github.com/uber-go/tally" 41 ) 42 43 var errNoM3MsgOptions = errors.New("m3msg aggregator client: missing m3msg options") 44 45 // Configuration contains client configuration. 46 type Configuration struct { 47 Type AggregatorClientType `yaml:"type"` 48 M3Msg *M3MsgConfiguration `yaml:"m3msg"` 49 PlacementKV *kv.OverrideConfiguration `yaml:"placementKV"` 50 Watcher *placement.WatcherConfiguration `yaml:"placementWatcher"` 51 HashType *sharding.HashType `yaml:"hashType"` 52 ShardCutoverWarmupDuration *time.Duration `yaml:"shardCutoverWarmupDuration"` 53 ShardCutoffLingerDuration *time.Duration `yaml:"shardCutoffLingerDuration"` 54 Encoder EncoderConfiguration `yaml:"encoder"` 55 FlushSize int `yaml:"flushSize,omitempty"` // FlushSize is deprecated 56 FlushWorkerCount int `yaml:"flushWorkerCount"` 57 ForceFlushEvery time.Duration `yaml:"forceFlushEvery"` 58 MaxBatchSize int `yaml:"maxBatchSize"` 59 MaxTimerBatchSize int `yaml:"maxTimerBatchSize"` 60 QueueSize int `yaml:"queueSize"` 61 QueueDropType *DropType `yaml:"queueDropType"` 62 Connection ConnectionConfiguration `yaml:"connection"` 63 } 64 65 // NewAdminClient creates a new admin client. 66 func (c *Configuration) NewAdminClient( 67 kvClient m3clusterclient.Client, 68 clockOpts clock.Options, 69 instrumentOpts instrument.Options, 70 rwOpts xio.Options, 71 ) (AdminClient, error) { 72 client, err := c.NewClient(kvClient, clockOpts, instrumentOpts, rwOpts) 73 if err != nil { 74 return nil, err 75 } 76 return client.(AdminClient), nil 77 } 78 79 // NewClient creates a new client. 80 func (c *Configuration) NewClient( 81 kvClient m3clusterclient.Client, 82 clockOpts clock.Options, 83 instrumentOpts instrument.Options, 84 rwOpts xio.Options, 85 ) (Client, error) { 86 opts, err := c.NewClientOptions(kvClient, clockOpts, instrumentOpts, rwOpts) 87 if err != nil { 88 return nil, err 89 } 90 91 return NewClient(opts) 92 } 93 94 var ( 95 errLegacyClientNoPlacementKVConfig = errors.New("no placement KV config set") 96 errLegacyClientNoWatcherConfig = errors.New("no placement watcher config set") 97 ) 98 99 // NewClientOptions creates Options that can be used to 100 // create a New Aggregator Client. 101 func (c *Configuration) NewClientOptions( 102 kvClient m3clusterclient.Client, 103 clockOpts clock.Options, 104 instrumentOpts instrument.Options, 105 rwOpts xio.Options, 106 ) (Options, error) { 107 opts := NewOptions(). 108 SetAggregatorClientType(c.Type). 109 SetClockOptions(clockOpts). 110 SetInstrumentOptions(instrumentOpts). 111 SetRWOptions(rwOpts) 112 113 switch c.Type { 114 case M3MsgAggregatorClient: 115 m3msgCfg := c.M3Msg 116 if m3msgCfg == nil { 117 return nil, errNoM3MsgOptions 118 } 119 120 m3msgOpts, err := m3msgCfg.NewM3MsgOptions(kvClient, instrumentOpts, rwOpts) 121 if err != nil { 122 return nil, err 123 } 124 125 // Allow M3Msg options to override the timer options for instrument options. 126 opts = opts.SetInstrumentOptions( 127 opts.InstrumentOptions().SetTimerOptions(m3msgOpts.TimerOptions())) 128 129 // Set the M3Msg options configured. 130 opts = opts.SetM3MsgOptions(m3msgOpts) 131 case LegacyAggregatorClient: 132 placementKV := c.PlacementKV 133 if placementKV == nil { 134 return nil, errLegacyClientNoPlacementKVConfig 135 } 136 137 placementWatcher := c.Watcher 138 if placementWatcher == nil { 139 return nil, errLegacyClientNoWatcherConfig 140 } 141 142 scope := instrumentOpts.MetricsScope() 143 connectionOpts := c.Connection.NewConnectionOptions(scope.SubScope("connection")) 144 kvOpts, err := placementKV.NewOverrideOptions() 145 if err != nil { 146 return nil, err 147 } 148 149 placementStore, err := kvClient.Store(kvOpts) 150 if err != nil { 151 return nil, err 152 } 153 154 iOpts := instrumentOpts.SetMetricsScope(scope.SubScope("encoder")) 155 encoderOpts := c.Encoder.NewEncoderOptions(iOpts) 156 157 iOpts = instrumentOpts.SetMetricsScope(scope.SubScope("placement-watcher")) 158 watcherOpts := placementWatcher.NewOptions(placementStore, iOpts) 159 160 // Get the shard fn. 161 hashType := sharding.DefaultHash 162 if c.HashType != nil { 163 hashType = *c.HashType 164 } 165 shardFn, err := hashType.ShardFn() 166 if err != nil { 167 return nil, err 168 } 169 170 opts = opts.SetWatcherOptions(watcherOpts). 171 SetShardFn(shardFn). 172 SetEncoderOptions(encoderOpts). 173 SetConnectionOptions(connectionOpts) 174 175 if c.ShardCutoverWarmupDuration != nil { 176 opts = opts.SetShardCutoverWarmupDuration(*c.ShardCutoverWarmupDuration) 177 } 178 if c.ShardCutoffLingerDuration != nil { 179 opts = opts.SetShardCutoffLingerDuration(*c.ShardCutoffLingerDuration) 180 } 181 if c.FlushWorkerCount != 0 { 182 opts = opts.SetFlushWorkerCount(c.FlushWorkerCount) 183 } 184 if c.ForceFlushEvery != 0 { 185 opts = opts.SetForceFlushEvery(c.ForceFlushEvery) 186 } 187 if c.MaxBatchSize != 0 { 188 opts = opts.SetMaxBatchSize(c.MaxBatchSize) 189 } 190 if c.MaxTimerBatchSize != 0 { 191 opts = opts.SetMaxTimerBatchSize(c.MaxTimerBatchSize) 192 } 193 if c.QueueSize != 0 { 194 opts = opts.SetInstanceQueueSize(c.QueueSize) 195 } 196 if c.QueueDropType != nil { 197 opts = opts.SetQueueDropType(*c.QueueDropType) 198 } 199 default: 200 return nil, fmt.Errorf("unknown client type: %v", c.Type) 201 } 202 203 // Validate the options. 204 if err := opts.Validate(); err != nil { 205 return nil, err 206 } 207 return opts, nil 208 } 209 210 // ConnectionConfiguration contains the connection configuration. 211 type ConnectionConfiguration struct { 212 ConnectionTimeout time.Duration `yaml:"connectionTimeout"` 213 ConnectionKeepAlive *bool `yaml:"connectionKeepAlive"` 214 WriteTimeout time.Duration `yaml:"writeTimeout"` 215 InitReconnectThreshold int `yaml:"initReconnectThreshold"` 216 MaxReconnectThreshold int `yaml:"maxReconnectThreshold"` 217 ReconnectThresholdMultiplier int `yaml:"reconnectThresholdMultiplier"` 218 MaxReconnectDuration *time.Duration `yaml:"maxReconnectDuration"` 219 WriteRetries *retry.Configuration `yaml:"writeRetries"` 220 } 221 222 // NewConnectionOptions creates new connection options. 223 func (c *ConnectionConfiguration) NewConnectionOptions(scope tally.Scope) ConnectionOptions { 224 opts := NewConnectionOptions() 225 if c.ConnectionTimeout != 0 { 226 opts = opts.SetConnectionTimeout(c.ConnectionTimeout) 227 } 228 if c.ConnectionKeepAlive != nil { 229 opts = opts.SetConnectionKeepAlive(*c.ConnectionKeepAlive) 230 } 231 if c.WriteTimeout != 0 { 232 opts = opts.SetWriteTimeout(c.WriteTimeout) 233 } 234 if c.InitReconnectThreshold != 0 { 235 opts = opts.SetInitReconnectThreshold(c.InitReconnectThreshold) 236 } 237 if c.MaxReconnectThreshold != 0 { 238 opts = opts.SetMaxReconnectThreshold(c.MaxReconnectThreshold) 239 } 240 if c.ReconnectThresholdMultiplier != 0 { 241 opts = opts.SetReconnectThresholdMultiplier(c.ReconnectThresholdMultiplier) 242 } 243 if c.MaxReconnectDuration != nil { 244 opts = opts.SetMaxReconnectDuration(*c.MaxReconnectDuration) 245 } 246 if c.WriteRetries != nil { 247 retryOpts := c.WriteRetries.NewOptions(scope) 248 opts = opts.SetWriteRetryOptions(retryOpts) 249 } 250 return opts 251 } 252 253 // EncoderConfiguration configures the encoder. 254 type EncoderConfiguration struct { 255 InitBufferSize *int `yaml:"initBufferSize"` 256 MaxMessageSize *int `yaml:"maxMessageSize"` 257 BytesPool *pool.BucketizedPoolConfiguration `yaml:"bytesPool"` 258 } 259 260 // NewEncoderOptions create a new set of encoder options. 261 func (c *EncoderConfiguration) NewEncoderOptions( 262 instrumentOpts instrument.Options, 263 ) protobuf.UnaggregatedOptions { 264 opts := protobuf.NewUnaggregatedOptions() 265 if c.InitBufferSize != nil { 266 opts = opts.SetInitBufferSize(*c.InitBufferSize) 267 } 268 if c.MaxMessageSize != nil { 269 opts = opts.SetMaxMessageSize(*c.MaxMessageSize) 270 } 271 if c.BytesPool != nil { 272 sizeBuckets := c.BytesPool.NewBuckets() 273 objectPoolOpts := c.BytesPool.NewObjectPoolOptions(instrumentOpts) 274 bytesPool := pool.NewBytesPool(sizeBuckets, objectPoolOpts) 275 opts = opts.SetBytesPool(bytesPool) 276 bytesPool.Init() 277 } 278 return opts 279 } 280 281 // M3MsgConfiguration contains the M3Msg client configuration, required 282 // if using M3Msg client type. 283 type M3MsgConfiguration struct { 284 Producer producerconfig.ProducerConfiguration `yaml:"producer"` 285 } 286 287 // NewM3MsgOptions returns new M3Msg options from configuration. 288 func (c *M3MsgConfiguration) NewM3MsgOptions( 289 kvClient m3clusterclient.Client, 290 instrumentOpts instrument.Options, 291 rwOpts xio.Options, 292 ) (M3MsgOptions, error) { 293 opts := NewM3MsgOptions() 294 295 // For M3Msg clients we want to use the default timer options 296 // as defined by the default M3Msg options for low overhead 297 // timers. 298 instrumentOpts = instrumentOpts.SetTimerOptions(opts.TimerOptions()) 299 300 producer, err := c.Producer.NewProducer(kvClient, instrumentOpts, rwOpts) 301 if err != nil { 302 return nil, err 303 } 304 305 opts = opts.SetProducer(producer) 306 307 // Validate the options. 308 if err := opts.Validate(); err != nil { 309 return nil, err 310 } 311 return opts, nil 312 }