PMDK C++ bindings  1.13.0-git107.g7e59f08f
This is the C++ bindings documentation for PMDK's libpmemobj.
make_persistent_array.hpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright 2016-2021, Intel Corporation */
3 
12 #ifndef LIBPMEMOBJ_CPP_MAKE_PERSISTENT_ARRAY_HPP
13 #define LIBPMEMOBJ_CPP_MAKE_PERSISTENT_ARRAY_HPP
14 
22 #include <libpmemobj/tx_base.h>
23 
24 #include <cassert>
25 #include <limits>
26 
27 namespace pmem
28 {
29 
30 namespace obj
31 {
32 
52 template <typename T>
53 typename detail::pp_if_array<T>::type
55 {
56  typedef typename detail::pp_array_type<T>::type I;
57 
58  /*
59  * Allowing N greater than ptrdiff_t max value would cause problems
60  * with accessing array and calculating address difference between two
61  * elements placed further apart than ptrdiff_t max value
62  */
63  assert(N <=
64  static_cast<std::size_t>(std::numeric_limits<ptrdiff_t>::max()));
65 
66  if (pmemobj_tx_stage() != TX_STAGE_WORK)
68  "refusing to allocate memory outside of transaction scope");
69 
70  persistent_ptr<T> ptr = pmemobj_tx_xalloc(
71  sizeof(I) * N, detail::type_num<I>(), flag.value);
72 
73  if (ptr == nullptr) {
74  const char *msg = "Failed to allocate persistent memory array";
75  if (errno == ENOMEM)
78  else
81  }
82 
83  /*
84  * cache raw pointer to data - using persistent_ptr.get() in a loop
85  * is expensive.
86  */
87  auto data = ptr.get();
88 
89  /*
90  * When an exception is thrown from one of the constructors
91  * we don't perform any cleanup - i.e. we don't call destructors
92  * (unlike new[] operator), we only rely on transaction abort.
93  * This approach was taken to ensure consistent behaviour for
94  * case when transaction is aborted after make_persistent completes and
95  * we have no way to call destructors.
96  */
97  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
98  detail::create<I>(data + i);
99 
100  return ptr;
101 }
102 
121 template <typename T>
122 typename detail::pp_if_size_array<T>::type
124 {
125  typedef typename detail::pp_array_type<T>::type I;
126  enum { N = detail::pp_array_elems<T>::elems };
127 
128  if (pmemobj_tx_stage() != TX_STAGE_WORK)
130  "refusing to allocate memory outside of transaction scope");
131 
132  persistent_ptr<T> ptr = pmemobj_tx_xalloc(
133  sizeof(I) * N, detail::type_num<I>(), flag.value);
134 
135  if (ptr == nullptr) {
136  const char *msg = "Failed to allocate persistent memory array";
137  if (errno == ENOMEM)
140  else
143  }
144 
145  /*
146  * cache raw pointer to data - using persistent_ptr.get() in a loop
147  * is expensive.
148  */
149  auto data = ptr.get();
150 
151  /*
152  * When an exception is thrown from one of the constructors
153  * we don't perform any cleanup - i.e. we don't call destructors
154  * (unlike new[] operator), we only rely on transaction abort.
155  * This approach was taken to ensure consistent behaviour for
156  * case when transaction is aborted after make_persistent completes and
157  * we have no way to call destructors.
158  */
159  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
160  detail::create<I>(data + i);
161 
162  return ptr;
163 }
164 
184 template <typename T>
185 void
186 delete_persistent(typename detail::pp_if_array<T>::type ptr, std::size_t N)
187 {
188  typedef typename detail::pp_array_type<T>::type I;
189 
190  if (pmemobj_tx_stage() != TX_STAGE_WORK)
192  "refusing to free memory outside of transaction scope");
193 
194  if (ptr == nullptr)
195  return;
196 
197  /*
198  * cache raw pointer to data - using persistent_ptr.get() in a loop
199  * is expensive.
200  */
201  auto data = ptr.get();
202 
203  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
204  detail::destroy<I>(
205  data[static_cast<std::ptrdiff_t>(N) - 1 - i]);
206 
207  if (pmemobj_tx_free(*ptr.raw_ptr()) != 0)
210  "failed to delete persistent memory object");
211 }
212 
231 template <typename T>
232 void
233 delete_persistent(typename detail::pp_if_size_array<T>::type ptr)
234 {
235  typedef typename detail::pp_array_type<T>::type I;
236  enum { N = detail::pp_array_elems<T>::elems };
237 
238  if (pmemobj_tx_stage() != TX_STAGE_WORK)
240  "refusing to free memory outside of transaction scope");
241 
242  if (ptr == nullptr)
243  return;
244 
245  /*
246  * cache raw pointer to data - using persistent_ptr.get() in a loop
247  * is expensive.
248  */
249  auto data = ptr.get();
250 
251  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
252  detail::destroy<I>(
253  data[static_cast<std::ptrdiff_t>(N) - 1 - i]);
254 
255  if (pmemobj_tx_free(*ptr.raw_ptr()) != 0)
258  "failed to delete persistent memory object");
259 }
260 
261 } /* namespace obj */
262 
263 } /* namespace pmem */
264 
265 #endif /* LIBPMEMOBJ_CPP_MAKE_PERSISTENT_ARRAY_HPP */
allocation_flag - defines flags which can be passed to make_persistent
Common array traits.
Compile time type check for make_persistent.
Persistent pointer class.
Definition: persistent_ptr.hpp:153
element_type * get() const noexcept
Get the direct pointer.
Definition: persistent_ptr.hpp:479
Custom transaction error class.
Definition: pexceptions.hpp:132
Custom transaction error class.
Definition: pexceptions.hpp:156
Custom out of memory error class.
Definition: pexceptions.hpp:144
Custom transaction error class.
Definition: pexceptions.hpp:167
Commonly used functionality.
void delete_persistent(typename detail::pp_if_not_array< T >::type ptr)
Transactionally free an object of type T held in a persistent_ptr.
Definition: make_persistent.hpp:126
detail::pp_if_not_array< T >::type make_persistent(allocation_flag flag, Args &&... args)
Transactionally allocate and construct an object of type T.
Definition: make_persistent.hpp:54
Functions for lifetime management.
ExcT exception_with_errormsg(Args &&... args)
Generic error message decorator for pmemobj-based exceptions.
Definition: pexceptions.hpp:69
Persistent memory namespace.
Definition: allocation_flag.hpp:15
Custom pmem exceptions.
Type of flag which can be passed to make_persistent.
Definition: allocation_flag.hpp:31
static allocation_flag none()
Do not change allocator behaviour.
Definition: allocation_flag.hpp:61
Helper functionality for handling variadic templates.