google.golang.org/grpc@v1.72.2/internal/hierarchy/hierarchy.go (about)

     1  /*
     2   *
     3   * Copyright 2020 gRPC authors.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * 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  // Package hierarchy contains functions to set and get hierarchy string from
    20  // addresses.
    21  //
    22  // This package is experimental.
    23  package hierarchy
    24  
    25  import (
    26  	"google.golang.org/grpc/resolver"
    27  )
    28  
    29  type pathKeyType string
    30  
    31  const pathKey = pathKeyType("grpc.internal.address.hierarchical_path")
    32  
    33  type pathValue []string
    34  
    35  func (p pathValue) Equal(o any) bool {
    36  	op, ok := o.(pathValue)
    37  	if !ok {
    38  		return false
    39  	}
    40  	if len(op) != len(p) {
    41  		return false
    42  	}
    43  	for i, v := range p {
    44  		if v != op[i] {
    45  			return false
    46  		}
    47  	}
    48  	return true
    49  }
    50  
    51  // FromEndpoint returns the hierarchical path of endpoint.
    52  func FromEndpoint(endpoint resolver.Endpoint) []string {
    53  	path, _ := endpoint.Attributes.Value(pathKey).(pathValue)
    54  	return path
    55  }
    56  
    57  // SetInEndpoint overrides the hierarchical path in endpoint with path.
    58  func SetInEndpoint(endpoint resolver.Endpoint, path []string) resolver.Endpoint {
    59  	endpoint.Attributes = endpoint.Attributes.WithValue(pathKey, pathValue(path))
    60  	return endpoint
    61  }
    62  
    63  // Get returns the hierarchical path of addr.
    64  func Get(addr resolver.Address) []string {
    65  	attrs := addr.BalancerAttributes
    66  	if attrs == nil {
    67  		return nil
    68  	}
    69  	path, _ := attrs.Value(pathKey).(pathValue)
    70  	return ([]string)(path)
    71  }
    72  
    73  // Set overrides the hierarchical path in addr with path.
    74  func Set(addr resolver.Address, path []string) resolver.Address {
    75  	addr.BalancerAttributes = addr.BalancerAttributes.WithValue(pathKey, pathValue(path))
    76  	return addr
    77  }
    78  
    79  // Group splits a slice of addresses into groups based on
    80  // the first hierarchy path. The first hierarchy path will be removed from the
    81  // result.
    82  //
    83  // Input:
    84  // [
    85  //
    86  //	{addr0, path: [p0, wt0]}
    87  //	{addr1, path: [p0, wt1]}
    88  //	{addr2, path: [p1, wt2]}
    89  //	{addr3, path: [p1, wt3]}
    90  //
    91  // ]
    92  //
    93  // Addresses will be split into p0/p1, and the p0/p1 will be removed from the
    94  // path.
    95  //
    96  // Output:
    97  //
    98  //	{
    99  //	  p0: [
   100  //	    {addr0, path: [wt0]},
   101  //	    {addr1, path: [wt1]},
   102  //	  ],
   103  //	  p1: [
   104  //	    {addr2, path: [wt2]},
   105  //	    {addr3, path: [wt3]},
   106  //	  ],
   107  //	}
   108  //
   109  // If hierarchical path is not set, or has no path in it, the address is
   110  // dropped.
   111  func Group(addrs []resolver.Address) map[string][]resolver.Address {
   112  	ret := make(map[string][]resolver.Address)
   113  	for _, addr := range addrs {
   114  		oldPath := Get(addr)
   115  		if len(oldPath) == 0 {
   116  			continue
   117  		}
   118  		curPath := oldPath[0]
   119  		newPath := oldPath[1:]
   120  		newAddr := Set(addr, newPath)
   121  		ret[curPath] = append(ret[curPath], newAddr)
   122  	}
   123  	return ret
   124  }
   125  
   126  // GroupEndpoints splits a slice of endpoints into groups based on
   127  // the first hierarchy path. The first hierarchy path will be removed from the
   128  // result.
   129  //
   130  // Input:
   131  // [
   132  //
   133  //	{endpoint0, path: [p0, wt0]}
   134  //	{endpoint1, path: [p0, wt1]}
   135  //	{endpoint2, path: [p1, wt2]}
   136  //	{endpoint3, path: [p1, wt3]}
   137  //
   138  // ]
   139  //
   140  // Endpoints will be split into p0/p1, and the p0/p1 will be removed from the
   141  // path.
   142  //
   143  // Output:
   144  //
   145  //	{
   146  //	  p0: [
   147  //	    {endpoint0, path: [wt0]},
   148  //	    {endpoint1, path: [wt1]},
   149  //	  ],
   150  //	  p1: [
   151  //	    {endpoint2, path: [wt2]},
   152  //	    {endpoint3, path: [wt3]},
   153  //	  ],
   154  //	}
   155  //
   156  // If hierarchical path is not set, or has no path in it, the endpoint is
   157  // dropped.
   158  func GroupEndpoints(endpoints []resolver.Endpoint) map[string][]resolver.Endpoint {
   159  	ret := make(map[string][]resolver.Endpoint)
   160  	for _, endpoint := range endpoints {
   161  		oldPath := FromEndpoint(endpoint)
   162  		if len(oldPath) == 0 {
   163  			continue
   164  		}
   165  		curPath := oldPath[0]
   166  		newPath := oldPath[1:]
   167  		newEndpoint := SetInEndpoint(endpoint, newPath)
   168  		ret[curPath] = append(ret[curPath], newEndpoint)
   169  	}
   170  	return ret
   171  }