github.com/m3db/m3@v1.5.0/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 func (c *Configuration) newClientOptions( 100 kvClient m3clusterclient.Client, 101 clockOpts clock.Options, 102 instrumentOpts instrument.Options, 103 rwOpts xio.Options, 104 ) (Options, error) { 105 opts := NewOptions(). 106 SetAggregatorClientType(c.Type). 107 SetClockOptions(clockOpts). 108 SetInstrumentOptions(instrumentOpts). 109 SetRWOptions(rwOpts) 110 111 switch c.Type { 112 case M3MsgAggregatorClient: 113 m3msgCfg := c.M3Msg 114 if m3msgCfg == nil { 115 return nil, errNoM3MsgOptions 116 } 117 118 m3msgOpts, err := m3msgCfg.NewM3MsgOptions(kvClient, instrumentOpts, rwOpts) 119 if err != nil { 120 return nil, err 121 } 122 123 // Allow M3Msg options to override the timer options for instrument options. 124 opts = opts.SetInstrumentOptions( 125 opts.InstrumentOptions().SetTimerOptions(m3msgOpts.TimerOptions())) 126 127 // Set the M3Msg options configured. 128 opts = opts.SetM3MsgOptions(m3msgOpts) 129 case LegacyAggregatorClient: 130 placementKV := c.PlacementKV 131 if placementKV == nil { 132 return nil, errLegacyClientNoPlacementKVConfig 133 } 134 135 placementWatcher := c.Watcher 136 if placementWatcher == nil { 137 return nil, errLegacyClientNoWatcherConfig 138 } 139 140 scope := instrumentOpts.MetricsScope() 141 connectionOpts := c.Connection.NewConnectionOptions(scope.SubScope("connection")) 142 kvOpts, err := placementKV.NewOverrideOptions() 143 if err != nil { 144 return nil, err 145 } 146 147 placementStore, err := kvClient.Store(kvOpts) 148 if err != nil { 149 return nil, err 150 } 151 152 iOpts := instrumentOpts.SetMetricsScope(scope.SubScope("encoder")) 153 encoderOpts := c.Encoder.NewEncoderOptions(iOpts) 154 155 iOpts = instrumentOpts.SetMetricsScope(scope.SubScope("placement-watcher")) 156 watcherOpts := placementWatcher.NewOptions(placementStore, iOpts) 157 158 // Get the shard fn. 159 hashType := sharding.DefaultHash 160 if c.HashType != nil { 161 hashType = *c.HashType 162 } 163 shardFn, err := hashType.ShardFn() 164 if err != nil { 165 return nil, err 166 } 167 168 opts = opts.SetWatcherOptions(watcherOpts). 169 SetShardFn(shardFn). 170 SetEncoderOptions(encoderOpts). 171 SetConnectionOptions(connectionOpts) 172 173 if c.ShardCutoverWarmupDuration != nil { 174 opts = opts.SetShardCutoverWarmupDuration(*c.ShardCutoverWarmupDuration) 175 } 176 if c.ShardCutoffLingerDuration != nil { 177 opts = opts.SetShardCutoffLingerDuration(*c.ShardCutoffLingerDuration) 178 } 179 if c.FlushWorkerCount != 0 { 180 opts = opts.SetFlushWorkerCount(c.FlushWorkerCount) 181 } 182 if c.ForceFlushEvery != 0 { 183 opts = opts.SetForceFlushEvery(c.ForceFlushEvery) 184 } 185 if c.MaxBatchSize != 0 { 186 opts = opts.SetMaxBatchSize(c.MaxBatchSize) 187 } 188 if c.MaxTimerBatchSize != 0 { 189 opts = opts.SetMaxTimerBatchSize(c.MaxTimerBatchSize) 190 } 191 if c.QueueSize != 0 { 192 opts = opts.SetInstanceQueueSize(c.QueueSize) 193 } 194 if c.QueueDropType != nil { 195 opts = opts.SetQueueDropType(*c.QueueDropType) 196 } 197 default: 198 return nil, fmt.Errorf("unknown client type: %v", c.Type) 199 } 200 201 // Validate the options. 202 if err := opts.Validate(); err != nil { 203 return nil, err 204 } 205 return opts, nil 206 } 207 208 // ConnectionConfiguration contains the connection configuration. 209 type ConnectionConfiguration struct { 210 ConnectionTimeout time.Duration `yaml:"connectionTimeout"` 211 ConnectionKeepAlive *bool `yaml:"connectionKeepAlive"` 212 WriteTimeout time.Duration `yaml:"writeTimeout"` 213 InitReconnectThreshold int `yaml:"initReconnectThreshold"` 214 MaxReconnectThreshold int `yaml:"maxReconnectThreshold"` 215 ReconnectThresholdMultiplier int `yaml:"reconnectThresholdMultiplier"` 216 MaxReconnectDuration *time.Duration `yaml:"maxReconnectDuration"` 217 WriteRetries *retry.Configuration `yaml:"writeRetries"` 218 } 219 220 // NewConnectionOptions creates new connection options. 221 func (c *ConnectionConfiguration) NewConnectionOptions(scope tally.Scope) ConnectionOptions { 222 opts := NewConnectionOptions() 223 if c.ConnectionTimeout != 0 { 224 opts = opts.SetConnectionTimeout(c.ConnectionTimeout) 225 } 226 if c.ConnectionKeepAlive != nil { 227 opts = opts.SetConnectionKeepAlive(*c.ConnectionKeepAlive) 228 } 229 if c.WriteTimeout != 0 { 230 opts = opts.SetWriteTimeout(c.WriteTimeout) 231 } 232 if c.InitReconnectThreshold != 0 { 233 opts = opts.SetInitReconnectThreshold(c.InitReconnectThreshold) 234 } 235 if c.MaxReconnectThreshold != 0 { 236 opts = opts.SetMaxReconnectThreshold(c.MaxReconnectThreshold) 237 } 238 if c.ReconnectThresholdMultiplier != 0 { 239 opts = opts.SetReconnectThresholdMultiplier(c.ReconnectThresholdMultiplier) 240 } 241 if c.MaxReconnectDuration != nil { 242 opts = opts.SetMaxReconnectDuration(*c.MaxReconnectDuration) 243 } 244 if c.WriteRetries != nil { 245 retryOpts := c.WriteRetries.NewOptions(scope) 246 opts = opts.SetWriteRetryOptions(retryOpts) 247 } 248 return opts 249 } 250 251 // EncoderConfiguration configures the encoder. 252 type EncoderConfiguration struct { 253 InitBufferSize *int `yaml:"initBufferSize"` 254 MaxMessageSize *int `yaml:"maxMessageSize"` 255 BytesPool *pool.BucketizedPoolConfiguration `yaml:"bytesPool"` 256 } 257 258 // NewEncoderOptions create a new set of encoder options. 259 func (c *EncoderConfiguration) NewEncoderOptions( 260 instrumentOpts instrument.Options, 261 ) protobuf.UnaggregatedOptions { 262 opts := protobuf.NewUnaggregatedOptions() 263 if c.InitBufferSize != nil { 264 opts = opts.SetInitBufferSize(*c.InitBufferSize) 265 } 266 if c.MaxMessageSize != nil { 267 opts = opts.SetMaxMessageSize(*c.MaxMessageSize) 268 } 269 if c.BytesPool != nil { 270 sizeBuckets := c.BytesPool.NewBuckets() 271 objectPoolOpts := c.BytesPool.NewObjectPoolOptions(instrumentOpts) 272 bytesPool := pool.NewBytesPool(sizeBuckets, objectPoolOpts) 273 opts = opts.SetBytesPool(bytesPool) 274 bytesPool.Init() 275 } 276 return opts 277 } 278 279 // M3MsgConfiguration contains the M3Msg client configuration, required 280 // if using M3Msg client type. 281 type M3MsgConfiguration struct { 282 Producer producerconfig.ProducerConfiguration `yaml:"producer"` 283 } 284 285 // NewM3MsgOptions returns new M3Msg options from configuration. 286 func (c *M3MsgConfiguration) NewM3MsgOptions( 287 kvClient m3clusterclient.Client, 288 instrumentOpts instrument.Options, 289 rwOpts xio.Options, 290 ) (M3MsgOptions, error) { 291 opts := NewM3MsgOptions() 292 293 // For M3Msg clients we want to use the default timer options 294 // as defined by the default M3Msg options for low overhead 295 // timers. 296 instrumentOpts = instrumentOpts.SetTimerOptions(opts.TimerOptions()) 297 298 producer, err := c.Producer.NewProducer(kvClient, instrumentOpts, rwOpts) 299 if err != nil { 300 return nil, err 301 } 302 303 opts = opts.SetProducer(producer) 304 305 // Validate the options. 306 if err := opts.Validate(); err != nil { 307 return nil, err 308 } 309 return opts, nil 310 }