pstore2
storage.hpp
1 //===- include/pstore/core/storage.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 //===----------------------------------------------------------------------===//
17 
18 #ifndef PSTORE_CORE_STORAGE_HPP
19 #define PSTORE_CORE_STORAGE_HPP
20 
21 #include "pstore/core/address.hpp"
22 #include "pstore/core/region.hpp"
25 
26 namespace pstore {
27 
29  struct sat_entry {
33  std::shared_ptr<void> value;
34 
36  region::memory_mapper_ptr region;
37 
38 #ifndef NDEBUG
39  bool is_valid () const noexcept {
40  if (value == nullptr && region == nullptr) {
41  return true;
42  }
43 
44  auto * const ptr = static_cast<std::uint8_t const *> (value.get ());
45  auto * const region_base = static_cast<std::uint8_t const *> (region->data ().get ());
46  auto * const region_end = region_base + region->size ();
47  return ptr >= region_base && ptr + address::segment_size <= region_end;
48  }
49 #endif
50  };
51 
53  static auto constexpr sat_elements = address::max_segment + 1U;
54  using segment_address_table = std::array<sat_entry, sat_elements>;
55  using sat_iterator = segment_address_table::iterator;
56  using file_ptr = std::shared_ptr<file::file_base>;
57 
58  class storage {
59  public:
60  static auto constexpr full_region_size = UINT64_C (1) << 32U; // 4 Gigabytes
61  static auto constexpr min_region_size = UINT64_C (1) << 22U; // 4 Megabytes
62  // Check that full_region_size is a multiple of min_region_size
63  PSTORE_STATIC_ASSERT (full_region_size % min_region_size == 0);
64 
65  using region_container = std::vector<region::memory_mapper_ptr>;
66 
67  template <typename File>
68  storage (std::shared_ptr<File> const & file,
69  std::unique_ptr<system_page_size_interface> && page_size,
70  std::unique_ptr<region::factory> && region_factory)
71  : file_{std::static_pointer_cast<file::file_base> (file)}
72  , page_size_{std::move (page_size)}
73  , region_factory_{std::move (region_factory)}
74  , regions_{region_factory_->init ()} {}
75 
76  template <typename File>
77  explicit storage (std::shared_ptr<File> const & file)
78  : file_{std::static_pointer_cast<file::file_base> (file)}
79  , region_factory_{region::get_factory (
80  std::static_pointer_cast<file::file_handle> (file), full_region_size,
81  min_region_size)}
82  , regions_{region_factory_->init ()} {}
83 
84  file::file_base * file () noexcept { return file_.get (); }
85  file::file_base const * file () const noexcept { return file_.get (); }
86 
87  void map_bytes (std::uint64_t new_size);
88 
91  void update_master_pointers (std::size_t old_length);
92 
94  using in_store_pointer = std::uint8_t const *;
95  using temp_pointer = std::uint8_t *;
96  };
98  using in_store_pointer = std::uint8_t *;
99  using temp_pointer = std::uint8_t const *;
100  };
101 
122  template <typename Traits, typename Function>
123  void copy (address addr, std::size_t size, typename Traits::temp_pointer p,
124  Function copier) const;
125 
136  bool request_spans_regions (address const & addr, std::size_t size) const noexcept;
137 
139  void protect (address first, address last);
140 
145  std::shared_ptr<void const>
146  segment_base (address::segment_type const segment) const noexcept {
147  return segment_base_impl (*this, segment);
148  }
149  std::shared_ptr<void> const & segment_base (address::segment_type const segment) noexcept {
150  return segment_base_impl (*this, segment);
151  }
153 
155  std::shared_ptr<void const> address_to_pointer (address const addr) const noexcept {
156  return address_to_pointer_impl (*this, addr);
157  }
158  std::shared_ptr<void> address_to_pointer (address const addr) noexcept {
159  return address_to_pointer_impl (*this, addr);
160  }
161 
162  template <typename T>
163  std::shared_ptr<T const> address_to_pointer (typed_address<T> addr) const noexcept {
164  return std::static_pointer_cast<T const> (address_to_pointer (addr.to_address ()));
165  }
166  template <typename T>
167  std::shared_ptr<T> address_to_pointer (typed_address<T> addr) noexcept {
168  return std::static_pointer_cast<T> (address_to_pointer (addr.to_address ()));
169  }
171 
172 
173  // For unit testing only.
174  region_container const & regions () const { return regions_; }
175 
176  private:
177  void shrink (std::uint64_t new_size);
178 
179  static sat_iterator
180  slice_region_into_segments (std::shared_ptr<memory_mapper_base> const & region,
181  sat_iterator segment_it, sat_iterator segment_end);
182 
183  template <typename Storage,
184  typename ResultType = typename inherit_const<
185  Storage, std::shared_ptr<void> const &, std::shared_ptr<void const>>::type>
186  static auto segment_base_impl (Storage & storage,
187  address::segment_type const segment) noexcept -> ResultType;
188 
189  template <typename Storage,
190  typename ResultType = typename inherit_const<Storage, std::shared_ptr<void>,
191  std::shared_ptr<void const>>::type>
192  static auto address_to_pointer_impl (Storage & storage, address const addr) noexcept
193  -> ResultType;
194 
197  std::unique_ptr<segment_address_table> sat_ = std::make_unique<segment_address_table> ();
198 
200  file_ptr file_;
201  std::unique_ptr<system_page_size_interface> page_size_ =
202  std::make_unique<system_page_size> ();
203  std::unique_ptr<region::factory> region_factory_;
204  region_container regions_;
205  };
206 
207  // segment_base
208  // ~~~~~~~~~~~~
209  template <typename Storage, typename ResultType>
210  inline auto storage::segment_base_impl (Storage & storage,
211  address::segment_type const segment) noexcept
212  -> ResultType {
213  PSTORE_ASSERT (segment < storage.sat_->size ());
214  auto & e = (*storage.sat_)[segment];
215  PSTORE_ASSERT (e.is_valid ());
216  return e.value;
217  }
218 
219  // address_to_pointer
220  // ~~~~~~~~~~~~~~~~~~
221  template <typename Storage, typename ResultType>
222  inline auto storage::address_to_pointer_impl (Storage & storage, address const addr) noexcept
223  -> ResultType {
224  auto segment_base = storage.segment_base (addr.segment ());
225  using uint8_type = typename inherit_const<Storage, std::uint8_t>::type;
226  return {segment_base,
227  std::static_pointer_cast<uint8_type> (segment_base).get () + addr.offset ()};
228  }
229 
230  // request_spans_regions
231  // ~~~~~~~~~~~~~~~~~~~~~
232  inline bool storage::request_spans_regions (address const & addr, std::size_t const size) const
233  noexcept {
234  (void) addr;
235  if (size == 0) {
236  return false;
237  }
238 #ifdef PSTORE_ALWAYS_SPANNING
239  return true;
240 #else
241  return (*sat_)[addr.segment ()].region != (*sat_)[(addr + size - 1U).segment ()].region;
242 #endif // PSTORE_ALWAYS_SPANNING
243  }
244 
245  // copy
246  // ~~~~
247  template <typename Traits, typename Function>
248  void storage::copy (address const addr, std::size_t size, typename Traits::temp_pointer p,
249  Function copier) const {
250 
251  PSTORE_STATIC_ASSERT (std::numeric_limits<std::size_t>::max () <=
252  std::numeric_limits<std::uint64_t>::max ());
253  address::segment_type segment = addr.segment ();
254  PSTORE_STATIC_ASSERT (std::numeric_limits<decltype (segment)>::max () <= sat_elements);
255  sat_entry const & segment_pointer = (*sat_)[segment];
256  PSTORE_ASSERT (segment_pointer.value != nullptr && segment_pointer.region != nullptr &&
257  segment_pointer.is_valid ());
258 
259  auto in_store_ptr =
260  static_cast<typename Traits::in_store_pointer> (segment_pointer.value.get ()) +
261  addr.offset ();
262  auto region_base =
263  static_cast<typename Traits::in_store_pointer> (segment_pointer.region->data ().get ());
264  PSTORE_ASSERT (in_store_ptr >= region_base &&
265  in_store_ptr <= region_base + segment_pointer.region->size ());
266 
267  std::uint64_t copy_size = segment_pointer.region->size () -
268  static_cast<std::uintptr_t> (in_store_ptr - region_base);
269  static_assert (std::numeric_limits<std::size_t>::max () <=
270  std::numeric_limits<std::uint64_t>::max (),
271  "size_t must not be larger than uint64!");
272  copy_size = std::min (copy_size, std::uint64_t{size});
273 
274  // An initial copy for the tail of the first of the regions covered by the addr..addr+size
275  // range.
276  copier (in_store_ptr, p, copy_size);
277 
278  // Now copy the subsequent region(s).
279  for (p += copy_size, size -= copy_size; size > 0; p += copy_size, size -= copy_size) {
280 
281  // We copied all of the necessary data to the previous region. Now move to the next
282  // region and do the same.
283  std::uint64_t const inc =
284  (copy_size + address::segment_size - 1) / address::segment_size;
285  PSTORE_ASSERT (inc < std::numeric_limits<address::segment_type>::max ());
286  PSTORE_ASSERT (segment + inc < sat_elements);
287  segment += static_cast<address::segment_type> (inc);
288 
289  region::memory_mapper_ptr const & region = (*sat_)[segment].region;
290  PSTORE_ASSERT (region != nullptr);
291 
292  copy_size = std::min (static_cast<std::uint64_t> (size), region->size ());
293  in_store_ptr = static_cast<typename Traits::in_store_pointer> (region->data ().get ());
294  copier (in_store_ptr, p, copy_size);
295  }
296  }
297 
298 } // namespace pstore
299 
300 #endif // PSTORE_CORE_STORAGE_HPP
std::shared_ptr< void > value
A pointer to the data belonging to the segment represented by this entry in the segment address table...
Definition: storage.hpp:33
Definition: storage.hpp:97
std::shared_ptr< void const > segment_base(address::segment_type const segment) const noexcept
Definition: storage.hpp:146
Definition: address.hpp:81
static constexpr segment_type const max_segment
The largest legal segment value.
Definition: address.hpp:96
An entry in the segment address table.
Definition: storage.hpp:29
Definition: address.hpp:231
Definition: storage.hpp:93
void copy(address addr, std::size_t size, typename Traits::temp_pointer p, Function copier) const
This function performs the bulk of the work of creating a "shadow" block when a request spans more th...
Definition: storage.hpp:248
region::memory_mapper_ptr region
The memory-mapped region to which the &#39;value&#39; pointer belongs.
Definition: storage.hpp:36
Definition: storage.hpp:58
Definition: nonpod2.cpp:40
Provides a member typedef inherit_const::type, which is defined as R const if T is a const type and R...
Definition: inherit_const.hpp:108
An implementation of the standard assert() macro with the exception that it will, on failure...
bool request_spans_regions(address const &addr, std::size_t size) const noexcept
Returns true if the given address range "spans" more than one region.
Definition: storage.hpp:232
static constexpr value_type const segment_size
The number of bytes in a segment.
Definition: address.hpp:98
typename std::conditional< std::is_const< typename std::remove_reference< T >::type >::value, RC, R >::type type
If T is const, R const otherwise R.
Definition: inherit_const.hpp:112
An abstract file class. Provides the interface for file access.
Definition: file.hpp:176
Functions for aligning values and pointers.