pstore2
transaction.hpp
Go to the documentation of this file.
1 //===- include/pstore/core/transaction.hpp ----------------*- mode: C++ -*-===//
2 //* _ _ _ *
3 //* | |_ _ __ __ _ _ __ ___ __ _ ___| |_(_) ___ _ __ *
4 //* | __| '__/ _` | '_ \/ __|/ _` |/ __| __| |/ _ \| '_ \ *
5 //* | |_| | | (_| | | | \__ \ (_| | (__| |_| | (_) | | | | *
6 //* \__|_| \__,_|_| |_|___/\__,_|\___|\__|_|\___/|_| |_| *
7 //* *
8 //===----------------------------------------------------------------------===//
9 //
10 // Part of the pstore project, under the Apache License v2.0 with LLVM Exceptions.
11 // See https://github.com/SNSystems/pstore/blob/master/LICENSE.txt for license
12 // information.
13 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
14 //
15 //===----------------------------------------------------------------------===//
18 
19 #ifndef PSTORE_CORE_TRANSACTION_HPP
20 #define PSTORE_CORE_TRANSACTION_HPP
21 
22 #include <mutex>
23 #include <type_traits>
24 
25 #include "pstore/core/address.hpp"
26 #include "pstore/core/database.hpp"
27 #include "pstore/core/time.hpp"
28 
29 namespace pstore {
42 
44  public:
45  virtual ~transaction_base () noexcept = default;
46 
47  transaction_base (transaction_base const &) = delete;
48  transaction_base (transaction_base && rhs) noexcept;
49 
50  transaction_base & operator= (transaction_base const &) = delete;
51  transaction_base & operator= (transaction_base && rhs) noexcept = delete;
52 
53  database & db () noexcept { return db_; }
54  database const & db () const noexcept { return db_; }
55 
58  bool is_open () const noexcept { return first_ != address::null (); }
59 
63 
65  transaction_base & rollback () noexcept;
66 
67 
69  std::shared_ptr<void const> getro (address const addr, std::size_t const size) {
70  PSTORE_ASSERT (addr >= first_ && addr + size <= first_ + size_);
71  return db ().getro (addr, size);
72  }
73 
74  template <typename T,
75  typename = typename std::enable_if<std::is_standard_layout<T>::value>::type>
76  std::shared_ptr<T const> getro (extent<T> const & ex) {
77  return this->getro (ex.addr, ex.size);
78  }
79 
80  template <typename T,
81  typename = typename std::enable_if<std::is_standard_layout<T>::value>::type>
82  std::shared_ptr<T const> getro (typed_address<T> const addr,
83  std::size_t const elements = 1) {
84  PSTORE_ASSERT (addr.to_address () >= first_ &&
85  (addr.to_address () + elements * sizeof (T)) <= first_ + size_);
86  return db_.getro (addr, elements);
87  }
89 
90 
92  std::shared_ptr<void> getrw (address const addr, std::size_t const size) {
93  PSTORE_ASSERT (addr >= first_ && addr + size <= first_ + size_);
94  return db_.getrw (addr, size);
95  }
96 
97  template <typename T,
98  typename = typename std::enable_if<std::is_standard_layout<T>::value>::type>
99  std::shared_ptr<T> getrw (extent<T> const & ex) {
100  return db_.getrw (ex);
101  }
102 
103  template <typename T,
104  typename = typename std::enable_if<std::is_standard_layout<T>::value>::type>
105  std::shared_ptr<T> getrw (typed_address<T> const addr, std::size_t const elements = 1) {
106  PSTORE_ASSERT (addr.to_address () >= first_ &&
107  (addr.to_address () + elements * sizeof (T)) <= first_ + size_);
108  return db_.getrw (addr, elements);
109  }
111 
120  virtual address allocate (std::uint64_t size, unsigned align);
121 
126  template <typename Ty>
128  return this->allocate (sizeof (Ty), alignof (Ty));
129  }
131 
133 
145  std::pair<std::shared_ptr<void>, address> alloc_rw (std::size_t size, unsigned align);
146 
156  template <typename Ty,
157  typename = typename std::enable_if<std::is_standard_layout<Ty>::value>::type>
158  auto alloc_rw (std::size_t const num = 1)
159  -> std::pair<std::shared_ptr<Ty>, typed_address<Ty>> {
160  auto result = this->alloc_rw (sizeof (Ty) * num, alignof (Ty));
161  return {std::static_pointer_cast<Ty> (result.first), typed_address<Ty> (result.second)};
162  }
164 
166  std::uint64_t size () const noexcept { return size_; }
167 
168  protected:
169  explicit transaction_base (database & db);
170 
171  private:
172  database & db_;
174  std::uint64_t size_ = 0;
175 
177  std::uint64_t dbsize_ = 0;
178 
181  address first_ = address::null ();
182  };
183 
184 
185  //* _ _ _ *
186  //* | |_ _ _ __ _ _ _ ___ __ _ __| |_(_)___ _ _ *
187  //* | _| '_/ _` | ' \(_-</ _` / _| _| / _ \ ' \ *
188  //* \__|_| \__,_|_||_/__/\__,_\__|\__|_\___/_||_| *
189  //* *
190  template <typename LockGuard>
191  class transaction : public transaction_base {
192  public:
193  using lock_type = LockGuard;
194 
195  transaction (database & db, lock_type && lock);
196  transaction (transaction const & rhs) = delete;
197  transaction (transaction && rhs) noexcept = default;
198 
199  ~transaction () noexcept override;
200 
201  transaction & operator= (transaction const & rhs) = delete;
202  transaction & operator= (transaction && rhs) noexcept = delete;
203 
204  private:
205  lock_type lock_;
206  };
207 
208  // (ctor)
209  // ~~~~~~
210  template <typename LockGuard>
211  transaction<LockGuard>::transaction (database & db, LockGuard && lock)
212  : transaction_base (db)
213  , lock_{std::move (lock)} {
214 
215  PSTORE_ASSERT (!this->is_open ());
216  }
217 
218  // (dtor)
219  // ~~~~~~
220  template <typename LockGuard>
222  static_assert (noexcept (rollback ()), "rollback must be noexcept");
223  this->rollback ();
224  }
225 
226  //* _ _ _ *
227  //* | |___ __| |__ __ _ _ _ __ _ _ _ __| | *
228  //* | / _ \/ _| / / / _` | || / _` | '_/ _` | *
229  //* |_\___/\__|_\_\ \__, |\_,_\__,_|_| \__,_| *
230  //* |___/ *
235  template <typename MutexType>
236  class lock_guard {
237  public:
238  explicit lock_guard (MutexType && mut)
239  : mut_{std::move (mut)} {
240  mut_.lock ();
241  owned_ = true;
242  }
243  lock_guard (lock_guard const & rhs) = delete;
244  lock_guard (lock_guard && rhs) noexcept
245  : mut_{std::move (rhs.mut_)}
246  , owned_{rhs.owned_} {
247  rhs.owned_ = false;
248  }
249 
250  ~lock_guard () {
251  if (owned_) {
252  mut_.unlock ();
253  owned_ = false;
254  }
255  }
256 
257  lock_guard & operator= (lock_guard const & rhs) = delete;
258  lock_guard & operator= (lock_guard && rhs) noexcept {
259  if (this != &rhs) {
260  mut_ = std::move (rhs.mut_);
261  owned_ = rhs.owned_;
262  rhs.owned_ = false;
263  }
264  return *this;
265  }
266 
267  private:
268  MutexType mut_;
269  bool owned_ = false;
270  };
271 
272 
273  //* _ _ _ _ *
274  //* | |_ _ _ __ _ _ _ ___ __ _ __| |_(_)___ _ _ _ __ _ _| |_ _____ __ *
275  //* | _| '_/ _` | ' \(_-</ _` / _| _| / _ \ ' \ | ' \ || | _/ -_) \ / *
276  //* \__|_| \__,_|_||_/__/\__,_\__|\__|_\___/_||_| |_|_|_\_,_|\__\___/_\_\ *
277  //* *
281  public:
282  explicit transaction_mutex (database & db)
283  : rl_{
284  db.file (), // file
285  sizeof (header) + offsetof (lock_block, transaction_lock), // offset
286  sizeof (lock_block::transaction_lock), // size
288  } {}
289 
290  transaction_mutex (transaction_mutex && rhs) noexcept = default;
291  transaction_mutex (transaction_mutex const & rhs) = delete;
292 
293  transaction_mutex & operator= (transaction_mutex const & rhs) = delete;
294  transaction_mutex & operator= (transaction_mutex && rhs) noexcept = default;
295 
296  void lock () { rl_.lock (); }
297  void unlock () { rl_.unlock (); }
298 
299  private:
300  file::range_lock rl_;
301  };
302 
304 
305 
312  return {db, std::move (lock)};
313  }
315  return {db, std::move (lock)};
316  }
318 
320 
321 } // namespace pstore
322 
323 #endif // PSTORE_CORE_TRANSACTION_HPP
bool is_open() const noexcept
Returns true if data has been added to this transaction, but not yet committed.
Definition: transaction.hpp:58
Specifies a write (or exclusive) lock.
lock_guard fills a similar role as a type such as std::scoped_lock<> in that it provides convenient R...
Definition: transaction.hpp:236
std::shared_ptr< void const > getro(address const addr, std::size_t const size) const
Definition: database.hpp:128
The lock-block is a small struct placed immediately after the file header which is used by the transa...
Definition: file_header.hpp:162
typed_address< T > addr
The address of the data associated with this extent.
Definition: address.hpp:456
An extent is a contiguous area of storage reserved for a data BLOB, represented as a range...
Definition: address.hpp:441
auto alloc_rw(std::size_t const num=1) -> std::pair< std::shared_ptr< Ty >, typed_address< Ty >>
Allocates sufficient space in the transaction for one or more new instances of type &#39;Ty&#39; and returns ...
Definition: transaction.hpp:158
Definition: address.hpp:81
file::file_base const * file() const
Returns the file in which this database is contained.
Definition: database.hpp:87
transaction< transaction_lock > begin(database &db, transaction_lock &lock)
Creates a new transaction. Every operation performed on a transaction instance can be potentially und...
Definition: transaction.hpp:311
std::pair< std::shared_ptr< void >, address > alloc_rw(std::size_t size, unsigned align)
Allocates sufficient space in the transaction for &#39;size&#39; bytes at an alignment given by &#39;align&#39; and r...
Definition: transaction.cpp:75
Definition: transaction.hpp:191
Definition: address.hpp:231
std::shared_ptr< void > getrw(address const addr, std::size_t const size)
Load a block of data starting at address addr and of size bytes.
Definition: database.hpp:189
A synchronization object that can be used to protect data in a file from being simultaneously accesse...
Definition: file.hpp:382
std::uint64_t size
The size of the data associated with this extent.
Definition: address.hpp:461
address allocate()
Extend the database store ensuring that there&#39;s enough room for an instance of the template type...
Definition: transaction.hpp:127
transaction_base & commit()
Commits all modifications made to the data store as part of this transaction.
Definition: transaction.cpp:89
transaction_base & rollback() noexcept
Discards all modifications made to the data store as part of this transaction.
Definition: transaction.cpp:147
Definition: nonpod2.cpp:40
std::uint64_t size() const noexcept
Returns the number of bytes allocated in this transaction.
Definition: transaction.hpp:166
Definition: database.hpp:40
A mutex which is used to protect a pstore file from being simultaneously written by multiple threads ...
Definition: transaction.hpp:280
The database transaction class.
Definition: transaction.hpp:43
The data store file header.
Definition: file_header.hpp:78