dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/balancer/loadstore/load_store_wrapper.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 /* 19 * 20 * Copyright 2020 gRPC authors. 21 * 22 */ 23 24 // Package loadstore contains the loadStoreWrapper shared by the balancers. 25 package loadstore 26 27 import ( 28 "sync" 29 ) 30 31 import ( 32 "dubbo.apache.org/dubbo-go/v3/xds/client/load" 33 ) 34 35 // NewWrapper creates a Wrapper. 36 func NewWrapper() *Wrapper { 37 return &Wrapper{} 38 } 39 40 // Wrapper wraps a load store with cluster and edsService. 41 // 42 // It's store and cluster/edsService can be updated separately. And it will 43 // update its internal perCluster store so that new stats will be added to the 44 // correct perCluster. 45 // 46 // Note that this struct is a temporary walkaround before we implement graceful 47 // switch for EDS. Any update to the clusterName and serviceName is too early, 48 // the perfect timing is when the picker is updated with the new connection. 49 // This early update could cause picks for the old SubConn being reported to the 50 // new services. 51 // 52 // When the graceful switch in EDS is done, there should be no need for this 53 // struct. The policies that record/report load shouldn't need to handle update 54 // of lrsServerName/cluster/edsService. Its parent should do a graceful switch 55 // of the whole tree when one of that changes. 56 type Wrapper struct { 57 mu sync.RWMutex 58 cluster string 59 edsService string 60 // store and perCluster are initialized as nil. They are only set by the 61 // balancer when LRS is enabled. Before that, all functions to record loads 62 // are no-op. 63 store *load.Store 64 perCluster load.PerClusterReporter 65 } 66 67 // UpdateClusterAndService updates the cluster name and eds service for this 68 // wrapper. If any one of them is changed from before, the perCluster store in 69 // this wrapper will also be updated. 70 func (lsw *Wrapper) UpdateClusterAndService(cluster, edsService string) { 71 lsw.mu.Lock() 72 defer lsw.mu.Unlock() 73 if cluster == lsw.cluster && edsService == lsw.edsService { 74 return 75 } 76 lsw.cluster = cluster 77 lsw.edsService = edsService 78 lsw.perCluster = lsw.store.PerCluster(lsw.cluster, lsw.edsService) 79 } 80 81 // UpdateLoadStore updates the load store for this wrapper. If it is changed 82 // from before, the perCluster store in this wrapper will also be updated. 83 func (lsw *Wrapper) UpdateLoadStore(store *load.Store) { 84 lsw.mu.Lock() 85 defer lsw.mu.Unlock() 86 if store == lsw.store { 87 return 88 } 89 lsw.store = store 90 lsw.perCluster = lsw.store.PerCluster(lsw.cluster, lsw.edsService) 91 } 92 93 // CallStarted records a call started in the store. 94 func (lsw *Wrapper) CallStarted(locality string) { 95 lsw.mu.RLock() 96 defer lsw.mu.RUnlock() 97 if lsw.perCluster != nil { 98 lsw.perCluster.CallStarted(locality) 99 } 100 } 101 102 // CallFinished records a call finished in the store. 103 func (lsw *Wrapper) CallFinished(locality string, err error) { 104 lsw.mu.RLock() 105 defer lsw.mu.RUnlock() 106 if lsw.perCluster != nil { 107 lsw.perCluster.CallFinished(locality, err) 108 } 109 } 110 111 // CallServerLoad records the server load in the store. 112 func (lsw *Wrapper) CallServerLoad(locality, name string, val float64) { 113 lsw.mu.RLock() 114 defer lsw.mu.RUnlock() 115 if lsw.perCluster != nil { 116 lsw.perCluster.CallServerLoad(locality, name, val) 117 } 118 } 119 120 // CallDropped records a call dropped in the store. 121 func (lsw *Wrapper) CallDropped(category string) { 122 lsw.mu.RLock() 123 defer lsw.mu.RUnlock() 124 if lsw.perCluster != nil { 125 lsw.perCluster.CallDropped(category) 126 } 127 }