pstore2
region.hpp
Go to the documentation of this file.
1 //===- include/pstore/core/region.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_REGION_HPP
19 #define PSTORE_CORE_REGION_HPP
20 
22 
23 namespace pstore {
24  namespace region {
25 
26  constexpr std::uint64_t round_up (std::uint64_t const x, std::uint64_t const y) noexcept {
27  return (x + y - 1) / y * y;
28  }
29 
30  using memory_mapper_ptr = std::shared_ptr<memory_mapper_base>;
31 
32 
33  //* _ _ _ _ _ *
34  //* _ __ ___ __ _(_) ___ _ __ | |__ _ _(_) | __| | ___ _ __ *
35  //* | '__/ _ \/ _` | |/ _ \| '_ \ | '_ \| | | | | |/ _` |/ _ \ '__| *
36  //* | | | __/ (_| | | (_) | | | | | |_) | |_| | | | (_| | __/ | *
37  //* |_| \___|\__, |_|\___/|_| |_| |_.__/ \__,_|_|_|\__,_|\___|_| *
38  //* |___/ *
39 
47 
48  template <typename File, typename MemoryMapper>
49  struct region_builder {
50  public:
51  using container_type = std::vector<pstore::region::memory_mapper_ptr>;
52 
57  region_builder (std::shared_ptr<File> file, std::uint64_t full_size,
58  std::uint64_t minimum_size) noexcept;
59  // No assignment or copying.
60  region_builder (region_builder const &) = delete;
61  region_builder (region_builder &&) noexcept = delete;
62 
63  ~region_builder () noexcept = default;
64 
65  // No assignment or copying.
66  region_builder & operator= (region_builder const &) = delete;
67  region_builder & operator= (region_builder &&) = delete;
68 
71  auto operator() (std::uint64_t bytes_to_map) -> container_type;
72 
84  void append (gsl::not_null<container_type *> regions, std::uint64_t offset,
85  std::uint64_t bytes_to_map);
86 
87  private:
88  void push (gsl::not_null<container_type *> regions, std::uint64_t file_size,
89  std::uint64_t offset, std::uint64_t size);
90 
93  void check_regions_are_contiguous (container_type const & regions);
94 
97  std::shared_ptr<File> file_;
98 
100  std::uint64_t const full_size_;
102  std::uint64_t const minimum_size_;
103  };
104 
105  // region_builder
106  // ~~~~~~~~~~~~~~
107  template <typename File, typename MemoryMapper>
109  std::shared_ptr<File> file, std::uint64_t const full_size,
110  std::uint64_t const minimum_size) noexcept
111  : file_ (file)
112  , full_size_ (full_size)
113  , minimum_size_ (minimum_size) {
114 
115  PSTORE_ASSERT (full_size >= minimum_size && full_size_ % minimum_size_ == 0);
116  }
117 
118  // append
119  // ~~~~~~
120  template <typename File, typename MemoryMapper>
122  std::uint64_t offset,
123  std::uint64_t bytes_to_map) {
124  PSTORE_ASSERT (regions != nullptr);
125  PSTORE_ASSERT (offset % minimum_size_ == 0);
126  bytes_to_map = round_up (bytes_to_map, minimum_size_);
127  PSTORE_ASSERT (bytes_to_map % minimum_size_ == 0);
128 
129  // Zero or more regions whose size is a multiple of minimum-size but no
130  // more than full-size.
131  while (bytes_to_map > 0) {
132  // Map no more than "full size" in one go.
133  std::uint64_t const size = std::min (full_size_, bytes_to_map);
134 
135  bytes_to_map -= size;
136  this->push (regions, bytes_to_map,
137  offset, // start of region
138  size); // size of region
139  offset += full_size_;
140  }
141  this->check_regions_are_contiguous (*regions);
142  }
143 
144  // operator()
145  // ~~~~~~~~~~
146  template <typename File, typename MemoryMapper>
147  auto region_builder<File, MemoryMapper>::operator() (std::uint64_t bytes_to_map)
148  -> container_type {
149  container_type regions;
150  this->append (&regions, 0 /*offset*/, bytes_to_map);
151  return regions;
152  }
153 
154  // push
155  // ~~~~
156  template <typename File, typename MemoryMapper>
157  void
159  std::uint64_t const /*file_size*/,
160  std::uint64_t offset, std::uint64_t size) {
161  PSTORE_ASSERT (regions != nullptr);
162  PSTORE_ASSERT (size >= minimum_size_);
163  // (Note that we separately make pages read-only to guard against writing to committed
164  // transactions: that's done by database::protect() rather than here.)
165  regions->push_back (
166  std::make_shared<MemoryMapper> (*file_, file_->is_writable (), offset, size));
167  }
168 
169  // check_regions_are_contiguous
170  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171  template <typename File, typename MemoryMapper>
173  container_type const & regions) {
174 #ifdef NDEBUG
175  (void) regions;
176 #else
177  // Check that the regions are contiguous and sorted.
178  std::uint64_t p = 0;
179  for (pstore::region::memory_mapper_ptr const & region : regions) {
180  PSTORE_ASSERT (region->offset () == p);
181  p += region->size ();
182  }
183 #endif
184  }
185 
186 
187  // small_files_enabled
188  // ~~~~~~~~~~~~~~~~~~~
189  constexpr bool small_files_enabled () noexcept {
190 #ifdef PSTORE_POSIX_SMALL_FILES
191  return true;
192 #else
193  return false;
194 #endif
195  }
196 
197 
198  /* __ _ *
199  * / _| __ _ ___| |_ ___ _ __ _ _ *
200  * | |_ / _` |/ __| __/ _ \| '__| | | | *
201  * | _| (_| | (__| || (_) | | | |_| | *
202  * |_| \__,_|\___|\__\___/|_| \__, | *
203  * |___/ *
204  */
205  class factory {
206  public:
207  virtual ~factory () noexcept;
208 
218  virtual std::vector<memory_mapper_ptr> init () = 0;
219 
220  virtual void add (gsl::not_null<std::vector<memory_mapper_ptr> *> regions,
221  std::uint64_t original_size, std::uint64_t new_size) = 0;
222 
223  virtual std::shared_ptr<file::file_base> file () = 0;
224 
225  std::uint64_t full_size () const noexcept { return full_size_; }
226  std::uint64_t min_size () const noexcept { return min_size_; }
227 
228  protected:
232  constexpr factory (std::uint64_t const full_size, std::uint64_t const min_size) noexcept
233  : full_size_{full_size}
234  , min_size_{min_size} {
235  PSTORE_ASSERT (full_size_ % min_size_ == 0);
236  }
237 
238  template <typename File, typename MemoryMapper>
239  auto create (std::shared_ptr<File> file) -> std::vector<memory_mapper_ptr>;
240 
241  template <typename File, typename MemoryMapper>
242  void append (std::shared_ptr<File> file,
243  gsl::not_null<std::vector<memory_mapper_ptr> *> regions,
244  std::uint64_t original_size, std::uint64_t new_size);
245 
246  private:
247  std::uint64_t const full_size_;
248  std::uint64_t const min_size_;
249  };
250 
251  // create
252  // ~~~~~~
253  template <typename File, typename MemoryMapper>
254  auto factory::create (std::shared_ptr<File> file) -> std::vector<memory_mapper_ptr> {
255 
256  // There's no lock on the file when we call the size() method here. However, the file
257  // is only allowed to grow so if it changes then the worst outcome is that we end up
258  // memory mapping more of it beyond the logical size.
259 
260  std::uint64_t const file_size = file->size ();
261  region_builder<File, MemoryMapper> builder (file, this->full_size (),
262  this->min_size ());
263  return builder (file_size);
264  }
265 
266  // append
267  // ~~~~~~
268  template <typename File, typename MemoryMapper>
269  void factory::append (std::shared_ptr<File> file,
270  gsl::not_null<std::vector<memory_mapper_ptr> *> regions,
271  std::uint64_t original_size, std::uint64_t new_size) {
272 
273  PSTORE_ASSERT (new_size >= original_size);
274 
275  auto const min_size = this->min_size ();
276  region_builder<File, MemoryMapper> builder (file, this->full_size (), min_size);
277 
278  new_size = round_up (new_size, min_size);
279  if (!small_files_enabled ()) {
280  file->truncate (new_size);
281  }
282  builder.append (regions, original_size, new_size - original_size);
283  }
284 
285 
286  //* __ _ _ _ _ __ _ *
287  //* / _(_) |___ | |__ __ _ ___ ___ __| | / _|__ _ __| |_ ___ _ _ _ _ *
288  //* | _| | / -_) | '_ \/ _` (_-</ -_) _` | | _/ _` / _| _/ _ \ '_| || | *
289  //* |_| |_|_\___| |_.__/\__,_/__/\___\__,_| |_| \__,_\__|\__\___/_| \_, | *
290  //* |__/ *
291  class file_based_factory final : public factory {
292  public:
296  explicit file_based_factory (std::shared_ptr<file::file_handle> file,
297  std::uint64_t full_size, std::uint64_t min_size);
298 
299  std::vector<memory_mapper_ptr> init () override;
300  void add (gsl::not_null<std::vector<memory_mapper_ptr> *> regions,
301  std::uint64_t original_size, std::uint64_t new_size) override;
302 
303  std::shared_ptr<file::file_base> file () override;
304 
305  private:
306  std::shared_ptr<file::file_handle> file_;
307  };
308 
309 
310  //* _ _ __ _ *
311  //* _ __ ___ _ __ | |__ __ _ ___ ___ __| | / _|__ _ __| |_ ___ _ _ _ _ *
312  //* | ' \/ -_) ' \ | '_ \/ _` (_-</ -_) _` | | _/ _` / _| _/ _ \ '_| || | *
313  //* |_|_|_\___|_|_|_| |_.__/\__,_/__/\___\__,_| |_| \__,_\__|\__\___/_| \_, | *
314  //* |__/ *
315  class mem_based_factory final : public factory {
316  public:
320  explicit mem_based_factory (std::shared_ptr<file::in_memory> file,
321  std::uint64_t full_size, std::uint64_t min_size);
322 
323  std::vector<memory_mapper_ptr> init () override;
324  void add (gsl::not_null<std::vector<memory_mapper_ptr> *> regions,
325  std::uint64_t original_size, std::uint64_t new_size) override;
326 
327  std::shared_ptr<file::file_base> file () override;
328 
329  private:
330  std::shared_ptr<file::in_memory> file_;
331  };
332 
333 
334  std::unique_ptr<factory> get_factory (std::shared_ptr<file::file_handle> const & file,
335  std::uint64_t full_size, std::uint64_t min_size);
336 
337  std::unique_ptr<factory> get_factory (std::shared_ptr<file::in_memory> const & file,
338  std::uint64_t full_size, std::uint64_t min_size);
339  } // end namespace region
340 } // end namespace pstore
341 #endif // PSTORE_CORE_REGION_HPP
Provides a portable interface for memory mapping portions of a file or for treating regions of memory...
void append(gsl::not_null< container_type *> regions, std::uint64_t offset, std::uint64_t bytes_to_map)
Creates one of more additional memory-mapped regions covering the file starting at the position given...
Definition: region.hpp:121
auto operator()(std::uint64_t bytes_to_map) -> container_type
Definition: region.hpp:147
Definition: gsl.hpp:589
Definition: region.hpp:205
Definition: region.hpp:315
region_builder(std::shared_ptr< File > file, std::uint64_t full_size, std::uint64_t minimum_size) noexcept
Definition: region.hpp:108
A class which is responsible for creating the memory-mapped regions used by the data store...
Definition: region.hpp:49
Definition: nonpod2.cpp:40
Definition: region.hpp:291
constexpr factory(std::uint64_t const full_size, std::uint64_t const min_size) noexcept
Definition: region.hpp:232