TPIE

2362a60
serialized_store.h
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 // Copyright 2014 The TPIE development team
4 //
5 // This file is part of TPIE.
6 //
7 // TPIE is free software: you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation, either version 3 of the License, or (at your
10 // option) any later version.
11 //
12 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
19 
20 #ifndef _TPIE_BTREE_SERIALIZED_STORE_H_
21 #define _TPIE_BTREE_SERIALIZED_STORE_H_
22 
23 #include <tpie/portability.h>
24 #include <tpie/btree/base.h>
25 #include <tpie/tpie_assert.h>
26 #include <tpie/serialization2.h>
27 #include <cstddef>
28 #include <fstream>
29 
30 namespace tpie {
31 namespace bbits {
32 
41 template <typename T,
42  typename A,
43  std::size_t a_,
44  std::size_t b_,
45  std::size_t bs_
46  >
47 class serialized_store {
48 public:
52  typedef T value_type;
53 
57  typedef A augment_type;
58 
59 
60  typedef size_t size_type;
61 
62  typedef uint64_t off_t;
63 
64 
65  serialized_store(const serialized_store & o) = delete;
66  serialized_store & operator=(const serialized_store & o) = delete;
67  serialized_store(serialized_store && o) = default;
68 
69  serialized_store & operator=(serialized_store && o) {
70  this->~serialized_store();
71  new (this) serialized_store(o);
72  return this;
73  }
74 
75 private:
76  struct internal_content {
77  off_t offset;
78  A augment;
79 
80  static const bool is_trivially_serializable=true;
81  };
82 
83  static constexpr size_t block_size() {return bs_?bs_:24*1024;}
84  static constexpr size_t min_internal_size() {return 1;}
85  static constexpr size_t max_internal_size() {return a_ ? a_ : (block_size() - sizeof(off_t) - sizeof(size_t)) / sizeof(internal_content) ; }
86  static constexpr size_t min_leaf_size() {return 1;}
87  static constexpr size_t max_leaf_size() {return b_ ? b_ : (block_size() - sizeof(off_t) - sizeof(size_t)) / sizeof(T);}
88 
89  struct internal {
90  off_t my_offset; //NOTE not serialized
91  size_t count;
92  internal_content values[max_internal_size()];
93 
94  template <typename S>
95  friend void serialize(S & s, const internal & i) {
96  using tpie::serialize;
97  serialize(s, i.count);
98  serialize(s, i.values, i.values + i.count);
99  }
100 
101  template <typename D>
102  friend void unserialize(D & d, internal & i) {
103  using tpie::unserialize;
104  unserialize(d, i.count);
105  //tp_assert(i.count <= max_internal_size(), "too large internal");
106  unserialize(d, i.values, i.values + i.count);
107  }
108  };
109 
110  struct leaf {
111  off_t my_offset; //NOTE not serialized
112  size_t count;
113  T values[max_leaf_size()];
114 
115  template <typename S>
116  friend void serialize(S & s, const leaf & i) {
117  using tpie::serialize;
118  serialize(s, i.count);
119  serialize(s, i.values, i.values + i.count);
120  }
121 
122  template <typename D>
123  friend void unserialize(D & d, leaf & i) {
124  using tpie::unserialize;
125  unserialize(d, i.count);
126  //tp_assert(i.count <= max_leaf_size(), "too large leaf");
127  unserialize(d, i.values, i.values + i.count);
128  }
129  };
130 
131  struct header {
132  static constexpr uint64_t good_magic = 0x8bbd51bfe5e3d477, current_version = 0;
133  uint64_t magic;
134  uint64_t version; // 0
135  off_t root; // offset of root
136  size_t height; // tree height (internal and leaf levels)
137  size_t size; // number of items (from btree)
138  off_t metadata_offset;
139  off_t metadata_size;
140  };
141 
142  typedef std::shared_ptr<internal> internal_type;
143  typedef std::shared_ptr<leaf> leaf_type;
144 
148  explicit serialized_store(const std::string & path, bool write_only=false):
149  m_height(0), m_size(0), metadata_offset(0), metadata_size(0), path(path) {
150  f.reset(new std::fstream());
151  header h;
152  if (write_only) {
153  f->open(path, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary);
154  if (!f->is_open())
155  throw invalid_file_exception("Open failed");
156  memset(&h, 0, sizeof(h));
157  f->write(reinterpret_cast<char *>(&h), sizeof(h));
158  } else {
159  f->open(path, std::ios_base::in | std::ios_base::binary);
160  if (!f->is_open())
161  throw invalid_file_exception("Open failed");
162  f->read(reinterpret_cast<char *>(&h), sizeof(h));
163  if (!*f)
164  throw invalid_file_exception("Unable to read header");
165 
166  if (h.magic != header::good_magic)
167  throw invalid_file_exception("Bad magic");
168 
169  if (h.version != header::current_version)
170  throw invalid_file_exception("Bad version");
171 
172  m_height = h.height;
173  m_size = h.size;
174  metadata_offset = h.metadata_offset;
175  metadata_size = h.metadata_size;
176  if (m_height == 1) {
177  root_leaf = std::make_shared<leaf>();
178  root_leaf->my_offset = h.root;
179  f->seekg(h.root);
180  unserialize(*f, *root_leaf);
181  } else if (m_height > 1) {
182  root_internal = std::make_shared<internal>();
183  root_internal->my_offset = h.root;
184  f->seekg(h.root);
185  unserialize(*f, *root_internal);
186  }
187  }
188  }
189 
190 
191  void move(internal_type src, size_t src_i,
192  internal_type dst, size_t dst_i) {
193  dst->values[dst_i] = src->values[src_i];
194  }
195 
196  void move(leaf_type src, size_t src_i,
197  leaf_type dst, size_t dst_i) {
198  dst->values[dst_i] = src->values[src_i];
199  }
200 
201  void set(leaf_type dst, size_t dst_i, T c) {
202  assert(dst == current_leaf);
203  dst->values[dst_i] = c;
204  }
205 
206  void set(internal_type node, size_t i, internal_type c) {
207  assert(node == current_internal);
208  node->values[i].offset = c->my_offset;
209  }
210 
211  void set(internal_type node, size_t i, leaf_type c) {
212  assert(node == current_internal);
213  node->values[i].offset = c->my_offset;
214  }
215 
216  const T & get(leaf_type l, size_t i) const {
217  return l->values[i];
218  }
219 
220  size_t count(internal_type node) const {
221  return node->count;
222  }
223 
224  size_t count(leaf_type node) const {
225  return node->count;
226  }
227 
228  void set_count(internal_type node, size_t i) {
229  node->count = i;
230  }
231 
232  void set_count(leaf_type node, size_t i) {
233  node->count = i;
234  }
235 
236  leaf_type create_leaf() {
237  assert(!current_internal && !current_leaf);
238  current_leaf = std::make_shared<leaf>();
239  current_leaf->my_offset = (stream_size_type)f->tellp();
240  return current_leaf;
241  }
242  leaf_type create(leaf_type) {return create_leaf();}
243  internal_type create_internal() {
244  assert(!current_internal && !current_leaf);
245  current_internal = std::make_shared<internal>();
246  current_internal->my_offset = (stream_size_type)f->tellp();
247  return current_internal;
248  }
249  internal_type create(internal_type) {return create_internal();}
250 
251  void set_root(internal_type node) {root_internal = node;}
252  void set_root(leaf_type node) {root_leaf = node;}
253 
254  internal_type get_root_internal() const {
255  return root_internal;
256  }
257 
258  leaf_type get_root_leaf() const {
259  return root_leaf;
260  }
261 
262  internal_type get_child_internal(internal_type node, size_t i) const {
263  internal_type child = std::make_shared<internal>();
264  assert(i < node->count);
265  child->my_offset = node->values[i].offset;
266  f->seekg(child->my_offset);
267  unserialize(*f, *child);
268  return child;
269  }
270 
271  leaf_type get_child_leaf(internal_type node, size_t i) const {
272  leaf_type child = std::make_shared<leaf>();
273  assert(i < node->count);
274  child->my_offset = node->values[i].offset;
275  f->seekg(child->my_offset);
276  unserialize(*f, *child);
277  return child;
278  }
279 
280  size_t index(off_t my_offset, internal_type node) const {
281  for (size_t i=0; i < node->count; ++i)
282  if (node->values[i].offset == my_offset) return i;
283  tp_assert(false, "Not found");
284  tpie_unreachable();
285  }
286 
287  size_t index(leaf_type l, internal_type node) const {
288  return index(l->my_offset, node);
289  }
290 
291  size_t index(internal_type i, internal_type node) const {
292  return index(i->my_offset, node);
293  }
294 
295  void set_augment(leaf_type l, internal_type p, augment_type ag) {
296  size_t idx = index(l->my_offset, p);
297  p->values[idx].augment = ag;
298  }
299 
300  void set_augment(internal_type i, internal_type p, augment_type ag) {
301  size_t idx = index(i->my_offset, p);
302  p->values[idx].augment = ag;
303  }
304 
305  const augment_type & augment(internal_type p, size_t i) const {
306  return p->values[i].augment;
307  }
308 
309  size_t height() const throw() {
310  return m_height;
311  }
312 
313  void set_height(size_t height) throw() {
314  m_height = height;
315  }
316 
317  size_t size() const throw() {
318  return m_size;
319  }
320 
321  void set_size(size_t size) throw() {
322  m_size = size;
323  }
324 
325  void flush() {
326  if (current_internal) {
327  assert(!current_leaf);
328  assert((stream_size_type)f->tellp() == current_internal->my_offset);
329  serialize(*f, *current_internal);
330  current_internal.reset();
331  }
332  if (current_leaf) {
333  assert((stream_size_type)f->tellp() == current_leaf->my_offset);
334  serialize(*f, *current_leaf);
335  current_leaf.reset();
336  }
337  }
338 
339  void finalize_build() {
340  // Should call flush() first.
341  assert(!current_internal && !current_leaf);
342 
343  header h;
344  h.magic = header::good_magic;
345  h.version = header::current_version;
346  h.root = 0;
347  if (root_internal) {
348  h.root = root_internal->my_offset;
349  } else if (root_leaf) {
350  h.root = root_leaf->my_offset;
351  } else {
352  assert(m_size == 0);
353  }
354  h.height = m_height;
355  h.size = m_size;
356  h.metadata_offset = metadata_offset;
357  h.metadata_size = metadata_size;
358  f->seekp(0);
359  f->write(reinterpret_cast<char *>(&h), sizeof(h));
360  f->close();
361 
362  f->open(path, std::ios_base::in | std::ios_base::binary);
363  if (!f->is_open())
364  throw invalid_file_exception("Open failed");
365  }
366 
367  void set_metadata(const std::string & data) {
368  assert(!current_internal && !current_leaf);
369  assert(f->is_open());
370  metadata_offset = (stream_size_type)f->tellp();
371  metadata_size = data.size();
372  f->write(data.c_str(), data.size());
373  }
374 
375  std::string get_metadata() {
376  assert(f->is_open());
377  if (metadata_offset == 0 || metadata_size == 0)
378  return {};
379  std::string data(metadata_size, '\0');
380  f->read(&data[0], metadata_size);
381  return data;
382  }
383 
384  size_t m_height;
385  size_t m_size;
386  off_t metadata_offset, metadata_size;
387 
388  std::string path;
389  std::unique_ptr<std::fstream> f;
390  internal_type current_internal, root_internal;
391  leaf_type current_leaf, root_leaf;
392 
393  template <typename>
394  friend class ::tpie::btree_node;
395 
396  template <typename>
397  friend class ::tpie::btree_iterator;
398 
399  template <typename, typename>
400  friend class bbits::tree;
401 
402  template <typename, typename>
403  friend class bbits::tree_state;
404 
405  template<typename, typename>
406  friend class bbits::builder;
407 
408  template <typename, bool>
409  friend struct bbits::block_size_getter;
410 };
411 
412 } //namespace bbits
413 } //namespace tpie
414 #endif /*_TPIE_BTREE_SERIALIZED_STORE_H_*/
Defines the tp_assert macro.
Binary serialization and unserialization.
This file contains a few deprecated definitions for legacy code.
void unserialize(S &src, foo &v)
Sample tpie::unserialize prototype.
A augment_type
Type of augmentation stored.
T value_type
Type of value of items stored.
Serializing store.
Definition: base.h:217
void serialize(D &dst, const foo &v)
Sample tpie::serialize prototype.
#define tp_assert(condition, message)
Definition: tpie_assert.h:48