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 }