PMDK C++ bindings  1.10.1
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-2020, Intel Corporation */
3 
11 #ifndef LIBPMEMOBJ_CPP_MAKE_PERSISTENT_ARRAY_HPP
12 #define LIBPMEMOBJ_CPP_MAKE_PERSISTENT_ARRAY_HPP
13 
21 #include <libpmemobj/tx_base.h>
22 
23 #include <cassert>
24 #include <limits>
25 
26 namespace pmem
27 {
28 
29 namespace obj
30 {
31 
48 template <typename T>
49 typename detail::pp_if_array<T>::type
51 {
52  typedef typename detail::pp_array_type<T>::type I;
53 
54  /*
55  * Allowing N greater than ptrdiff_t max value would cause problems
56  * with accessing array and calculating address difference between two
57  * elements placed further apart than ptrdiff_t max value
58  */
59  assert(N <=
60  static_cast<std::size_t>(std::numeric_limits<ptrdiff_t>::max()));
61 
62  if (pmemobj_tx_stage() != TX_STAGE_WORK)
64  "refusing to allocate memory outside of transaction scope");
65 
66  persistent_ptr<T> ptr = pmemobj_tx_xalloc(
67  sizeof(I) * N, detail::type_num<I>(), flag.value);
68 
69  if (ptr == nullptr) {
70  if (errno == ENOMEM)
72  "Failed to allocate persistent memory array")
73  .with_pmemobj_errormsg();
74  else
76  "Failed to allocate persistent memory array")
77  .with_pmemobj_errormsg();
78  }
79 
80  /*
81  * cache raw pointer to data - using persistent_ptr.get() in a loop
82  * is expensive.
83  */
84  auto data = ptr.get();
85 
86  /*
87  * When an exception is thrown from one of the constructors
88  * we don't perform any cleanup - i.e. we don't call destructors
89  * (unlike new[] operator), we only rely on transaction abort.
90  * This approach was taken to ensure consistent behaviour for
91  * case when transaction is aborted after make_persistent completes and
92  * we have no way to call destructors.
93  */
94  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
95  detail::create<I>(data + i);
96 
97  return ptr;
98 }
99 
115 template <typename T>
116 typename detail::pp_if_size_array<T>::type
118 {
119  typedef typename detail::pp_array_type<T>::type I;
120  enum { N = detail::pp_array_elems<T>::elems };
121 
122  if (pmemobj_tx_stage() != TX_STAGE_WORK)
124  "refusing to allocate memory outside of transaction scope");
125 
126  persistent_ptr<T> ptr = pmemobj_tx_xalloc(
127  sizeof(I) * N, detail::type_num<I>(), flag.value);
128 
129  if (ptr == nullptr) {
130  if (errno == ENOMEM)
132  "Failed to allocate persistent memory array")
133  .with_pmemobj_errormsg();
134  else
136  "Failed to allocate persistent memory array")
137  .with_pmemobj_errormsg();
138  }
139 
140  /*
141  * cache raw pointer to data - using persistent_ptr.get() in a loop
142  * is expensive.
143  */
144  auto data = ptr.get();
145 
146  /*
147  * When an exception is thrown from one of the constructors
148  * we don't perform any cleanup - i.e. we don't call destructors
149  * (unlike new[] operator), we only rely on transaction abort.
150  * This approach was taken to ensure consistent behaviour for
151  * case when transaction is aborted after make_persistent completes and
152  * we have no way to call destructors.
153  */
154  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
155  detail::create<I>(data + i);
156 
157  return ptr;
158 }
159 
178 template <typename T>
179 void
180 delete_persistent(typename detail::pp_if_array<T>::type ptr, std::size_t N)
181 {
182  typedef typename detail::pp_array_type<T>::type I;
183 
184  if (pmemobj_tx_stage() != TX_STAGE_WORK)
186  "refusing to free memory outside of transaction scope");
187 
188  if (ptr == nullptr)
189  return;
190 
191  /*
192  * cache raw pointer to data - using persistent_ptr.get() in a loop
193  * is expensive.
194  */
195  auto data = ptr.get();
196 
197  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
198  detail::destroy<I>(
199  data[static_cast<std::ptrdiff_t>(N) - 1 - i]);
200 
201  if (pmemobj_tx_free(*ptr.raw_ptr()) != 0)
203  "failed to delete persistent memory object")
204  .with_pmemobj_errormsg();
205 }
206 
224 template <typename T>
225 void
226 delete_persistent(typename detail::pp_if_size_array<T>::type ptr)
227 {
228  typedef typename detail::pp_array_type<T>::type I;
229  enum { N = detail::pp_array_elems<T>::elems };
230 
231  if (pmemobj_tx_stage() != TX_STAGE_WORK)
233  "refusing to free memory outside of transaction scope");
234 
235  if (ptr == nullptr)
236  return;
237 
238  /*
239  * cache raw pointer to data - using persistent_ptr.get() in a loop
240  * is expensive.
241  */
242  auto data = ptr.get();
243 
244  for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(N); ++i)
245  detail::destroy<I>(
246  data[static_cast<std::ptrdiff_t>(N) - 1 - i]);
247 
248  if (pmemobj_tx_free(*ptr.raw_ptr()) != 0)
250  "failed to delete persistent memory object")
251  .with_pmemobj_errormsg();
252 }
253 
254 } /* namespace obj */
255 
256 } /* namespace pmem */
257 
258 #endif /* LIBPMEMOBJ_CPP_MAKE_PERSISTENT_ARRAY_HPP */
pmem::obj::persistent_ptr::get
element_type * get() const noexcept
Get the direct pointer.
Definition: persistent_ptr.hpp:509
pmem::transaction_free_error
Custom transaction error class.
Definition: pexceptions.hpp:145
pmem
Persistent memory namespace.
Definition: allocation_flag.hpp:15
pmem::transaction_out_of_memory
Custom out of memory error class.
Definition: pexceptions.hpp:125
common.hpp
Commonly used functionality.
pexceptions.hpp
Custom exceptions.
check_persistent_ptr_array.hpp
Compile time type check for make_persistent.
pmem::obj::delete_persistent
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:119
pmem::obj::persistent_ptr
Persistent pointer class.
Definition: persistent_ptr.hpp:183
pmem::obj::allocation_flag::none
static allocation_flag none()
Do not change allocator behaviour.
Definition: allocation_flag.hpp:61
array_traits.hpp
Common array traits.
life.hpp
Functions for destroying arrays.
pmem::obj::allocation_flag
Type of flag which can be passed to make_persistent.
Definition: allocation_flag.hpp:31
pmem::transaction_scope_error
Custom transaction error class.
Definition: pexceptions.hpp:163
variadic.hpp
Helper functionality for handling variadic templates.
allocation_flag.hpp
allocation_flag - defines flags which can be passed to make_persistent
pmem::obj::make_persistent
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:50
pmem::transaction_alloc_error
Custom transaction error class.
Definition: pexceptions.hpp:103