userver: userver/utils/swappingsmart.hpp Source File
Loading...
Searching...
No Matches
swappingsmart.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/utils/swappingsmart.hpp
4/// @brief @copybrief utils::SwappingSmart
5/// @ingroup userver_universal
6
7#include <atomic>
8#include <memory>
9
10USERVER_NAMESPACE_BEGIN
11
12namespace utils {
13
14/// @brief Deprecated RCU-like shared_ptr cell with swap-based updates for readers.
15///
16/// Use a faster and more reliable rcu::Variable instead of this class!
17///
18/// This class helps to store pointer. Pointer stored as shared_ptr.
19/// Whet you call Get, you will get copy of this shared pointer under read lock.
20/// When you call Set pointer, it will be stored under writelock.
21///
22/// It works slower than SwappingPtr in 5 times, but readers will always have
23/// shared_ptr that they obtained, so it is impossible that data will be free'd.
24template <typename T>
26public:
27 SwappingSmart() = default;
28
29 explicit SwappingSmart(const std::shared_ptr<T>& ptr) { Set(ptr); }
30
31 std::shared_ptr<T> Get() const {
32 const short index = current_.load(std::memory_order_relaxed);
33 return ptrs_[index];
34 }
35 void Set(const std::shared_ptr<T>& ptr) {
36 std::shared_ptr<T> buf = ptr;
37 // wait for write lock
38 while (write_lock_.test_and_set(std::memory_order_acquire)) {
39 }
40 // read current index
41 const short index = current_.load(std::memory_order_relaxed);
42 // get new index
43 const short new_index = 1 - index;
44 // store data in new index
45 std::swap(ptrs_[new_index], buf);
46 // enable new index
47 current_.store(new_index, std::memory_order_relaxed);
48 // unlock write lock
49 write_lock_.clear(std::memory_order_release);
50 // old value will be cleaned here, after lock
51 }
52 void Set(T&& obj) { Set(std::make_shared<T>(std::move(obj))); }
53 void Clear() {
54 Set(std::make_shared<T>());
55 Set(std::make_shared<T>());
56 }
57
58private:
59 std::atomic<short> current_{0};
60 std::atomic_flag write_lock_ ATOMIC_FLAG_INIT;
61 std::shared_ptr<T> ptrs_[2];
62};
63
64} // namespace utils
65
66USERVER_NAMESPACE_END