github.com/polarismesh/polaris@v1.17.8/cache/service/service.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package service 19 20 import ( 21 "context" 22 "crypto/sha1" 23 "sort" 24 "strconv" 25 "strings" 26 "sync" 27 "time" 28 29 "go.uber.org/zap" 30 "golang.org/x/sync/singleflight" 31 32 types "github.com/polarismesh/polaris/cache/api" 33 "github.com/polarismesh/polaris/common/model" 34 "github.com/polarismesh/polaris/common/utils" 35 "github.com/polarismesh/polaris/store" 36 ) 37 38 // serviceCache Service data cache implementation class 39 type serviceCache struct { 40 *types.BaseCache 41 42 storage store.Store 43 // service_id -> service 44 ids *utils.SyncMap[string, *model.Service] 45 // namespace -> [serviceName -> service] 46 names *utils.SyncMap[string, *utils.SyncMap[string, *model.Service]] 47 // 兼容Cl5,sid -> name 48 cl5Sid2Name *utils.SyncMap[string, string] 49 // 兼容Cl5,name -> service 50 cl5Names *utils.SyncMap[string, *model.Service] 51 alias *serviceAliasBucket 52 serviceList *serviceNamespaceBucket 53 disableBusiness bool 54 needMeta bool 55 singleFlight *singleflight.Group 56 instCache types.InstanceCache 57 58 plock sync.RWMutex 59 // service-id -> struct{}{} 60 pendingServices *utils.SyncMap[string, struct{}] 61 countLock sync.Mutex 62 // namespace -> model.NamespaceServiceCount 63 namespaceServiceCnt *utils.SyncMap[string, *model.NamespaceServiceCount] 64 65 lastMtimeLogged int64 66 67 serviceCount int64 68 lastCheckAllTime int64 69 70 revisionWorker *ServiceRevisionWorker 71 72 cancel context.CancelFunc 73 } 74 75 // NewServiceCache 返回一个serviceCache 76 func NewServiceCache(storage store.Store, cacheMgr types.CacheManager) types.ServiceCache { 77 return &serviceCache{ 78 BaseCache: types.NewBaseCache(storage, cacheMgr), 79 storage: storage, 80 alias: newServiceAliasBucket(), 81 serviceList: newServiceNamespaceBucket(), 82 } 83 } 84 85 // initialize 缓存对象初始化 86 func (sc *serviceCache) Initialize(opt map[string]interface{}) error { 87 sc.instCache = sc.BaseCache.CacheMgr.GetCacher(types.CacheInstance).(*instanceCache) 88 sc.singleFlight = new(singleflight.Group) 89 sc.ids = utils.NewSyncMap[string, *model.Service]() 90 sc.names = utils.NewSyncMap[string, *utils.SyncMap[string, *model.Service]]() 91 sc.cl5Sid2Name = utils.NewSyncMap[string, string]() 92 sc.cl5Names = utils.NewSyncMap[string, *model.Service]() 93 sc.pendingServices = utils.NewSyncMap[string, struct{}]() 94 sc.namespaceServiceCnt = utils.NewSyncMap[string, *model.NamespaceServiceCount]() 95 sc.revisionWorker = newRevisionWorker(sc, sc.instCache.(*instanceCache)) 96 97 ctx, cancel := context.WithCancel(context.Background()) 98 sc.cancel = cancel 99 // 先启动revision计算协程 100 go sc.revisionWorker.revisionWorker(ctx) 101 if opt == nil { 102 return nil 103 } 104 sc.disableBusiness, _ = opt["disableBusiness"].(bool) 105 sc.needMeta, _ = opt["needMeta"].(bool) 106 return nil 107 } 108 109 // LastMtime 最后一次更新时间 110 func (sc *serviceCache) Close() error { 111 if err := sc.BaseCache.Close(); err != nil { 112 return err 113 } 114 if sc.cancel != nil { 115 sc.cancel() 116 } 117 return nil 118 } 119 120 // LastMtime 最后一次更新时间 121 func (sc *serviceCache) LastMtime() time.Time { 122 return sc.BaseCache.LastMtime(sc.Name()) 123 } 124 125 // update Service缓存更新函数 126 // service + service_metadata作为一个整体获取 127 func (sc *serviceCache) Update() error { 128 // 多个线程竞争,只有一个线程进行更新 129 _, err, _ := sc.singleFlight.Do(sc.Name(), func() (interface{}, error) { 130 defer func() { 131 sc.lastMtimeLogged = types.LogLastMtime(sc.lastMtimeLogged, sc.LastMtime().Unix(), "Service") 132 sc.checkAll() 133 }() 134 return nil, sc.DoCacheUpdate(sc.Name(), sc.realUpdate) 135 }) 136 return err 137 } 138 139 func (sc *serviceCache) checkAll() { 140 curTimeSec := time.Now().Unix() 141 if curTimeSec-sc.lastCheckAllTime < checkAllIntervalSec { 142 return 143 } 144 defer func() { 145 sc.lastCheckAllTime = curTimeSec 146 }() 147 count, err := sc.storage.GetServicesCount() 148 if err != nil { 149 log.Errorf("[Cache][Service] get service count from storage err: %s", err.Error()) 150 return 151 } 152 if sc.serviceCount == int64(count) { 153 return 154 } 155 log.Infof( 156 "[Cache][Service] service count not match, expect %d, actual %d, fallback to load all", 157 count, sc.serviceCount) 158 sc.ResetLastMtime(sc.Name()) 159 } 160 161 func (sc *serviceCache) realUpdate() (map[string]time.Time, int64, error) { 162 // 获取几秒前的全部数据 163 start := time.Now() 164 services, err := sc.storage.GetMoreServices(sc.LastFetchTime(), sc.IsFirstUpdate(), sc.disableBusiness, sc.needMeta) 165 if err != nil { 166 log.Errorf("[Cache][Service] update services err: %s", err.Error()) 167 return nil, -1, err 168 } 169 170 lastMtimes, update, del := sc.setServices(services) 171 costTime := time.Since(start) 172 log.Info("[Cache][Service] get more services", zap.Int("update", update), zap.Int("delete", del), 173 zap.Time("last", sc.LastMtime()), zap.Duration("used", costTime)) 174 return lastMtimes, int64(len(services)), err 175 } 176 177 // clear 清理内部缓存数据 178 func (sc *serviceCache) Clear() error { 179 sc.BaseCache.Clear() 180 sc.ids = utils.NewSyncMap[string, *model.Service]() 181 sc.names = utils.NewSyncMap[string, *utils.SyncMap[string, *model.Service]]() 182 sc.cl5Sid2Name = utils.NewSyncMap[string, string]() 183 sc.cl5Names = utils.NewSyncMap[string, *model.Service]() 184 sc.pendingServices = utils.NewSyncMap[string, struct{}]() 185 sc.namespaceServiceCnt = utils.NewSyncMap[string, *model.NamespaceServiceCount]() 186 sc.alias = newServiceAliasBucket() 187 sc.serviceList = newServiceNamespaceBucket() 188 return nil 189 } 190 191 // name 获取资源名称 192 func (sc *serviceCache) Name() string { 193 return types.ServiceName 194 } 195 196 func (sc *serviceCache) GetAliasFor(name string, namespace string) *model.Service { 197 svc := sc.GetServiceByName(name, namespace) 198 if svc == nil { 199 return nil 200 } 201 if svc.Reference == "" { 202 return nil 203 } 204 return sc.GetServiceByID(svc.Reference) 205 } 206 207 // GetServiceByID 根据服务ID获取服务数据 208 func (sc *serviceCache) GetServiceByID(id string) *model.Service { 209 if id == "" { 210 return nil 211 } 212 svc, ok := sc.ids.Load(id) 213 if !ok { 214 return nil 215 } 216 sc.fillServicePorts(svc) 217 return svc 218 } 219 220 // GetOrLoadServiceByID 先从缓存获取服务,如果没有的话,再从存储层获取,并设置到 Cache 中 221 func (sc *serviceCache) GetOrLoadServiceByID(id string) *model.Service { 222 if id == "" { 223 return nil 224 } 225 value, ok := sc.ids.Load(id) 226 if !ok { 227 _, _, _ = sc.singleFlight.Do(id, func() (interface{}, error) { 228 svc, err := sc.storage.GetServiceByID(id) 229 if err == nil && svc != nil { 230 sc.ids.Store(svc.ID, svc) 231 } 232 return svc, err 233 }) 234 235 value, ok = sc.ids.Load(id) 236 if !ok { 237 return nil 238 } 239 } 240 svc := value 241 sc.fillServicePorts(svc) 242 return svc 243 } 244 245 // GetServiceByName 根据服务名获取服务数据 246 func (sc *serviceCache) GetServiceByName(name string, namespace string) *model.Service { 247 if name == "" || namespace == "" { 248 return nil 249 } 250 251 spaces, ok := sc.names.Load(namespace) 252 if !ok { 253 return nil 254 } 255 value, ok := spaces.Load(name) 256 if !ok { 257 return nil 258 } 259 svc := value 260 sc.fillServicePorts(svc) 261 return svc 262 } 263 264 func (sc *serviceCache) fillServicePorts(svc *model.Service) { 265 if svc.Ports != "" { 266 return 267 } 268 if sc.instCache == nil { 269 return 270 } 271 ports := sc.instCache.GetServicePorts(svc.ID) 272 if len(ports) == 0 { 273 return 274 } 275 item := make([]string, 0, len(ports)) 276 for i := range ports { 277 item = append(item, strconv.FormatUint(uint64(ports[i].Port), 10)) 278 } 279 svc.ServicePorts = ports 280 svc.Ports = strings.Join(item, ",") 281 } 282 283 // CleanNamespace 清除Namespace对应的服务缓存 284 func (sc *serviceCache) CleanNamespace(namespace string) { 285 sc.names.Delete(namespace) 286 } 287 288 // IteratorServices 对缓存中的服务进行迭代 289 func (sc *serviceCache) IteratorServices(iterProc types.ServiceIterProc) error { 290 var ( 291 cont bool 292 err error 293 ) 294 295 proc := func(k string, svc *model.Service) bool { 296 sc.fillServicePorts(svc) 297 cont, err = iterProc(k, svc) 298 if err != nil { 299 return false 300 } 301 return cont 302 } 303 sc.ids.Range(proc) 304 return err 305 } 306 307 // GetNamespaceCntInfo Return to the service statistics according to the namespace, 308 // 309 // the count statistics and health instance statistics 310 func (sc *serviceCache) GetNamespaceCntInfo(namespace string) model.NamespaceServiceCount { 311 val, _ := sc.namespaceServiceCnt.Load(namespace) 312 if val == nil { 313 return model.NamespaceServiceCount{ 314 InstanceCnt: &model.InstanceCount{}, 315 } 316 } 317 318 return *val 319 } 320 321 // GetServicesCount 获取缓存中服务的个数 322 func (sc *serviceCache) GetServicesCount() int { 323 count := 0 324 sc.ids.Range(func(key string, value *model.Service) bool { 325 count++ 326 return true 327 }) 328 329 return count 330 } 331 332 // ListServices get service list and revision by namespace 333 func (sc *serviceCache) ListServices(ns string) (string, []*model.Service) { 334 return sc.serviceList.ListServices(ns) 335 } 336 337 // ListAllServices get all service and revision 338 func (sc *serviceCache) ListAllServices() (string, []*model.Service) { 339 return sc.serviceList.ListAllServices() 340 } 341 342 // ListServiceAlias get all service alias by target service 343 func (sc *serviceCache) ListServiceAlias(namespace, name string) []*model.Service { 344 return sc.alias.getServiceAliases(&model.Service{ 345 Namespace: namespace, 346 Name: name, 347 }) 348 } 349 350 // GetServiceByCl5Name obtains the corresponding SID according to cl5Name 351 func (sc *serviceCache) GetServiceByCl5Name(cl5Name string) *model.Service { 352 value, ok := sc.cl5Names.Load(genCl5Name(cl5Name)) 353 if !ok { 354 return nil 355 } 356 357 return value 358 } 359 360 // removeServices Delete the service data from the cache 361 func (sc *serviceCache) removeServices(service *model.Service) { 362 // Delete the index of serviceid 363 sc.ids.Delete(service.ID) 364 // delete service item from name list 365 sc.serviceList.removeService(service) 366 // delete service all link alias info 367 sc.alias.cleanServiceAlias(service) 368 // delete pending count service task 369 sc.pendingServices.Delete(service.ID) 370 371 // Delete the index of servicename 372 spaceName := service.Namespace 373 if spaces, ok := sc.names.Load(spaceName); ok { 374 spaces.Delete(service.Name) 375 } 376 377 /******Compatible CL5******/ 378 if cl5Name, ok := sc.cl5Sid2Name.Load(service.Name); ok { 379 sc.cl5Sid2Name.Delete(service.Name) 380 sc.cl5Names.Delete(cl5Name) 381 } 382 /******Compatible CL5******/ 383 } 384 385 // setServices 服务缓存更新 386 // 返回:更新数量,删除数量 387 func (sc *serviceCache) setServices(services map[string]*model.Service) (map[string]time.Time, int, int) { 388 if len(services) == 0 { 389 return nil, 0, 0 390 } 391 392 lastMtime := sc.LastMtime().Unix() 393 394 progress := 0 395 update := 0 396 del := 0 397 398 // 这里要记录 ns 的变动情况,避免由于 svc delete 之后,命名空间的服务计数无法更新 399 changeNs := make(map[string]struct{}) 400 svcCount := sc.serviceCount 401 402 aliases := make([]*model.Service, 0, 32) 403 404 for _, service := range services { 405 progress++ 406 if progress%20000 == 0 { 407 log.Infof( 408 "[Cache][Service] update service item progress(%d / %d)", progress, len(services)) 409 } 410 serviceMtime := service.ModifyTime.Unix() 411 if lastMtime < serviceMtime { 412 lastMtime = serviceMtime 413 } 414 415 if service.IsAlias() { 416 aliases = append(aliases, service) 417 } 418 419 spaceName := service.Namespace 420 changeNs[spaceName] = struct{}{} 421 // 发现有删除操作 422 if !service.Valid { 423 sc.removeServices(service) 424 sc.revisionWorker.Notify(service.ID, false) 425 del++ 426 svcCount-- 427 continue 428 } 429 430 update++ 431 _, exist := sc.ids.Load(service.ID) 432 if !exist { 433 svcCount++ 434 } 435 436 sc.ids.Store(service.ID, service) 437 sc.serviceList.addService(service) 438 sc.revisionWorker.Notify(service.ID, true) 439 440 spaces, ok := sc.names.Load(spaceName) 441 if !ok { 442 spaces = utils.NewSyncMap[string, *model.Service]() 443 sc.names.Store(spaceName, spaces) 444 } 445 spaces.Store(service.Name, service) 446 447 /******兼容cl5******/ 448 sc.updateCl5SidAndNames(service) 449 /******兼容cl5******/ 450 } 451 452 if sc.serviceCount != svcCount { 453 log.Infof("[Cache][Service] service count update from %d to %d", 454 sc.serviceCount, svcCount) 455 sc.serviceCount = svcCount 456 } 457 458 sc.postProcessServiceAlias(aliases) 459 sc.postProcessUpdatedServices(changeNs) 460 sc.serviceList.reloadRevision() 461 return map[string]time.Time{ 462 sc.Name(): time.Unix(lastMtime, 0), 463 }, update, del 464 } 465 466 func (sc *serviceCache) notifyServiceCountReload(svcIds map[string]bool) { 467 sc.plock.RLock() 468 defer sc.plock.RUnlock() 469 for k := range svcIds { 470 sc.pendingServices.Store(k, struct{}{}) 471 } 472 } 473 474 // appendServiceCountChangeNamespace 475 // Two Case 476 // Case ONE: 477 // 1. T1, ServiceCache pulls all of the service information 478 // 2. T2 time, instanecache pulls and updates the instance count information, and notify ServiceCache to 479 // count the namespace count Reload 480 // 481 // - In this case, the instancecache notifies the servicecache, ServiceCache is a fixed count update. 482 // Case TWO: 483 // 1. T1, instanecache pulls and updates the instance count information, and notify ServiceCache to 484 // make a namespace count Reload 485 // 2. T2 moments, ServiceCache pulls all of the service information 486 // 487 // - This situation, ServiceCache does not update the count, because the corresponding service object 488 // has not been cached, you need to put it in a PendingService waiting 489 // - Because under this case, WatchCountChangech is the first RELOAD notification from Instanecache, 490 // handled the reload notification of ServiceCache. 491 // - Therefore, for the reload notification of instancecache, you need to record the non-existing SVCID 492 // record in the Pending list; wait for the servicecache's Reload notification. after arriving, 493 // need to handle the last legacy PENDING calculation task. 494 func (sc *serviceCache) appendServiceCountChangeNamespace(changeNs map[string]struct{}) map[string]struct{} { 495 sc.plock.Lock() 496 defer sc.plock.Unlock() 497 waitDel := map[string]struct{}{} 498 sc.pendingServices.Range(func(svcId string, _ struct{}) bool { 499 svc, ok := sc.ids.Load(svcId) 500 if !ok { 501 return true 502 } 503 changeNs[svc.Namespace] = struct{}{} 504 waitDel[svcId] = struct{}{} 505 return true 506 }) 507 for svcId := range waitDel { 508 sc.pendingServices.Delete(svcId) 509 } 510 return changeNs 511 } 512 513 func (sc *serviceCache) postProcessServiceAlias(aliases []*model.Service) { 514 for i := range aliases { 515 alias := aliases[i] 516 517 _, aliasExist := sc.ids.Load(alias.ID) 518 aliasFor, aliasForExist := sc.ids.Load(alias.Reference) 519 if !aliasForExist { 520 continue 521 } 522 523 if aliasExist { 524 sc.alias.addServiceAlias(alias, aliasFor) 525 } else { 526 sc.alias.delServiceAlias(alias, aliasFor) 527 } 528 } 529 } 530 531 func (sc *serviceCache) postProcessUpdatedServices(affect map[string]struct{}) { 532 affect = sc.appendServiceCountChangeNamespace(affect) 533 sc.countLock.Lock() 534 defer sc.countLock.Unlock() 535 progress := 0 536 for namespace := range affect { 537 progress++ 538 if progress%10000 == 0 { 539 log.Infof("[Cache][Service] namespace service detail count progress(%d / %d)", progress, len(affect)) 540 } 541 // Construction of service quantity statistics 542 value, ok := sc.names.Load(namespace) 543 if !ok { 544 sc.namespaceServiceCnt.Delete(namespace) 545 continue 546 } 547 548 count, _ := sc.namespaceServiceCnt.LoadOrStore(namespace, &model.NamespaceServiceCount{}) 549 550 // For count information under the Namespace involved in the change, it is necessary to re-come over. 551 count.ServiceCount = 0 552 count.InstanceCnt = &model.InstanceCount{} 553 554 value.Range(func(key string, svc *model.Service) bool { 555 count.ServiceCount++ 556 insCnt := sc.instCache.GetInstancesCountByServiceID(svc.ID) 557 count.InstanceCnt.TotalInstanceCount += insCnt.TotalInstanceCount 558 count.InstanceCnt.HealthyInstanceCount += insCnt.HealthyInstanceCount 559 return true 560 }) 561 } 562 } 563 564 // updateCl5SidAndNames 更新cl5的服务数据 565 func (sc *serviceCache) updateCl5SidAndNames(service *model.Service) { 566 // 不是cl5服务的,不需要更新 567 if _, ok := service.Meta["internal-cl5-sid"]; !ok { 568 return 569 } 570 571 // service更新 572 // service中不存在cl5Name,可以认为是该sid删除了cl5Name,删除缓存 573 // service中存在cl5Name,则更新缓存 574 cl5NameMeta, ok := service.Meta["internal-cl5-name"] 575 sid := service.Name 576 if !ok { 577 if oldCl5Name, exist := sc.cl5Sid2Name.Load(sid); exist { 578 sc.cl5Sid2Name.Delete(sid) 579 sc.cl5Names.Delete(oldCl5Name) 580 } 581 return 582 } 583 584 // 更新的service,有cl5Name 585 cl5Name := genCl5Name(cl5NameMeta) 586 sc.cl5Sid2Name.Store(sid, cl5Name) 587 sc.cl5Names.Store(cl5Name, service) 588 } 589 590 // GetRevisionWorker 591 func (sc *serviceCache) GetRevisionWorker() types.ServiceRevisionWorker { 592 return sc.revisionWorker 593 } 594 595 // genCl5Name 兼容cl5Name 596 // 部分cl5Name与已有服务名存在冲突,因此给cl5Name加上一个前缀 597 func genCl5Name(name string) string { 598 return "cl5." + name 599 } 600 601 // ComputeRevision 计算唯一的版本标识 602 func ComputeRevision(serviceRevision string, instances []*model.Instance) (string, error) { 603 h := sha1.New() 604 if _, err := h.Write([]byte(serviceRevision)); err != nil { 605 return "", err 606 } 607 608 var slice sort.StringSlice 609 for _, item := range instances { 610 slice = append(slice, item.Revision()) 611 } 612 if len(slice) > 0 { 613 slice.Sort() 614 } 615 return types.ComputeRevisionBySlice(h, slice) 616 } 617 618 const ( 619 // RevisionConcurrenceCount Revision计算的并发线程数 620 RevisionConcurrenceCount = 64 621 // RevisionChanCount 存储revision计算的通知管道,可以稍微设置大一点 622 RevisionChanCount = 102400 623 ) 624 625 // 更新revision的结构体 626 type revisionNotify struct { 627 serviceID string 628 valid bool 629 } 630 631 // create new revision notify 632 func newRevisionNotify(serviceID string, valid bool) *revisionNotify { 633 return &revisionNotify{ 634 serviceID: serviceID, 635 valid: valid, 636 } 637 } 638 639 func newRevisionWorker(svcCache *serviceCache, instCache *instanceCache) *ServiceRevisionWorker { 640 return &ServiceRevisionWorker{ 641 svcCache: svcCache, 642 instCache: instCache, 643 comRevisionCh: make(chan *revisionNotify, RevisionChanCount), 644 revisions: map[string]string{}, 645 } 646 } 647 648 type ServiceRevisionWorker struct { 649 svcCache *serviceCache 650 instCache *instanceCache 651 652 comRevisionCh chan *revisionNotify 653 revisions map[string]string // service id -> reversion (所有instance reversion 的累计计算值) 654 lock sync.RWMutex // for revisions rw lock 655 } 656 657 func (sc *ServiceRevisionWorker) Notify(serviceID string, valid bool) { 658 sc.comRevisionCh <- newRevisionNotify(serviceID, valid) 659 } 660 661 // GetServiceInstanceRevision 获取服务实例计算之后的revision 662 func (sc *ServiceRevisionWorker) GetServiceInstanceRevision(serviceID string) string { 663 value, ok := sc.readRevisions(serviceID) 664 if !ok { 665 return "" 666 } 667 return value 668 } 669 670 // GetServiceRevisionCount 计算一下缓存中的revision的个数 671 func (sc *ServiceRevisionWorker) GetServiceRevisionCount() int { 672 sc.lock.RLock() 673 defer sc.lock.RUnlock() 674 675 return len(sc.revisions) 676 } 677 678 // revisionWorker Cache中计算服务实例revision的worker 679 func (sc *ServiceRevisionWorker) revisionWorker(ctx context.Context) { 680 log.Infof("[Cache] compute revision worker start") 681 defer log.Infof("[Cache] compute revision worker done") 682 683 // 启动多个协程来计算revision,后续可以通过启动参数控制 684 for i := 0; i < RevisionConcurrenceCount; i++ { 685 go func() { 686 for { 687 select { 688 case req := <-sc.comRevisionCh: 689 if ok := sc.processRevisionWorker(req); !ok { 690 continue 691 } 692 693 // 每个计算完,等待2ms 694 time.Sleep(2 * time.Millisecond) 695 case <-ctx.Done(): 696 return 697 } 698 } 699 }() 700 } 701 } 702 703 // processRevisionWorker 处理revision计算的函数 704 func (sc *ServiceRevisionWorker) processRevisionWorker(req *revisionNotify) bool { 705 if req == nil { 706 log.Errorf("[Cache][Revision] get null revision request") 707 return false 708 } 709 710 if req.serviceID == "" { 711 log.Errorf("[Cache][Revision] get request service ID is empty") 712 return false 713 } 714 715 if !req.valid { 716 log.Infof("[Cache][Revision] service(%s) revision has all been removed", req.serviceID) 717 sc.deleteRevisions(req.serviceID) 718 return true 719 } 720 721 service := sc.svcCache.GetServiceByID(req.serviceID) 722 if service == nil { 723 // log.Errorf("[Cache][Revision] can not found service id(%s)", req.serviceID) 724 return false 725 } 726 727 instances := sc.instCache.GetInstancesByServiceID(req.serviceID) 728 revision, err := ComputeRevision(service.Revision, instances) 729 if err != nil { 730 log.Errorf( 731 "[Cache] compute service id(%s) instances revision err: %s", req.serviceID, err.Error()) 732 return false 733 } 734 735 sc.setRevisions(req.serviceID, revision) // string -> string 736 log.Debugf("[Cache] compute service id(%s) instances revision : %s", req.serviceID, revision) 737 return true 738 } 739 740 func (sc *ServiceRevisionWorker) deleteRevisions(id string) { 741 sc.lock.Lock() 742 delete(sc.revisions, id) 743 sc.lock.Unlock() 744 } 745 746 func (sc *ServiceRevisionWorker) setRevisions(key string, val string) { 747 sc.lock.Lock() 748 sc.revisions[key] = val 749 sc.lock.Unlock() 750 } 751 752 func (sc *ServiceRevisionWorker) readRevisions(key string) (string, bool) { 753 sc.lock.RLock() 754 defer sc.lock.RUnlock() 755 756 id, ok := sc.revisions[key] 757 return id, ok 758 }