dubbo.apache.org/dubbo-go/v3@v3.1.1/metadata/service/local/service.go (about) 1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package local 19 20 import ( 21 "sort" 22 "sync" 23 ) 24 25 import ( 26 "github.com/Workiva/go-datastructures/slice/skip" 27 28 "github.com/dubbogo/gost/log/logger" 29 ) 30 31 import ( 32 "dubbo.apache.org/dubbo-go/v3/common" 33 "dubbo.apache.org/dubbo-go/v3/common/constant" 34 "dubbo.apache.org/dubbo-go/v3/common/extension" 35 "dubbo.apache.org/dubbo-go/v3/config" 36 "dubbo.apache.org/dubbo-go/v3/metadata/definition" 37 "dubbo.apache.org/dubbo-go/v3/metadata/service" 38 ) 39 40 func init() { 41 extension.SetLocalMetadataService(constant.DefaultKey, GetLocalMetadataService) 42 } 43 44 // version will be used by Version func 45 const ( 46 version = "1.0.0" 47 ) 48 49 // MetadataService is store and query the metadata info in memory when each service registry 50 type MetadataService struct { 51 service.BaseMetadataService 52 exportedServiceURLs *sync.Map 53 subscribedServiceURLs *sync.Map 54 serviceDefinitions *sync.Map 55 lock *sync.RWMutex 56 mOnce *sync.Once 57 metadataInfo *common.MetadataInfo 58 metadataServiceURL *common.URL 59 } 60 61 var ( 62 metadataServiceInstance *MetadataService 63 metadataServiceInitOnce sync.Once 64 ) 65 66 // GetLocalMetadataService which should be singleton initiates a metadata service 67 func GetLocalMetadataService() (service.MetadataService, error) { 68 metadataServiceInitOnce.Do(func() { 69 metadataServiceInstance = &MetadataService{ 70 BaseMetadataService: service.NewBaseMetadataService(config.GetApplicationConfig().Name), 71 exportedServiceURLs: &sync.Map{}, 72 subscribedServiceURLs: &sync.Map{}, 73 serviceDefinitions: &sync.Map{}, 74 lock: &sync.RWMutex{}, 75 metadataInfo: nil, 76 mOnce: &sync.Once{}, 77 } 78 }) 79 return metadataServiceInstance, nil 80 } 81 82 // addURL will add URL in memory 83 func (mts *MetadataService) addURL(targetMap *sync.Map, url *common.URL) bool { 84 var ( 85 urlSet interface{} 86 loaded bool 87 ) 88 logger.Debug(url.ServiceKey()) 89 if urlSet, loaded = targetMap.LoadOrStore(url.ServiceKey(), skip.New(uint64(0))); loaded { 90 mts.lock.RLock() 91 wantedUrl := urlSet.(*skip.SkipList).Get(url) 92 if len(wantedUrl) > 0 && wantedUrl[0] != nil { 93 mts.lock.RUnlock() 94 return false 95 } 96 mts.lock.RUnlock() 97 } 98 mts.lock.Lock() 99 // double chk 100 wantedUrl := urlSet.(*skip.SkipList).Get(url) 101 if len(wantedUrl) > 0 && wantedUrl[0] != nil { 102 mts.lock.Unlock() 103 return false 104 } 105 urlSet.(*skip.SkipList).Insert(url) 106 mts.lock.Unlock() 107 return true 108 } 109 110 // removeURL is used to remove specified url 111 func (mts *MetadataService) removeURL(targetMap *sync.Map, url *common.URL) { 112 if value, loaded := targetMap.Load(url.ServiceKey()); loaded { 113 mts.lock.Lock() 114 value.(*skip.SkipList).Delete(url) 115 mts.lock.Unlock() 116 mts.lock.RLock() 117 defer mts.lock.RUnlock() 118 if value.(*skip.SkipList).Len() == 0 { 119 targetMap.Delete(url.ServiceKey()) 120 } 121 } 122 } 123 124 // getAllService can return all the exportedUrlString except for metadataService 125 func (mts *MetadataService) getAllService(services *sync.Map) []*common.URL { 126 // using skip list to dedup and sorting 127 var res []*common.URL 128 services.Range(func(key, value interface{}) bool { 129 urls := value.(*skip.SkipList) 130 for i := uint64(0); i < urls.Len(); i++ { 131 url := urls.ByPosition(i).(*common.URL) 132 if url.Service() != constant.MetadataServiceName { 133 res = append(res, url) 134 } 135 } 136 return true 137 }) 138 sort.Sort(common.URLSlice(res)) 139 return res 140 } 141 142 // getSpecifiedService can return specified service url by serviceKey 143 func (mts *MetadataService) getSpecifiedService(services *sync.Map, serviceKey string, protocol string) []*common.URL { 144 var res []*common.URL 145 serviceList, loaded := services.Load(serviceKey) 146 if loaded { 147 urls := serviceList.(*skip.SkipList) 148 for i := uint64(0); i < urls.Len(); i++ { 149 url := urls.ByPosition(i).(*common.URL) 150 if len(protocol) == 0 || protocol == constant.AnyValue || url.Protocol == protocol || url.GetParam(constant.ProtocolKey, "") == protocol { 151 res = append(res, url) 152 } 153 } 154 sort.Stable(common.URLSlice(res)) 155 } 156 return res 157 } 158 159 // ExportURL can store the in memory 160 func (mts *MetadataService) ExportURL(url *common.URL) (bool, error) { 161 if constant.MetadataServiceName == url.GetParam(constant.InterfaceKey, "") { 162 mts.metadataServiceURL = url 163 return true, nil 164 } 165 mts.mOnce.Do(func() { 166 mts.metadataInfo = common.NewMetadataInfWithApp(config.GetApplicationConfig().Name) 167 }) 168 mts.metadataInfo.AddService(common.NewServiceInfoWithURL(url)) 169 return mts.addURL(mts.exportedServiceURLs, url), nil 170 } 171 172 // UnexportURL can remove the url store in memory 173 func (mts *MetadataService) UnexportURL(url *common.URL) error { 174 if constant.MetadataServiceName == url.GetParam(constant.InterfaceKey, "") { 175 mts.metadataServiceURL = nil 176 return nil 177 } 178 if mts.metadataInfo != nil { 179 mts.metadataInfo.RemoveService(common.NewServiceInfoWithURL(url)) 180 } 181 mts.removeURL(mts.exportedServiceURLs, url) 182 return nil 183 } 184 185 // SubscribeURL can store the in memory 186 func (mts *MetadataService) SubscribeURL(url *common.URL) (bool, error) { 187 return mts.addURL(mts.subscribedServiceURLs, url), nil 188 } 189 190 // UnsubscribeURL can remove the url store in memory 191 func (mts *MetadataService) UnsubscribeURL(url *common.URL) error { 192 mts.removeURL(mts.subscribedServiceURLs, url) 193 return nil 194 } 195 196 // PublishServiceDefinition publish url's service metadata info, and write into memory 197 func (mts *MetadataService) PublishServiceDefinition(url *common.URL) error { 198 if common.RoleType(common.CONSUMER).Role() == url.GetParam(constant.SideKey, "") { 199 return nil 200 } 201 interfaceName := url.GetParam(constant.InterfaceKey, "") 202 isGeneric := url.GetParamBool(constant.GenericKey, false) 203 if len(interfaceName) > 0 && !isGeneric { 204 tmpService := common.ServiceMap.GetServiceByServiceKey(url.Protocol, url.ServiceKey()) 205 sd := definition.BuildFullDefinition(*tmpService, url) 206 data, err := sd.ToBytes() 207 if err != nil { 208 logger.Errorf("publishProvider getServiceDescriptor error. providerUrl:%v , error:%v ", url, err) 209 return nil 210 } 211 mts.serviceDefinitions.Store(url.ServiceKey(), string(data)) 212 return nil 213 } 214 logger.Errorf("publishProvider interfaceName is empty . providerUrl:%v ", url) 215 return nil 216 } 217 218 // GetExportedURLs get all exported urls 219 func (mts *MetadataService) GetExportedURLs(serviceInterface string, group string, version string, protocol string) ([]*common.URL, error) { 220 if serviceInterface == constant.AnyValue { 221 return mts.getAllService(mts.exportedServiceURLs), nil 222 } else { 223 serviceKey := definition.ServiceDescriperBuild(serviceInterface, group, version) 224 return mts.getSpecifiedService(mts.exportedServiceURLs, serviceKey, protocol), nil 225 } 226 } 227 228 // GetSubscribedURLs get all subscribedUrl 229 func (mts *MetadataService) GetSubscribedURLs() ([]*common.URL, error) { 230 return mts.getAllService(mts.subscribedServiceURLs), nil 231 } 232 233 // GetServiceDefinition can get service definition by interfaceName, group and version 234 func (mts *MetadataService) GetServiceDefinition(interfaceName string, group string, version string) (string, error) { 235 serviceKey := definition.ServiceDescriperBuild(interfaceName, group, version) 236 v, _ := mts.serviceDefinitions.Load(serviceKey) 237 return v.(string), nil 238 } 239 240 // GetServiceDefinitionByServiceKey can get service definition by serviceKey 241 func (mts *MetadataService) GetServiceDefinitionByServiceKey(serviceKey string) (string, error) { 242 v, _ := mts.serviceDefinitions.Load(serviceKey) 243 return v.(string), nil 244 } 245 246 // GetMetadataInfo can get metadata in memory 247 func (mts *MetadataService) GetMetadataInfo(revision string) (*common.MetadataInfo, error) { 248 if revision == "" { 249 return mts.metadataInfo, nil 250 } 251 if mts.metadataInfo.CalAndGetRevision() != revision { 252 return nil, nil 253 } 254 return mts.metadataInfo, nil 255 } 256 257 // GetExportedServiceURLs get exported service urls 258 func (mts *MetadataService) GetExportedServiceURLs() ([]*common.URL, error) { 259 return mts.getAllService(mts.exportedServiceURLs), nil 260 } 261 262 // RefreshMetadata will always return true because it will be implement by remote service 263 func (mts *MetadataService) RefreshMetadata(string, string) (bool, error) { 264 return true, nil 265 } 266 267 // Version will return the version of metadata service 268 func (mts *MetadataService) Version() (string, error) { 269 return version, nil 270 } 271 272 // GetMetadataServiceURL get url of MetadataService 273 func (mts *MetadataService) GetMetadataServiceURL() (*common.URL, error) { 274 return mts.metadataServiceURL, nil 275 } 276 277 // SetMetadataServiceURL save url of MetadataService 278 func (mts *MetadataService) SetMetadataServiceURL(url *common.URL) error { 279 mts.metadataServiceURL = url 280 return nil 281 }