diff --git a/config/base_config.go b/config/base_config.go index f58138d2e58a1b3da06894d3afa4728ea2ecf8fb..de0f9e7f8e9b7e8e01cab00a86d80ee3f6840cea 100644 --- a/config/base_config.go +++ b/config/base_config.go @@ -42,7 +42,11 @@ type multiConfiger interface { // BaseConfig is the common configuration for provider and consumer type BaseConfig struct { - ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` + ConfigCenterConfig *ConfigCenterConfig `yaml:"config_center" json:"config_center,omitempty"` + Remotes map[string]*RemoteConfig `yaml:"remotes" json:"remotes,omitempty"` + // application + ApplicationConfig *ApplicationConfig `yaml:"application" json:"application,omitempty" property:"application"` + configCenterUrl *common.URL prefix string fatherConfig interface{} @@ -51,6 +55,12 @@ type BaseConfig struct { fileStream *bytes.Buffer } +// GetRemoteConfig will return the remote's config with the name if found +func (c *BaseConfig) GetRemoteConfig(name string) (config *RemoteConfig, ok bool) { + config, ok = c.Remotes[name] + return +} + // startConfigCenter will start the config center. // it will prepare the environment func (c *BaseConfig) startConfigCenter() error { @@ -63,7 +73,7 @@ func (c *BaseConfig) startConfigCenter() error { if c.prepareEnvironment() != nil { return perrors.WithMessagef(err, "start config center error!") } - //c.fresh() + // c.fresh() return err } @@ -101,14 +111,14 @@ func (c *BaseConfig) prepareEnvironment() error { return perrors.WithStack(err) } } - //global config file + // global config file mapContent, err := dynamicConfig.Parser().Parse(content) if err != nil { return perrors.WithStack(err) } config.GetEnvInstance().UpdateExternalConfigMap(mapContent) - //appGroup config file + // appGroup config file if len(appContent) != 0 { appMapConent, err := dynamicConfig.Parser().Parse(appContent) if err != nil { @@ -264,7 +274,7 @@ func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryC if f.Kind() == reflect.Map { if f.Type().Elem().Kind() == reflect.Ptr { - //initiate config + // initiate config s := reflect.New(f.Type().Elem().Elem()) prefix := s.MethodByName("Prefix").Call(nil)[0].String() for _, pfx := range strings.Split(prefix, "|") { @@ -279,7 +289,7 @@ func setFieldValue(val reflect.Value, id reflect.Value, config *config.InmemoryC } - //iter := f.MapRange() + // iter := f.MapRange() for _, k := range f.MapKeys() { v := f.MapIndex(k) @@ -314,7 +324,7 @@ func (c *BaseConfig) fresh() { } func (c *BaseConfig) freshInternalConfig(config *config.InmemoryConfiguration) { - //reflect to init struct + // reflect to init struct tp := reflect.ValueOf(c.fatherConfig).Elem().Type() initializeStruct(tp, reflect.ValueOf(c.fatherConfig).Elem()) diff --git a/config/base_config_test.go b/config/base_config_test.go index 60eccfb1836dccbec0e8dc593a0954005117c28e..9c4b4f903dc7dac6aca60fd6ceb1eb1af0fd6c69 100644 --- a/config/base_config_test.go +++ b/config/base_config_test.go @@ -45,13 +45,15 @@ func Test_refresh(t *testing.T) { father := &ConsumerConfig{ Check: &[]bool{true}[0], - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{ "shanghai_reg2": { Protocol: "mock", @@ -139,13 +141,15 @@ func Test_appExternal_refresh(t *testing.T) { config.GetEnvInstance().UpdateExternalConfigMap(mockMap) father := &ConsumerConfig{ Check: &[]bool{true}[0], - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{ "shanghai_reg2": { Protocol: "mock", @@ -225,13 +229,15 @@ func Test_appExternalWithoutId_refresh(t *testing.T) { config.GetEnvInstance().UpdateExternalConfigMap(mockMap) father := &ConsumerConfig{ Check: &[]bool{true}[0], - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{ "shanghai_reg2": { Protocol: "mock", @@ -310,13 +316,15 @@ func Test_refresh_singleRegistry(t *testing.T) { father := &ConsumerConfig{ Check: &[]bool{true}[0], - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{}, Registry: &RegistryConfig{}, References: map[string]*ReferenceConfig{ @@ -373,13 +381,15 @@ func Test_refreshProvider(t *testing.T) { config.GetEnvInstance().UpdateExternalConfigMap(mockMap) father := &ProviderConfig{ - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{ "shanghai_reg2": { Protocol: "mock", diff --git a/config/config_loader.go b/config/config_loader.go index 1ed43ededdf9c8bfeb30c0c8f62b8c9a414246e6..8552caef89bc33210d29e2cfea0cc3715883d83d 100644 --- a/config/config_loader.go +++ b/config/config_loader.go @@ -21,6 +21,7 @@ import ( "fmt" "log" "os" + "sync" "time" ) @@ -37,12 +38,19 @@ import ( ) var ( - consumerConfig *ConsumerConfig - providerConfig *ProviderConfig - metricConfig *MetricConfig - applicationConfig *ApplicationConfig - maxWait = 3 - confRouterFile string + consumerConfig *ConsumerConfig + providerConfig *ProviderConfig + // baseConfig = providerConfig.BaseConfig or consumerConfig + baseConfig *BaseConfig + // baseConfigOnce is used to make sure that we only create it once. + baseConfigOnce sync.Once + + // configAccessMutex is used to make sure that BaseConfig.xxxxConfig will only be created once if needed. + // it should be used combine with double-check to avoid the race condition + configAccessMutex sync.Mutex + + maxWait = 3 + confRouterFile string ) // loaded consumer & provider config from xxx.yml, and log config from xxx.xml @@ -100,12 +108,6 @@ func loadConsumerConfig() { } } - metricConfig = consumerConfig.MetricConfig - applicationConfig = consumerConfig.ApplicationConfig - extension.SetAndInitGlobalDispatcher(consumerConfig.eventDispatcherType) - - extension.SetAndInitGlobalDispatcher(consumerConfig.eventDispatcherType) - checkApplicationName(consumerConfig.ApplicationConfig) if err := configCenterRefreshConsumer(); err != nil { logger.Errorf("[consumer config center refresh] %#v", err) @@ -126,14 +128,14 @@ func loadConsumerConfig() { ref.Implement(rpcService) } - //wait for invoker is available, if wait over default 3s, then panic + // wait for invoker is available, if wait over default 3s, then panic var count int checkok := true for { for _, refconfig := range consumerConfig.References { if (refconfig.Check != nil && *refconfig.Check) || (refconfig.Check == nil && consumerConfig.Check != nil && *consumerConfig.Check) || - (refconfig.Check == nil && consumerConfig.Check == nil) { //default to true + (refconfig.Check == nil && consumerConfig.Check == nil) { // default to true if refconfig.invoker != nil && !refconfig.invoker.IsAvailable() { @@ -178,13 +180,6 @@ func loadProviderConfig() { } } - // so, you should know that the consumer's config will be override - metricConfig = providerConfig.MetricConfig - applicationConfig = providerConfig.ApplicationConfig - extension.SetAndInitGlobalDispatcher(providerConfig.eventDispatcherType) - - extension.SetAndInitGlobalDispatcher(consumerConfig.eventDispatcherType) - checkApplicationName(providerConfig.ApplicationConfig) if err := configCenterRefreshProvider(); err != nil { logger.Errorf("[provider config center refresh] %#v", err) @@ -225,6 +220,9 @@ func Load() { // service config loadProviderConfig() + // common part + extension.SetAndInitGlobalDispatcher(providerConfig.eventDispatcherType) + // init the shutdown callback GracefulShutdownInit() } @@ -241,39 +239,83 @@ func RPCService(service common.RPCService) { // GetMetricConfig find the MetricConfig // if it is nil, create a new one +// we use double-check to reduce race condition +// In general, it will be locked 0 or 1 time. +// So you don't need to worry about the race condition func GetMetricConfig() *MetricConfig { - if metricConfig == nil { - metricConfig = &MetricConfig{} + if GetBaseConfig().MetricConfig == nil { + configAccessMutex.Lock() + defer configAccessMutex.Unlock() + if GetBaseConfig().MetricConfig == nil { + GetBaseConfig().MetricConfig = &MetricConfig{} + } } - return metricConfig + return GetBaseConfig().MetricConfig } // GetApplicationConfig find the application config // if not, we will create one // Usually applicationConfig will be initialized when system start +// we use double-check to reduce race condition +// In general, it will be locked 0 or 1 time. +// So you don't need to worry about the race condition func GetApplicationConfig() *ApplicationConfig { - if applicationConfig == nil { - applicationConfig = &ApplicationConfig{} + if GetBaseConfig().ApplicationConfig == nil { + configAccessMutex.Lock() + defer configAccessMutex.Unlock() + if GetBaseConfig().ApplicationConfig == nil { + GetBaseConfig().ApplicationConfig = &ApplicationConfig{} + } } - return applicationConfig + return GetBaseConfig().ApplicationConfig } // GetProviderConfig find the provider config // if not found, create new one +// we use double-check to reduce race condition +// In general, it will be locked 0 or 1 time. +// So you don't need to worry about the race condition func GetProviderConfig() ProviderConfig { if providerConfig == nil { - logger.Warnf("providerConfig is nil!") - return ProviderConfig{} + logger.Warnf("providerConfig is nil! we will try to create one") + configAccessMutex.Lock() + defer configAccessMutex.Unlock() + if providerConfig == nil { + logger.Warnf("creating empty provider config. You should see this log only once.") + providerConfig = &ProviderConfig{} + } } return *providerConfig } // GetConsumerConfig find the consumer config // if not found, create new one +// we use double-check to reduce race condition +// In general, it will be locked 0 or 1 time. +// So you don't need to worry about the race condition func GetConsumerConfig() ConsumerConfig { if consumerConfig == nil { - logger.Warnf("consumerConfig is nil!") - return ConsumerConfig{} + logger.Warnf("consumerConfig is nil! we will try to create one") + configAccessMutex.Lock() + defer configAccessMutex.Unlock() + if consumerConfig == nil { + logger.Warnf("creating empty consumer config. You should see this log only once.") + consumerConfig = &ConsumerConfig{} + } } return *consumerConfig } + +func GetBaseConfig() *BaseConfig { + if baseConfig == nil { + baseConfigOnce.Do(func() { + baseConfig = &BaseConfig{ + MetricConfig: &MetricConfig{}, + ConfigCenterConfig: &ConfigCenterConfig{}, + Remotes: make(map[string]*RemoteConfig, 0), + ApplicationConfig: &ApplicationConfig{}, + } + }) + } + return baseConfig +} diff --git a/config/config_loader_test.go b/config/config_loader_test.go index 0192b4c8a06263266cb80b344a0792ea2f6af8c8..f653f5e7598756514fd1e50dd2077329cbb3c9c0 100644 --- a/config/config_loader_test.go +++ b/config/config_loader_test.go @@ -235,16 +235,25 @@ func TestConfigLoaderWithConfigCenterSingleRegistry(t *testing.T) { } +func TestGetBaseConfig(t *testing.T) { + bc := GetBaseConfig() + assert.NotNil(t, bc) + _, found := bc.GetRemoteConfig("mock") + assert.False(t, found) +} + // mockInitProviderWithSingleRegistry will init a mocked providerConfig func mockInitProviderWithSingleRegistry() { providerConfig = &ProviderConfig{ - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "1.0.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "1.0.0", + Owner: "dubbo", + Environment: "test"}, + }, Registry: &RegistryConfig{ Address: "mock://127.0.0.1:2181", Username: "user1", diff --git a/config/consumer_config.go b/config/consumer_config.go index debcd79fa281c40e5526f60f5c5cdb66688688f4..76476511fbf74a5e973d59e560f65cab978d4527 100644 --- a/config/consumer_config.go +++ b/config/consumer_config.go @@ -42,9 +42,6 @@ import ( type ConsumerConfig struct { BaseConfig `yaml:",inline"` Filter string `yaml:"filter" json:"filter,omitempty" property:"filter"` - // application - ApplicationConfig *ApplicationConfig `yaml:"application" json:"application,omitempty" property:"application"` - // client Connect_Timeout string `default:"100ms" yaml:"connect_timeout" json:"connect_timeout,omitempty" property:"connect_timeout"` ConnectTimeout time.Duration diff --git a/config/provider_config.go b/config/provider_config.go index 79569917455773653750d1d5921a722daf079b0a..bdb9bd2f96eecfc0e9d3fc0e1f72ad95879e264a 100644 --- a/config/provider_config.go +++ b/config/provider_config.go @@ -43,8 +43,6 @@ type ProviderConfig struct { ProxyFactory string `yaml:"proxy_factory" default:"default" json:"proxy_factory,omitempty" property:"proxy_factory"` // metadata-report MetadataReportConfig *MetadataReportConfig `yaml:"metadata_report" json:"metadata_report,omitempty" property:"metadata_report"` - - ApplicationConfig *ApplicationConfig `yaml:"application" json:"application,omitempty" property:"application"` Registry *RegistryConfig `yaml:"registry" json:"registry,omitempty" property:"registry"` Registries map[string]*RegistryConfig `yaml:"registries" json:"registries,omitempty" property:"registries"` Services map[string]*ServiceConfig `yaml:"services" json:"services,omitempty" property:"services"` diff --git a/config/reference_config_test.go b/config/reference_config_test.go index 7a65e55f09c997cb49b83f1f185faf9338cf0f5a..faaa461a75a5c887f6fa1cc568d7e809c42a6ac4 100644 --- a/config/reference_config_test.go +++ b/config/reference_config_test.go @@ -38,13 +38,15 @@ var regProtocol protocol.Protocol func doInitConsumer() { consumerConfig = &ConsumerConfig{ - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{ "shanghai_reg1": { Protocol: "mock", @@ -135,13 +137,15 @@ func doInitConsumerAsync() { func doInitConsumerWithSingleRegistry() { consumerConfig = &ConsumerConfig{ - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registry: &RegistryConfig{ Address: "mock://27.0.0.1:2181", Username: "user1", diff --git a/config/remote_config.go b/config/remote_config.go new file mode 100644 index 0000000000000000000000000000000000000000..f126afc90f1147ab323460104b53308e30a0d1df --- /dev/null +++ b/config/remote_config.go @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package config + +type RemoteConfig struct { + Address string `yaml:"address" json:"address,omitempty"` + Params map[string]string `yaml:"params" json:"address,omitempty"` +} + + diff --git a/config/service_config_test.go b/config/service_config_test.go index 387e3ced7ad00d9d2240ca5833a36994f707720d..eff9735b3de2c4bae340cecf8ec601b57bf3b303 100644 --- a/config/service_config_test.go +++ b/config/service_config_test.go @@ -33,13 +33,15 @@ import ( func doInitProvider() { providerConfig = &ProviderConfig{ - ApplicationConfig: &ApplicationConfig{ - Organization: "dubbo_org", - Name: "dubbo", - Module: "module", - Version: "2.6.0", - Owner: "dubbo", - Environment: "test"}, + BaseConfig: BaseConfig{ + ApplicationConfig: &ApplicationConfig{ + Organization: "dubbo_org", + Name: "dubbo", + Module: "module", + Version: "2.6.0", + Owner: "dubbo", + Environment: "test"}, + }, Registries: map[string]*RegistryConfig{ "shanghai_reg1": { Protocol: "mock", diff --git a/registry/nacos/registry.go b/registry/nacos/registry.go index a436b85064829b9f42c9dcc45545e5bf2fd2fefe..a8d4916c6ebf990dc951963f05fe80ee2320add2 100644 --- a/registry/nacos/registry.go +++ b/registry/nacos/registry.go @@ -140,7 +140,7 @@ func (nr *nacosRegistry) subscribe(conf *common.URL) (registry.Listener, error) return NewNacosListener(*conf, nr.namingClient) } -//subscribe from registry +// subscribe from registry func (nr *nacosRegistry) Subscribe(url *common.URL, notifyListener registry.NotifyListener) { for { if !nr.IsAvailable() { @@ -179,6 +179,7 @@ func (nr *nacosRegistry) GetUrl() common.URL { } func (nr *nacosRegistry) IsAvailable() bool { + // TODO return true }