libfoedus-core
FOEDUS Core Library
array_route.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2015, Hewlett-Packard Development Company, LP.
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11  * more details. You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the Free Software
13  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14  *
15  * HP designates this particular file as subject to the "Classpath" exception
16  * as provided by HP in the LICENSE.txt file that accompanied this code.
17  */
18 #ifndef FOEDUS_STORAGE_ARRAY_ARRAY_ROUTE_HPP_
19 #define FOEDUS_STORAGE_ARRAY_ARRAY_ROUTE_HPP_
20 
21 #include <stdint.h>
22 
23 #include "foedus/assert_nd.hpp"
24 #include "foedus/compiler.hpp"
29 
30 namespace foedus {
31 namespace storage {
32 namespace array {
41 union LookupRoute {
43  uint64_t word;
48  uint8_t route[8];
49 
51  uint8_t page_level,
52  uint8_t total_levels,
53  uint16_t payload_size,
54  ArrayOffset array_size) const;
55 
56  bool operator==(const LookupRoute& rhs) const { return word == rhs.word; }
57  bool operator!=(const LookupRoute& rhs) const { return word != rhs.word; }
58  bool operator<(const LookupRoute& rhs) const {
59  for (uint16_t i = 1; i <= 8U; ++i) {
60  // compare the higher level first. if the machine is big-endian, we can just compare word.
61  // but, this method is not used in performance-sensitive place, so let's be explicit.
62  if (route[8U - i] != rhs.route[8U - i]) {
63  return route[8U - i] < rhs.route[8U - i];
64  }
65  }
66  return false;
67  }
68  bool operator<=(const LookupRoute& rhs) const { return *this == rhs || *this < rhs; }
69 };
70 
71 inline uint16_t to_records_in_leaf(uint16_t payload_size) {
72  return kDataSize / (assorted::align8(payload_size) + kRecordOverhead);
73 }
74 
87  public:
89  : levels_(0),
90  records_in_leaf_(0),
91  leaf_fanout_div_(1),
92  interior_fanout_div_(1) {
93  }
94  LookupRouteFinder(uint8_t levels, uint16_t payload_size)
95  : levels_(levels),
96  records_in_leaf_(to_records_in_leaf(payload_size)),
97  leaf_fanout_div_(records_in_leaf_),
98  interior_fanout_div_(kInteriorFanout) {
99  }
100 
102 
117  ArrayOffset offset,
118  ArrayOffset *page_starts,
119  ArrayOffset *page_ends) const ALWAYS_INLINE;
120 
121  uint8_t get_levels() const ALWAYS_INLINE { return levels_; }
122  uint16_t get_records_in_leaf() const ALWAYS_INLINE { return records_in_leaf_; }
123 
124  private:
125  uint8_t levels_;
127  uint16_t records_in_leaf_;
129  assorted::ConstDiv leaf_fanout_div_;
131  assorted::ConstDiv interior_fanout_div_;
132 };
133 
135  LookupRoute ret;
136  ret.word = 0;
137  ArrayOffset old = offset;
138  offset = leaf_fanout_div_.div64(offset);
139  ret.route[0] = old - offset * records_in_leaf_;
140  for (uint8_t level = 1; level < levels_ - 1; ++level) {
141  old = offset;
142  offset = interior_fanout_div_.div64(offset);
143  ret.route[level] = old - offset * kInteriorFanout;
144  }
145  if (levels_ > 1) {
146  // the last level is done manually because we don't need any division there
147  ASSERT_ND(offset < kInteriorFanout);
148  ret.route[levels_ - 1] = offset;
149  }
150 
151  return ret;
152 }
153 
155  ArrayOffset offset,
156  ArrayOffset *page_starts,
157  ArrayOffset *page_ends) const {
158  LookupRoute ret;
159  ret.word = 0;
160  ArrayOffset old = offset;
161  offset = leaf_fanout_div_.div64(offset);
162  *page_starts = offset * records_in_leaf_;
163  *page_ends = *page_starts + records_in_leaf_;
164  ret.route[0] = old - (*page_starts);
165  for (uint8_t level = 1; level < levels_ - 1; ++level) {
166  old = offset;
167  offset = interior_fanout_div_.div64(offset);
168  ret.route[level] = old - offset * kInteriorFanout;
169  }
170  if (levels_ > 1) {
171  // the last level is done manually because we don't need any division there
172  ASSERT_ND(offset < kInteriorFanout);
173  ret.route[levels_ - 1] = offset;
174  }
175 
176  return ret;
177 }
178 
180  uint8_t page_level,
181  uint8_t total_levels,
182  uint16_t payload_size,
183  ArrayOffset array_size) const {
184  ASSERT_ND(total_levels > page_level);
185  ASSERT_ND(payload_size > 0);
186  ASSERT_ND(array_size > 0);
187  uint16_t records_in_leaf = to_records_in_leaf(payload_size);
188  uint64_t interval = records_in_leaf;
189  // for example:
190  // page_level==0, route={xxx, 3, 4} (levels=3): r*3 + r*kInteriorFanout*4 ~ +r
191  // page_level==1, route={xxx, yyy, 4} (levels=3): r*kInteriorFanout*4 ~ +r*kInteriorFanout
192  ArrayRange ret(0, 0);
193  if (page_level == 0) {
194  ret.end_ = records_in_leaf;
195  }
196  for (uint16_t level = 1; level < total_levels; ++level) {
197  if (level == page_level) {
198  ASSERT_ND(ret.begin_ == 0);
199  ASSERT_ND(ret.end_ == 0);
200  ret.end_ = interval * kInteriorFanout;
201  } else if (level > page_level) {
202  uint64_t shift = interval * route[level];
203  ret.begin_ += shift;
204  ret.end_ += shift;
205  }
206  interval *= kInteriorFanout;
207  }
208  ASSERT_ND(ret.begin_ < ret.end_);
209  ASSERT_ND(ret.begin_ < array_size);
210  if (ret.end_ > array_size) {
211  ret.end_ = array_size;
212  }
213  return ret;
214 }
215 
216 } // namespace array
217 } // namespace storage
218 } // namespace foedus
219 #endif // FOEDUS_STORAGE_ARRAY_ARRAY_ROUTE_HPP_
T align8(T value)
8-alignment.
const uint16_t kRecordOverhead
Byte size of system-managed region per each record.
Definition: record.hpp:56
uint8_t route[8]
[0] means record ordinal in leaf, [1] in its parent page, [2]...
Definition: array_route.hpp:48
Compactly represents the route to reach the given offset.
Definition: array_route.hpp:41
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
uint64_t ArrayOffset
The only key type in array storage.
Definition: array_id.hpp:48
uint64_t word
This is a 64bit data.
Definition: array_route.hpp:43
The pre-calculated p-m pair for optimized integer division by constant.
Definition: const_div.hpp:67
const uint16_t kDataSize
Byte size of data region in each page of array storage.
Definition: array_id.hpp:100
bool operator<=(const LookupRoute &rhs) const
Definition: array_route.hpp:68
ArrayOffset begin_
Inclusive beginning of the offset range.
Definition: array_id.hpp:86
bool operator!=(const LookupRoute &rhs) const
Definition: array_route.hpp:57
ArrayOffset end_
Exclusive end of the offset range.
Definition: array_id.hpp:88
uint16_t to_records_in_leaf(uint16_t payload_size)
Definition: array_route.hpp:71
bool operator==(const LookupRoute &rhs) const
Definition: array_route.hpp:56
LookupRoute find_route(ArrayOffset offset) const __attribute__((always_inline))
uint8_t get_levels() const __attribute__((always_inline))
LookupRoute find_route_and_switch(ArrayOffset offset, ArrayOffset *page_starts, ArrayOffset *page_ends) const __attribute__((always_inline))
find_route() plus calculates where page switches.
ArrayRange calculate_page_range(uint8_t page_level, uint8_t total_levels, uint16_t payload_size, ArrayOffset array_size) const
Represents an offset range in an array storage.
Definition: array_id.hpp:62
Packages logic and required properties to calculate LookupRoute in array storage from offset...
Definition: array_route.hpp:86
uint16_t get_records_in_leaf() const __attribute__((always_inline))
bool operator<(const LookupRoute &rhs) const
Definition: array_route.hpp:58
Definitions of IDs in this package and a few related constant values.
LookupRouteFinder(uint8_t levels, uint16_t payload_size)
Definition: array_route.hpp:94
const uint16_t kInteriorFanout
Max number of entries in an interior page of array storage.
Definition: array_id.hpp:110
#define ASSERT_ND(x)
A warning-free wrapper macro of assert() that has no performance effect in release mode even when 'x'...
Definition: assert_nd.hpp:72
uint64_t div64(uint64_t n) const
64-bit integer division that outputs both quotient and remainder.
Definition: const_div.hpp:241
#define ALWAYS_INLINE
A function suffix to hint that the function should always be inlined.
Definition: compiler.hpp:106