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  }