PMDK C++ bindings  1.9.1
This is the C++ bindings documentation for PMDK's libpmemobj.
volatile_state.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019-2020, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  *
16  * * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
40 #ifndef LIBPMEMOBJ_CPP_VOLATILE_STATE_HPP
41 #define LIBPMEMOBJ_CPP_VOLATILE_STATE_HPP
42 
43 #include <cassert>
44 #include <functional>
45 #include <memory>
46 #include <mutex>
47 #include <shared_mutex>
48 #include <tuple>
49 #include <unordered_map>
50 
53 #include <libpmemobj++/pool.hpp>
55 
56 namespace pmem
57 {
58 
59 namespace detail
60 {
61 
68 public:
69  template <typename T>
70  static T *
71  get_if_exists(const PMEMoid &oid)
72  {
73  auto &map = get_map();
74 
75  {
76  std::shared_lock<rwlock_type> lock(get_rwlock());
77  auto it = map.find(oid);
78  if (it != map.end())
79  return static_cast<T *>(it->second.get());
80  else
81  return nullptr;
82  }
83  }
84 
85  template <typename T>
86  static T *
87  get(const PMEMoid &oid)
88  {
89  auto &map = get_map();
90 
91  auto element = get_if_exists<T>(oid);
92  if (element)
93  return element;
94 
95  if (pmemobj_tx_stage() != TX_STAGE_NONE)
97  "volatile_state::get() cannot be called in a transaction");
98 
99  {
100  std::unique_lock<rwlock_type> lock(get_rwlock());
101 
102  auto deleter = [](void const *data) {
103  T const *p = static_cast<T const *>(data);
104  delete p;
105  };
106 
107  auto it = map.find(oid);
108  if (it == map.end()) {
109  auto ret = map.emplace(
110  std::piecewise_construct,
111  std::forward_as_tuple(oid),
112  std::forward_as_tuple(new T, deleter));
113 
114  /* emplace could fail only if there is already
115  * an element with the same key which is not
116  * possible */
117  assert(ret.second);
118 
119  it = ret.first;
120 
121  auto pop = pmemobj_pool_by_oid(oid);
122  auto *user_data =
123  static_cast<detail::pool_data *>(
124  pmemobj_get_user_data(pop));
125 
126  user_data->set_cleanup([oid] {
127  clear_from_pool(oid.pool_uuid_lo);
128  });
129  }
130 
131  return static_cast<T *>(it->second.get());
132  }
133  }
134 
135  static void
136  destroy(const PMEMoid &oid)
137  {
138  if (pmemobj_tx_stage() == TX_STAGE_WORK) {
140  obj::transaction::stage::oncommit, [oid] {
141  std::unique_lock<rwlock_type> lock(
142  get_rwlock());
143  get_map().erase(oid);
144  });
145  } else {
146  std::unique_lock<rwlock_type> lock(get_rwlock());
147  get_map().erase(oid);
148  }
149  }
150 
151 private:
152  struct pmemoid_hash {
153  std::size_t
154  operator()(const PMEMoid &oid) const
155  {
156  return oid.pool_uuid_lo + oid.off;
157  }
158  };
159 
160  struct pmemoid_equal_to {
161  bool
162  operator()(const PMEMoid &lhs, const PMEMoid &rhs) const
163  {
164  return lhs.pool_uuid_lo == rhs.pool_uuid_lo &&
165  lhs.off == rhs.off;
166  }
167  };
168 
169  using key_type = PMEMoid;
170  using value_type =
171  std::unique_ptr<void,
172  std::add_pointer<void(const void *)>::type>;
173 
174  using map_type = std::unordered_map<key_type, value_type, pmemoid_hash,
175  pmemoid_equal_to>;
176 
177  using rwlock_type = std::shared_timed_mutex;
178 
179  static void
180  clear_from_pool(uint64_t pool_id)
181  {
182  std::unique_lock<rwlock_type> lock(get_rwlock());
183  auto &map = get_map();
184 
185  for (auto it = map.begin(); it != map.end();) {
186  if (it->first.pool_uuid_lo == pool_id)
187  it = map.erase(it);
188  else
189  ++it;
190  }
191  }
192 
193  static map_type &
194  get_map()
195  {
196  static map_type map;
197  return map;
198  }
199 
200  static rwlock_type &
201  get_rwlock()
202  {
203  static rwlock_type rwlock;
204  return rwlock;
205  }
206 };
207 
208 } /* namespace detail */
209 
210 } /* namespace pmem */
211 
212 #endif /* LIBPMEMOBJ_CPP_VOLATILE_STATE_HPP */
pmem::obj::transaction::register_callback
static void register_callback(stage stg, std::function< void()> cb)
Registers callback to be called on specified stage for the transaction.
Definition: transaction.hpp:557
pmem
Persistent memory namespace.
Definition: allocation_flag.hpp:44
common.hpp
Commonly used functionality.
pool.hpp
C++ pmemobj pool.
transaction.hpp
C++ pmemobj transactions.
life.hpp
Functions for destroying arrays.
pmem::detail::volatile_state
Global key value store which allows persistent objects to use volatile memory.
Definition: volatile_state.hpp:67
pmem::transaction_scope_error
Custom transaction error class.
Definition: pexceptions.hpp:192