1 //
2 // Copyright 2020 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include <grpc/support/port_platform.h>
18 
19 #include "src/core/ext/filters/client_channel/lb_policy/address_filtering.h"
20 
21 #include <stddef.h>
22 
23 #include <algorithm>
24 #include <utility>
25 
26 #include "absl/strings/str_cat.h"
27 #include "absl/strings/str_join.h"
28 
29 #define GRPC_ARG_HIERARCHICAL_PATH "grpc.internal.address.hierarchical_path"
30 
31 namespace grpc_core {
32 
33 const char* kHierarchicalPathAttributeKey = "hierarchical_path";
34 
35 namespace {
36 
37 class HierarchicalPathAttribute : public ServerAddress::AttributeInterface {
38  public:
HierarchicalPathAttribute(std::vector<std::string> path)39   explicit HierarchicalPathAttribute(std::vector<std::string> path)
40       : path_(std::move(path)) {}
41 
Copy() const42   std::unique_ptr<AttributeInterface> Copy() const override {
43     return std::make_unique<HierarchicalPathAttribute>(path_);
44   }
45 
Cmp(const AttributeInterface * other) const46   int Cmp(const AttributeInterface* other) const override {
47     const std::vector<std::string>& other_path =
48         static_cast<const HierarchicalPathAttribute*>(other)->path_;
49     for (size_t i = 0; i < path_.size(); ++i) {
50       if (other_path.size() == i) return 1;
51       int r = path_[i].compare(other_path[i]);
52       if (r != 0) return r;
53     }
54     if (other_path.size() > path_.size()) return -1;
55     return 0;
56   }
57 
ToString() const58   std::string ToString() const override {
59     return absl::StrCat("[", absl::StrJoin(path_, ", "), "]");
60   }
61 
path() const62   const std::vector<std::string>& path() const { return path_; }
63 
64  private:
65   std::vector<std::string> path_;
66 };
67 
68 }  // namespace
69 
70 std::unique_ptr<ServerAddress::AttributeInterface>
MakeHierarchicalPathAttribute(std::vector<std::string> path)71 MakeHierarchicalPathAttribute(std::vector<std::string> path) {
72   return std::make_unique<HierarchicalPathAttribute>(std::move(path));
73 }
74 
MakeHierarchicalAddressMap(const absl::StatusOr<ServerAddressList> & addresses)75 absl::StatusOr<HierarchicalAddressMap> MakeHierarchicalAddressMap(
76     const absl::StatusOr<ServerAddressList>& addresses) {
77   if (!addresses.ok()) return addresses.status();
78   HierarchicalAddressMap result;
79   for (const ServerAddress& address : *addresses) {
80     const HierarchicalPathAttribute* path_attribute =
81         static_cast<const HierarchicalPathAttribute*>(
82             address.GetAttribute(kHierarchicalPathAttributeKey));
83     if (path_attribute == nullptr) continue;
84     const std::vector<std::string>& path = path_attribute->path();
85     auto it = path.begin();
86     ServerAddressList& target_list = result[*it];
87     std::unique_ptr<HierarchicalPathAttribute> new_attribute;
88     ++it;
89     if (it != path.end()) {
90       std::vector<std::string> remaining_path(it, path.end());
91       new_attribute = std::make_unique<HierarchicalPathAttribute>(
92           std::move(remaining_path));
93     }
94     target_list.emplace_back(address.WithAttribute(
95         kHierarchicalPathAttributeKey, std::move(new_attribute)));
96   }
97   return result;
98 }
99 
100 }  // namespace grpc_core
101