• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2017 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 #include <grpc/impl/codegen/port_platform.h>
20 
21 #include <algorithm>
22 #include <cstring>
23 
24 #include "absl/container/inlined_vector.h"
25 
26 #include "src/core/lib/channel/channel_trace.h"
27 #include "src/core/lib/channel/channelz.h"
28 #include "src/core/lib/channel/channelz_registry.h"
29 #include "src/core/lib/gpr/useful.h"
30 #include "src/core/lib/gprpp/memory.h"
31 #include "src/core/lib/gprpp/sync.h"
32 
33 #include <grpc/support/alloc.h>
34 #include <grpc/support/log.h>
35 #include <grpc/support/string_util.h>
36 #include <grpc/support/sync.h>
37 
38 namespace grpc_core {
39 namespace channelz {
40 namespace {
41 
42 // singleton instance of the registry.
43 ChannelzRegistry* g_channelz_registry = nullptr;
44 
45 const int kPaginationLimit = 100;
46 
47 }  // anonymous namespace
48 
Init()49 void ChannelzRegistry::Init() { g_channelz_registry = new ChannelzRegistry(); }
50 
Shutdown()51 void ChannelzRegistry::Shutdown() { delete g_channelz_registry; }
52 
Default()53 ChannelzRegistry* ChannelzRegistry::Default() {
54   GPR_DEBUG_ASSERT(g_channelz_registry != nullptr);
55   return g_channelz_registry;
56 }
57 
InternalRegister(BaseNode * node)58 void ChannelzRegistry::InternalRegister(BaseNode* node) {
59   MutexLock lock(&mu_);
60   node->uuid_ = ++uuid_generator_;
61   node_map_[node->uuid_] = node;
62 }
63 
InternalUnregister(intptr_t uuid)64 void ChannelzRegistry::InternalUnregister(intptr_t uuid) {
65   GPR_ASSERT(uuid >= 1);
66   MutexLock lock(&mu_);
67   GPR_ASSERT(uuid <= uuid_generator_);
68   node_map_.erase(uuid);
69 }
70 
InternalGet(intptr_t uuid)71 RefCountedPtr<BaseNode> ChannelzRegistry::InternalGet(intptr_t uuid) {
72   MutexLock lock(&mu_);
73   if (uuid < 1 || uuid > uuid_generator_) {
74     return nullptr;
75   }
76   auto it = node_map_.find(uuid);
77   if (it == node_map_.end()) return nullptr;
78   // Found node.  Return only if its refcount is not zero (i.e., when we
79   // know that there is no other thread about to destroy it).
80   BaseNode* node = it->second;
81   if (!node->RefIfNonZero()) return nullptr;
82   return RefCountedPtr<BaseNode>(node);
83 }
84 
InternalGetTopChannels(intptr_t start_channel_id)85 std::string ChannelzRegistry::InternalGetTopChannels(
86     intptr_t start_channel_id) {
87   absl::InlinedVector<RefCountedPtr<BaseNode>, 10> top_level_channels;
88   RefCountedPtr<BaseNode> node_after_pagination_limit;
89   {
90     MutexLock lock(&mu_);
91     for (auto it = node_map_.lower_bound(start_channel_id);
92          it != node_map_.end(); ++it) {
93       BaseNode* node = it->second;
94       if (node->type() == BaseNode::EntityType::kTopLevelChannel &&
95           node->RefIfNonZero()) {
96         // Check if we are over pagination limit to determine if we need to set
97         // the "end" element. If we don't go through this block, we know that
98         // when the loop terminates, we have <= to kPaginationLimit.
99         // Note that because we have already increased this node's
100         // refcount, we need to decrease it, but we can't unref while
101         // holding the lock, because this may lead to a deadlock.
102         if (top_level_channels.size() == kPaginationLimit) {
103           node_after_pagination_limit.reset(node);
104           break;
105         }
106         top_level_channels.emplace_back(node);
107       }
108     }
109   }
110   Json::Object object;
111   if (!top_level_channels.empty()) {
112     // Create list of channels.
113     Json::Array array;
114     for (size_t i = 0; i < top_level_channels.size(); ++i) {
115       array.emplace_back(top_level_channels[i]->RenderJson());
116     }
117     object["channel"] = std::move(array);
118   }
119   if (node_after_pagination_limit == nullptr) object["end"] = true;
120   Json json(std::move(object));
121   return json.Dump();
122 }
123 
InternalGetServers(intptr_t start_server_id)124 std::string ChannelzRegistry::InternalGetServers(intptr_t start_server_id) {
125   absl::InlinedVector<RefCountedPtr<BaseNode>, 10> servers;
126   RefCountedPtr<BaseNode> node_after_pagination_limit;
127   {
128     MutexLock lock(&mu_);
129     for (auto it = node_map_.lower_bound(start_server_id);
130          it != node_map_.end(); ++it) {
131       BaseNode* node = it->second;
132       if (node->type() == BaseNode::EntityType::kServer &&
133           node->RefIfNonZero()) {
134         // Check if we are over pagination limit to determine if we need to set
135         // the "end" element. If we don't go through this block, we know that
136         // when the loop terminates, we have <= to kPaginationLimit.
137         // Note that because we have already increased this node's
138         // refcount, we need to decrease it, but we can't unref while
139         // holding the lock, because this may lead to a deadlock.
140         if (servers.size() == kPaginationLimit) {
141           node_after_pagination_limit.reset(node);
142           break;
143         }
144         servers.emplace_back(node);
145       }
146     }
147   }
148   Json::Object object;
149   if (!servers.empty()) {
150     // Create list of servers.
151     Json::Array array;
152     for (size_t i = 0; i < servers.size(); ++i) {
153       array.emplace_back(servers[i]->RenderJson());
154     }
155     object["server"] = std::move(array);
156   }
157   if (node_after_pagination_limit == nullptr) object["end"] = true;
158   Json json(std::move(object));
159   return json.Dump();
160 }
161 
InternalLogAllEntities()162 void ChannelzRegistry::InternalLogAllEntities() {
163   absl::InlinedVector<RefCountedPtr<BaseNode>, 10> nodes;
164   {
165     MutexLock lock(&mu_);
166     for (auto& p : node_map_) {
167       BaseNode* node = p.second;
168       if (node->RefIfNonZero()) {
169         nodes.emplace_back(node);
170       }
171     }
172   }
173   for (size_t i = 0; i < nodes.size(); ++i) {
174     std::string json = nodes[i]->RenderJsonString();
175     gpr_log(GPR_INFO, "%s", json.c_str());
176   }
177 }
178 
179 }  // namespace channelz
180 }  // namespace grpc_core
181 
grpc_channelz_get_top_channels(intptr_t start_channel_id)182 char* grpc_channelz_get_top_channels(intptr_t start_channel_id) {
183   return gpr_strdup(
184       grpc_core::channelz::ChannelzRegistry::GetTopChannels(start_channel_id)
185           .c_str());
186 }
187 
grpc_channelz_get_servers(intptr_t start_server_id)188 char* grpc_channelz_get_servers(intptr_t start_server_id) {
189   return gpr_strdup(
190       grpc_core::channelz::ChannelzRegistry::GetServers(start_server_id)
191           .c_str());
192 }
193 
grpc_channelz_get_server(intptr_t server_id)194 char* grpc_channelz_get_server(intptr_t server_id) {
195   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> server_node =
196       grpc_core::channelz::ChannelzRegistry::Get(server_id);
197   if (server_node == nullptr ||
198       server_node->type() !=
199           grpc_core::channelz::BaseNode::EntityType::kServer) {
200     return nullptr;
201   }
202   grpc_core::Json json = grpc_core::Json::Object{
203       {"server", server_node->RenderJson()},
204   };
205   return gpr_strdup(json.Dump().c_str());
206 }
207 
grpc_channelz_get_server_sockets(intptr_t server_id,intptr_t start_socket_id,intptr_t max_results)208 char* grpc_channelz_get_server_sockets(intptr_t server_id,
209                                        intptr_t start_socket_id,
210                                        intptr_t max_results) {
211   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> base_node =
212       grpc_core::channelz::ChannelzRegistry::Get(server_id);
213   if (base_node == nullptr ||
214       base_node->type() != grpc_core::channelz::BaseNode::EntityType::kServer) {
215     return nullptr;
216   }
217   // This cast is ok since we have just checked to make sure base_node is
218   // actually a server node.
219   grpc_core::channelz::ServerNode* server_node =
220       static_cast<grpc_core::channelz::ServerNode*>(base_node.get());
221   return gpr_strdup(
222       server_node->RenderServerSockets(start_socket_id, max_results).c_str());
223 }
224 
grpc_channelz_get_channel(intptr_t channel_id)225 char* grpc_channelz_get_channel(intptr_t channel_id) {
226   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> channel_node =
227       grpc_core::channelz::ChannelzRegistry::Get(channel_id);
228   if (channel_node == nullptr ||
229       (channel_node->type() !=
230            grpc_core::channelz::BaseNode::EntityType::kTopLevelChannel &&
231        channel_node->type() !=
232            grpc_core::channelz::BaseNode::EntityType::kInternalChannel)) {
233     return nullptr;
234   }
235   grpc_core::Json json = grpc_core::Json::Object{
236       {"channel", channel_node->RenderJson()},
237   };
238   return gpr_strdup(json.Dump().c_str());
239 }
240 
grpc_channelz_get_subchannel(intptr_t subchannel_id)241 char* grpc_channelz_get_subchannel(intptr_t subchannel_id) {
242   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> subchannel_node =
243       grpc_core::channelz::ChannelzRegistry::Get(subchannel_id);
244   if (subchannel_node == nullptr ||
245       subchannel_node->type() !=
246           grpc_core::channelz::BaseNode::EntityType::kSubchannel) {
247     return nullptr;
248   }
249   grpc_core::Json json = grpc_core::Json::Object{
250       {"subchannel", subchannel_node->RenderJson()},
251   };
252   return gpr_strdup(json.Dump().c_str());
253 }
254 
grpc_channelz_get_socket(intptr_t socket_id)255 char* grpc_channelz_get_socket(intptr_t socket_id) {
256   grpc_core::RefCountedPtr<grpc_core::channelz::BaseNode> socket_node =
257       grpc_core::channelz::ChannelzRegistry::Get(socket_id);
258   if (socket_node == nullptr ||
259       socket_node->type() !=
260           grpc_core::channelz::BaseNode::EntityType::kSocket) {
261     return nullptr;
262   }
263   grpc_core::Json json = grpc_core::Json::Object{
264       {"socket", socket_node->RenderJson()},
265   };
266   return gpr_strdup(json.Dump().c_str());
267 }
268