VLink  2.0.0
A high-performance communication middleware
getter-inl.h
Go to the documentation of this file.
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 <string>
28 #include <utility>
29 
30 #include "../base/cpu_profiler_guard.h"
31 #include "../base/logger.h"
32 #include "../getter.h"
33 #include "../impl/url.h"
34 #include "../serializer.h"
35 
36 namespace vlink {
37 
38 template <typename ValueT, SecurityType SecT>
39 inline typename Getter<ValueT, SecT>::UniquePtr Getter<ValueT, SecT>::create_unique(const std::string& url_str,
40  InitType type) {
41  return std::make_unique<Getter<ValueT, SecT>>(url_str, type);
42 }
43 
44 template <typename ValueT, SecurityType SecT>
45 inline typename Getter<ValueT, SecT>::SharedPtr Getter<ValueT, SecT>::create_shared(const std::string& url_str,
46  InitType type) {
47  return std::make_shared<Getter<ValueT, SecT>>(url_str, type);
48 }
49 
50 template <typename ValueT, SecurityType SecT>
51 template <typename ConfT, typename>
52 inline Getter<ValueT, SecT>::Getter(const ConfT& conf, InitType type) {
53  static_assert(ConfT::get_allow_impl_type() & kImplType, "Conf does not support getter mode.");
54 
55  if VUNLIKELY (!conf.parse(kImplType) || !conf.is_valid()) {
56  VLOG_F(conf, " getter configuration is invalid or could not be parsed.");
57  return;
58  }
59 
60  this->impl_ = conf.create_getter();
61 
62  if VUNLIKELY (!this->impl_) {
63  VLOG_F(conf, " getter implementation not available for this transport.");
64  return;
65  }
66 
67  this->impl_->transport_type = conf.get_transport_type();
68  this->impl_->ser_type = Serializer::get_serialized_type<kValueType, ValueT>();
69  this->impl_->schema_type = Serializer::get_schema_type<kValueType, ValueT>();
70  this->impl_->is_cdr_type = Serializer::is_cdr_type<ValueT>();
71 
72  if constexpr (std::is_same_v<ConfT, Url>) {
73  this->impl_->url = conf.get_str();
74  }
75 
76  if constexpr (SecT == SecurityType::kWithSecurity) {
77  this->impl_->is_security_type = true;
78  }
79 
80  if VLIKELY (type == InitType::kWithInit) {
81  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
82  }
83 }
84 
85 template <typename ValueT, SecurityType SecT>
86 inline Getter<ValueT, SecT>::Getter(const std::string& url_str, InitType type)
87  : Getter<ValueT, SecT>(Url(url_str), type) {}
88 
89 template <typename ValueT, SecurityType SecT>
91  // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
92  this->deinit();
93 }
94 
95 template <typename ValueT, SecurityType SecT>
96 inline std::optional<ValueT> Getter<ValueT, SecT>::get() const {
97  std::lock_guard lock(mtx_);
98  return value_;
99 }
100 
101 template <typename ValueT, SecurityType SecT>
102 inline bool Getter<ValueT, SecT>::wait_for_value(std::chrono::milliseconds timeout) {
103  if VUNLIKELY (timeout.count() == 0) {
104  VLOG_W("Getter: Timeout value is 0, using infinite wait instead.");
105  timeout = Timeout::kInfinite;
106  }
107 
108  std::unique_lock lock(mtx_);
109 
110  this->impl_->reset_interrupted();
111 
112  if (value_.has_value()) {
113  return true;
114  }
115 
116  has_value_notification_ = false;
117 
118  auto predicate = [this]() -> bool { return has_value_notification_ || this->impl_->is_interrupted(); };
119 
120  if (timeout.count() < 0) {
121  cv_.wait(lock, std::move(predicate));
122  return !this->impl_->is_interrupted();
123  } else {
124  return cv_.wait_for(lock, timeout, std::move(predicate)) && !this->impl_->is_interrupted();
125  }
126 }
127 
128 template <typename ValueT, SecurityType SecT>
129 inline bool Getter<ValueT, SecT>::listen(MsgCallback&& callback) {
130  if VUNLIKELY (this->impl_->is_listened) {
131  VLOG_F("Getter has already been listened.");
132  return false;
133  }
134 
135  callback_ = std::move(callback);
136 
137  this->impl_->is_listened = true;
138 
139  return true;
140 }
141 
142 template <typename ValueT, SecurityType SecT>
144  std::lock_guard lock(mtx_);
145  change_reporting_ = enable;
146 }
147 
148 template <typename ValueT, SecurityType SecT>
149 inline void Getter<ValueT, SecT>::set_manual_unloan(bool manual_unloan) {
150  this->impl_->set_manual_unloan(manual_unloan);
151  this->is_manual_unloan_ = manual_unloan;
152 }
153 
154 template <typename ValueT, SecurityType SecT>
156  this->impl_->set_latency_and_lost_enabled(enable);
157 }
158 
159 template <typename ValueT, SecurityType SecT>
161  return this->impl_->is_latency_and_lost_enabled();
162 }
163 
164 template <typename ValueT, SecurityType SecT>
165 inline int64_t Getter<ValueT, SecT>::get_latency() const {
166  return this->impl_->get_latency();
167 }
168 
169 template <typename ValueT, SecurityType SecT>
171  return this->impl_->get_lost();
172 }
173 
174 template <typename ValueT, SecurityType SecT>
176  std::lock_guard lock(mtx_);
177  return change_reporting_;
178 }
179 
180 template <typename ValueT, SecurityType SecT>
183  return false;
184  }
185 
186  listen_bytes([this](const Bytes& data) {
187 #ifndef VLINK_DISABLE_PROFILER
188  CpuProfilerGuard profiler_guard(this->impl_->profiler.get());
189 #endif
190 
191  {
192  std::lock_guard lock(mtx_);
193 
194  if (change_reporting_) {
195  if (value_.has_value() && last_cache_ == data) {
196  return;
197  }
198 
199  last_cache_ = data;
200  }
201  }
202 
203  if constexpr (std::is_same_v<ValueT, Bytes>) {
204  if VLIKELY (callback_) {
205  callback_(data);
206  }
207 
208  {
209  std::lock_guard lock(mtx_);
210 
211  has_value_notification_ = true;
212 
213  value_.emplace(data);
214  }
215 
216  cv_.notify_all();
217 
218  } else {
219  thread_local auto value = this->template get_default_value<ValueT>();
220 
221  if VUNLIKELY (!Serializer::deserialize<kValueType>(data, value, this->impl_->transport_type)) {
222  VLOG_T("Getter deserialize failed, url: ", this->impl_->url, ".");
223  return;
224  }
225 
226  if VLIKELY (callback_) {
227  callback_(value);
228  }
229 
230  {
231  std::lock_guard lock(mtx_);
232 
233  has_value_notification_ = true;
234 
235  value_.emplace(value);
236  }
237 
238  cv_.notify_all();
239  }
240  });
241 
242  return true;
243 }
244 
245 template <typename ValueT, SecurityType SecT>
248 
249  cv_.notify_all();
250 }
251 
252 template <typename ValueT, SecurityType SecT>
254  if VUNLIKELY (this->has_inited_.load(std::memory_order_acquire)) {
255  this->impl_->deinit_ext();
256  this->impl_->impl_type = kSubscriber;
257  this->impl_->init_ext();
258  } else {
259  this->impl_->impl_type = kSubscriber;
260  }
261 }
262 
263 template <typename ValueT, SecurityType SecT>
265  if (!this->has_inited_.load(std::memory_order_acquire)) {
266  return;
267  }
268 
269  this->impl_->listen([this, callback = std::move(callback)](const Bytes& data) {
270  if constexpr (SecT == SecurityType::kWithSecurity) {
271  Bytes sec_data;
272 
273  if VUNLIKELY (!this->impl_->security || !this->impl_->security->decrypt(data, sec_data)) {
274  VLOG_T("Getter decrypt failed, url: ", this->impl_->url, ".");
275  return;
276  }
277 
278  this->invoke_callback(callback, sec_data);
279  } else {
280  this->impl_->try_record(ActionType::kGet, data);
281 
282  this->invoke_callback(callback, data);
283  }
284  });
285 }
286 
287 template <typename ValueT>
288 template <typename SecurityConfigT>
290  SecurityConfigT&& sec_cfg,
291  InitType type) {
292  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
293  "SecurityConfigT must be Security::Config.");
294 
295  return std::make_unique<SecurityGetter<ValueT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
296 }
297 
298 template <typename ValueT>
299 template <typename SecurityConfigT>
301  SecurityConfigT&& sec_cfg,
302  InitType type) {
303  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
304  "SecurityConfigT must be Security::Config.");
305 
306  return std::make_shared<SecurityGetter<ValueT>>(url_str, std::forward<SecurityConfigT>(sec_cfg), type);
307 }
308 
309 template <typename ValueT>
310 template <typename ConfT, typename SecurityConfigT, typename>
311 inline SecurityGetter<ValueT>::SecurityGetter(const ConfT& conf, SecurityConfigT&& sec_cfg, InitType type)
313  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
314  "SecurityConfigT must be Security::Config.");
315 
316  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
317 
318  if VLIKELY (type == InitType::kWithInit) {
319  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
320  }
321 }
322 
323 template <typename ValueT>
324 template <typename SecurityConfigT>
325 inline SecurityGetter<ValueT>::SecurityGetter(const std::string& url_str, SecurityConfigT&& sec_cfg, InitType type)
326  : Getter<ValueT, SecurityType::kWithSecurity>(url_str, InitType::kWithoutInit) {
327  static_assert(std::is_same_v<std::decay_t<SecurityConfigT>, Security::Config>,
328  "SecurityConfigT must be Security::Config.");
329 
330  this->enable_security(std::forward<SecurityConfigT>(sec_cfg));
331 
332  if VLIKELY (type == InitType::kWithInit) {
333  this->init(); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
334  }
335 }
336 
337 } // namespace vlink
#define VLOG_F(...)
Definition: logger.h:791
#define VLOG_W(...)
Definition: logger.h:787
#define VLOG_T(...)
Definition: logger.h:781
#define VUNLIKELY(...)
Short alias for VLINK_UNLIKELY.
Definition: macros.h:289
#define VLIKELY(...)
Short alias for VLINK_LIKELY.
Definition: macros.h:284