VLink  2.0.0
A high-performance communication middleware
node-inl.h
浏览该文件的文档.
1 /*
2  * Copyright (C) 2026 by Thun Lu. All rights reserved.
3  * Author: Thun Lu <thun.lu@zohomail.cn>
4  * Repo: https://github.com/thun-res/vlink
5  * _ __ __ _ __
6  * | | / / / / (_) ____ / /__
7  * | | / / / / / / / __ \ / //_/
8  * | |/ / / /___ / / / / / / / ,<
9  * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include <memory>
27 #include <mutex>
28 #include <string>
29 #include <utility>
30 
31 #include "../base/logger.h"
32 #include "../impl/types.h"
33 #include "../node.h"
34 #include "../version.h"
35 
36 namespace vlink {
37 
38 template <typename ImplT, SecurityType SecT>
39 inline bool Node<ImplT, SecT>::init() {
40  if constexpr (SecT == SecurityType::kWithSecurity) {
41  if VUNLIKELY (!impl_->security) {
42  VLOG_F("Node::init(): security node has no usable Security; check Security::Config. url: ", impl_->url);
43  }
44  }
45 
46  bool expected = false;
47 
48  if VUNLIKELY (!has_inited_.compare_exchange_strong(expected, true, std::memory_order_acq_rel,
49  std::memory_order_relaxed)) {
50  return false;
51  }
52 
54 
55  impl_->init();
56  impl_->init_ext();
57 
58  is_support_loan_ = impl_->is_support_loan();
59 
60  return true;
61 }
62 
63 template <typename ImplT, SecurityType SecT>
65  bool expected = true;
66 
67  if VUNLIKELY (!has_inited_.compare_exchange_strong(expected, false, std::memory_order_acq_rel,
68  std::memory_order_relaxed)) {
69  return false;
70  }
71 
72  interrupt(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
73 
74  if (quit_mtx_.has_value()) {
75  std::lock_guard quit_lock(quit_mtx_.value());
76  impl_->deinit();
77  impl_->deinit_ext();
78  } else {
79  impl_->deinit();
80  impl_->deinit_ext();
81  }
82 
83  return true;
84 }
85 
86 template <typename ImplT, SecurityType SecT>
87 inline bool Node<ImplT, SecT>::has_inited() const {
88  return has_inited_.load(std::memory_order_acquire);
89 }
90 
91 template <typename ImplT, SecurityType SecT>
93  return impl_->is_support_loan();
94 }
95 
96 template <typename ImplT, SecurityType SecT>
97 inline Bytes Node<ImplT, SecT>::loan(int64_t size) {
98  Bytes bytes = impl_->loan(size);
99 
100  return bytes;
101 }
102 
103 template <typename ImplT, SecurityType SecT>
104 inline bool Node<ImplT, SecT>::return_loan(const Bytes& bytes) {
105  return impl_->return_loan(bytes);
106 }
107 
108 template <typename ImplT, SecurityType SecT>
109 inline void Node<ImplT, SecT>::set_manual_unloan(bool manual_unloan) {
110  (void)manual_unloan;
111  VLOG_W("Node: Function [set_manual_unloan] is not supported.");
112 }
113 
114 template <typename ImplT, SecurityType SecT>
116  return is_manual_unloan_;
117 }
118 
119 template <typename ImplT, SecurityType SecT>
121  return impl_->suspend();
122 }
123 
124 template <typename ImplT, SecurityType SecT>
126  return impl_->resume();
127 }
128 
129 template <typename ImplT, SecurityType SecT>
130 inline bool Node<ImplT, SecT>::is_suspend() const {
131  return impl_->is_suspend();
132 }
133 
134 template <typename ImplT, SecurityType SecT>
135 inline bool Node<ImplT, SecT>::attach(class MessageLoop* message_loop) {
136  return impl_->attach(message_loop);
137 }
138 
139 template <typename ImplT, SecurityType SecT>
141  return impl_->detach();
142 }
143 
144 template <typename ImplT, SecurityType SecT>
146  return impl_->get_message_loop();
147 }
148 
149 template <typename ImplT, SecurityType SecT>
151  return impl_->interrupt();
152 }
153 
154 template <typename ImplT, SecurityType SecT>
156  return impl_->get_abstract_node();
157 }
158 
159 template <typename ImplT, SecurityType SecT>
161  return impl_->get_status(type);
162 }
163 
164 template <typename ImplT, SecurityType SecT>
166  impl_->register_status_handler(std::move(callback));
167 }
168 
169 template <typename ImplT, SecurityType SecT>
170 inline void Node<ImplT, SecT>::set_property(const std::string& prop, const std::string& value) {
171  impl_->set_property(prop, value);
172 }
173 
174 template <typename ImplT, SecurityType SecT>
175 inline std::string Node<ImplT, SecT>::get_property(const std::string& prop) const {
176  return impl_->get_property(prop);
177 }
178 
179 template <typename ImplT, SecurityType SecT>
181  return impl_->transport_type;
182 }
183 
184 template <typename ImplT, SecurityType SecT>
185 inline const std::string& Node<ImplT, SecT>::get_url() const {
186  return impl_->url;
187 }
188 
189 template <typename ImplT, SecurityType SecT>
190 inline void Node<ImplT, SecT>::set_record_path(const std::string& path) {
191  if VUNLIKELY (impl_->transport_type == TransportType::kIntra ||
192  (impl_->transport_type == TransportType::kDds && impl_->is_cdr_type)) {
193  VLOG_F("Node: Intra or Dds(cdr) type does not support record.");
194  return;
195  }
196 
197  impl_->set_record_path(path);
198 }
199 
200 template <typename ImplT, SecurityType SecT>
201 inline void Node<ImplT, SecT>::set_ser_type(const std::string& ser_type, SchemaType schema_type) {
202  auto next_schema_type = impl_->schema_type;
203 
204  if (ser_type.empty()) {
205  next_schema_type = SchemaType::kUnknown;
206  } else if (SchemaData::is_valid_type(schema_type) && schema_type != SchemaType::kUnknown) {
207  next_schema_type = schema_type;
208  } else {
209  const auto inferred_schema_type = SchemaData::infer_ser_type(ser_type);
210 
211  if VLIKELY (inferred_schema_type != SchemaType::kUnknown) {
212  next_schema_type = inferred_schema_type;
213  } else if (impl_->schema_type == SchemaType::kRaw || impl_->schema_type == SchemaType::kZeroCopy) {
214  next_schema_type = SchemaType::kUnknown;
215  }
216  }
217 
218  const bool ser_changed = impl_->ser_type != ser_type;
219  const bool schema_changed = impl_->schema_type != next_schema_type;
220 
221  if VLIKELY (!ser_changed && !schema_changed) {
222  return;
223  }
224 
225  if VUNLIKELY (ser_changed && !impl_->ser_type.empty() && !ser_type.empty()) {
226  CLOG_W("Node: Enforce serialization type [%s] => [%s].", impl_->ser_type.c_str(), ser_type.c_str());
227  }
228 
229  if VUNLIKELY (schema_changed && SchemaData::is_real_type(impl_->schema_type) &&
230  SchemaData::is_real_type(next_schema_type)) {
231  CLOG_W("Node: Enforce schema type [%d] => [%d].", static_cast<int>(impl_->schema_type),
232  static_cast<int>(next_schema_type));
233  }
234 
235  if VUNLIKELY (has_inited_.load(std::memory_order_acquire)) {
236  impl_->deinit_ext();
237  }
238 
239  impl_->ser_type = ser_type;
240  impl_->schema_type = next_schema_type;
241 
242  if VUNLIKELY (has_inited_.load(std::memory_order_acquire)) {
243  impl_->init_ext();
244  }
245 }
246 
247 template <typename ImplT, SecurityType SecT>
248 inline const std::string& Node<ImplT, SecT>::get_ser_type() const {
249  return impl_->ser_type;
250 }
251 
252 template <typename ImplT, SecurityType SecT>
254  return impl_->schema_type;
255 }
256 
257 template <typename ImplT, SecurityType SecT>
259  if VUNLIKELY (has_inited_.load(std::memory_order_acquire)) {
260  impl_->deinit_ext();
261  impl_->set_discovery_enabled(enable);
262  impl_->init_ext();
263  } else {
264  impl_->set_discovery_enabled(enable);
265  }
266 }
267 
268 template <typename ImplT, SecurityType SecT>
270  return impl_->get_discovery_enabled();
271 }
272 
273 template <typename ImplT, SecurityType SecT>
274 inline void Node<ImplT, SecT>::bind_proto_arena(void* proto_arena) {
275  proto_arena_ = proto_arena;
276 }
277 
278 template <typename ImplT, SecurityType SecT>
279 inline double Node<ImplT, SecT>::get_cpu_usage() const {
280  if VUNLIKELY (impl_->profiler) {
281  return impl_->profiler->get();
282  } else {
283  return -1;
284  }
285 }
286 
287 template <typename ImplT, SecurityType SecT>
289  return quit_mtx_.has_value();
290 }
291 
292 template <typename ImplT, SecurityType SecT>
293 inline void Node<ImplT, SecT>::set_safety_quit(bool safety_quit) {
294  if VUNLIKELY (safety_quit) {
295  if (!quit_mtx_.has_value()) {
296  quit_mtx_.emplace();
297  }
298  } else {
299  if (quit_mtx_.has_value()) {
300  quit_mtx_.reset();
301  }
302  }
303 }
304 
305 template <typename ImplT, SecurityType SecT>
306 inline void Node<ImplT, SecT>::set_ssl_options(const SslOptions& options) {
307  impl_->set_ssl_options(options);
308 }
309 
310 template <typename ImplT, SecurityType SecT>
312  static_assert(std::is_base_of_v<NodeImpl, ImplT>, "ImplT must be derived from NodeImpl.");
313 }
314 
315 template <typename ImplT, SecurityType SecT>
317  deinit(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
318 }
319 
320 template <typename ImplT, SecurityType SecT>
322  auto sec_cfg = cfg;
323 
324  return enable_security(std::move(sec_cfg));
325 }
326 
327 template <typename ImplT, SecurityType SecT>
329  static_assert(SecT == SecurityType::kWithSecurity, "Must be security type.");
330 
331  if VUNLIKELY (!impl_) {
332  return false;
333  }
334 
335  if VUNLIKELY (has_inited_.load(std::memory_order_acquire)) {
336  VLOG_W("Node::enable_security(): must run before init(); rejected to avoid live-traffic race.");
337  return false;
338  }
339 
340  return impl_->enable_security(std::move(cfg));
341 }
342 
343 template <typename ImplT, SecurityType SecT>
344 template <typename CallbackT, typename... ArgsT>
345 inline void Node<ImplT, SecT>::invoke_callback(const CallbackT& callback, ArgsT&&... args) {
346  if VUNLIKELY (quit_mtx_.has_value()) {
347  std::lock_guard quit_lock(quit_mtx_.value());
348  std::invoke(callback, std::forward<ArgsT>(args)...);
349  } else {
350  std::invoke(callback, std::forward<ArgsT>(args)...);
351  }
352 }
353 
354 template <typename ImplT, SecurityType SecT>
355 template <typename TypeT>
357  if constexpr (Traits::IsSharedPtr<TypeT>()) {
358  return std::make_shared<typename TypeT::element_type>();
359  } else if constexpr (Serializer::is_proto_ptr_type<TypeT>()) {
360  if VLIKELY (this->proto_arena_) {
361  return google::protobuf::Arena::Create<std::remove_pointer_t<TypeT>>(
362  static_cast<google::protobuf::Arena*>(this->proto_arena_));
363  }
364 
365  VLOG_F("Node: Proto arena is not bound, url: ", this->impl_->url, ".");
366 
367  return nullptr;
368  } else if constexpr (std::is_default_constructible_v<TypeT>) {
369  return TypeT{};
370  } else {
371  static_assert(Traits::ExpectFalse<TypeT>(), "TypeT is not default constructible.");
372  return {};
373  }
374 }
375 
376 } // namespace vlink
#define VLOG_F(...)
Definition: logger.h:791
#define VLOG_W(...)
Definition: logger.h:787
#define CLOG_W(...)
Definition: logger.h:799
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284
Definition: serializer-inl.h:101
#define VLINK_VERSION_PATCH
Definition: version.h:94
#define VLINK_VERSION_MAJOR
Definition: version.h:92
#define VLINK_VERSION_MINOR
Definition: version.h:93