PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
ebr.hpp
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2015-2018 Mindaugas Rasiukevicius <rmind at noxt eu>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 // SPDX-License-Identifier: BSD-3-Clause
28 /* Copyright 2021, Intel Corporation */
29 
35 #ifndef LIBPMEMOBJ_EBR_HPP
36 #define LIBPMEMOBJ_EBR_HPP
37 
38 #include <atomic>
39 #include <cassert>
40 #include <functional>
41 #include <mutex>
42 #include <thread>
43 #include <unordered_map>
44 
46 
47 namespace pmem
48 {
49 
50 namespace detail
51 {
52 
68 class ebr {
69  using atomic = std::atomic<size_t>;
70  using reference = std::reference_wrapper<atomic>;
71 
72 public:
73  class worker;
74 
75  ebr();
76 
77  worker register_worker();
78  bool sync();
79  void full_sync();
80  size_t staging_epoch();
81  size_t gc_epoch();
82 
83  class worker {
84  public:
85  worker(const worker &w) = delete;
86  worker(worker &&w) = default;
87  ~worker();
88 
89  worker &operator=(worker &w) = delete;
90  worker &operator=(worker &&w) = default;
91 
92  template <typename F>
93  void critical(F &&f);
94 
95  private:
96  worker(ebr *e_, reference ref);
97 
98  reference local_epoch;
99  ebr *e;
100 
101  friend ebr;
102  };
103 
104 private:
105  static const size_t ACTIVE_FLAG = static_cast<size_t>(1)
106  << (sizeof(size_t) * 8 - 1);
107  static const size_t EPOCHS_NUMBER = 3;
108 
109  atomic global_epoch;
110 
111  std::unordered_map<std::thread::id, atomic> workers;
112  std::mutex mtx;
113 };
114 
118 ebr::ebr() : global_epoch(0)
119 {
120 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
121  VALGRIND_HG_DISABLE_CHECKING(&global_epoch, sizeof(global_epoch));
122 #endif
123 }
124 
136 ebr::worker
138 {
139  std::lock_guard<std::mutex> lock(mtx);
140  auto res = workers.emplace(std::this_thread::get_id(), 0);
141  if (!res.second) {
142  throw std::runtime_error(
143  "There can be only one worker per thread");
144  }
145 
146  return worker{this, reference{res.first->second}};
147 }
148 
161 bool
163 {
164  auto current_epoch = global_epoch.load();
165 
166  std::lock_guard<std::mutex> lock(mtx);
167  for (auto &w : workers) {
168  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(
169  std::memory_order_seq_cst, &w.second);
170  auto local_e = w.second.load();
171  bool active = local_e & ACTIVE_FLAG;
172  if (active && (local_e != (current_epoch | ACTIVE_FLAG))) {
173  return false;
174  }
175  }
176 
177  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_BEFORE(std::memory_order_seq_cst,
178  &global_epoch);
179  global_epoch.store((current_epoch + 1) % EPOCHS_NUMBER);
180 
181  return true;
182 }
183 
191 void
193 {
194  size_t syncs_cnt = 0;
195  while (true) {
196  if (sync() && ++syncs_cnt == EPOCHS_NUMBER) {
197  break;
198  }
199  }
200 }
201 
210 size_t
212 {
213  auto res = global_epoch.load();
214  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(std::memory_order_seq_cst,
215  &global_epoch);
216  return res;
217 }
218 
227 size_t
229 {
230  auto res = (global_epoch.load() + 1) % EPOCHS_NUMBER;
231  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(std::memory_order_seq_cst,
232  &global_epoch);
233  return res;
234 }
235 
236 ebr::worker::worker(ebr *e_, reference ref) : local_epoch(ref), e(e_)
237 {
238 #if LIBPMEMOBJ_CPP_VG_HELGRIND_ENABLED
239  VALGRIND_HG_DISABLE_CHECKING(&ref.get(), sizeof(ref.get()));
240 #endif
241 }
242 
247 ebr::worker::~worker()
248 {
249  std::lock_guard<std::mutex> lock(e->mtx);
250  e->workers.erase(std::this_thread::get_id());
251 }
252 
261 template <typename F>
262 void
263 ebr::worker::critical(F &&f)
264 {
265  auto new_epoch = e->global_epoch.load() | ACTIVE_FLAG;
266  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(std::memory_order_seq_cst,
267  &(e->global_epoch));
268 
269  local_epoch.get().store(new_epoch);
270  LIBPMEMOBJ_CPP_ANNOTATE_HAPPENS_AFTER(std::memory_order_seq_cst,
271  &local_epoch);
272 
273  f();
274 
275  local_epoch.get().store(0);
276 }
277 
278 } /* namespace detail */
279 
280 } /* namespace pmem */
281 
282 #endif /* LIBPMEMOBJ_EBR_HPP */
Epoch-based reclamation (EBR).
Definition: ebr.hpp:68
bool sync()
Attempts to synchronise and announce a new epoch.
Definition: ebr.hpp:162
worker register_worker()
Registers and returns a new worker, which can perform critical operations (accessing some shared data...
Definition: ebr.hpp:137
size_t staging_epoch()
Returns the epoch where objects can be staged for reclamation.
Definition: ebr.hpp:211
ebr()
Default and only ebr constructor.
Definition: ebr.hpp:118
void full_sync()
Perform full synchronisation ensuring that all objects which are no longer globally visible (and pote...
Definition: ebr.hpp:192
size_t gc_epoch()
Returns the epoch available for reclamation, i.e.
Definition: ebr.hpp:228
Commonly used functionality.
Persistent memory namespace.
Definition: allocation_flag.hpp:15