libfoedus-core
FOEDUS Core Library
masstree_page_debug.cpp
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  */
19 
20 #include <glog/logging.h>
21 
22 #include <algorithm>
23 #include <ostream>
24 #include <string>
25 
26 namespace foedus {
27 namespace storage {
28 namespace masstree {
29 
30 std::ostream& operator<<(std::ostream& o, const MasstreePage& v) {
31  if (v.is_border()) {
32  o << reinterpret_cast<const MasstreeBorderPage&>(v);
33  } else {
34  o << reinterpret_cast<const MasstreeIntermediatePage&>(v);
35  }
36  return o;
37 }
38 
39 void describe_masstree_page_common(std::ostream* o_ptr, const MasstreePage& v) {
40  std::ostream& o = *o_ptr;
41  o << std::endl << "<addr>" << assorted::Hex(reinterpret_cast<uintptr_t>(&v), 16) << "</addr>";
42  o << std::endl << v.header();
43  o << std::endl << "<low_fence_>" << assorted::Hex(v.get_low_fence(), 16) << "</low_fence_>";
44  o << "<high_fence_>" << assorted::Hex(v.get_high_fence(), 16) << "</high_fence_>";
45  o << "<foster_fence_>" << assorted::Hex(v.get_foster_fence(), 16) << "</foster_fence_>";
46  o << std::endl << "<foster_minor>";
48  o << "</foster_minor>";
49  o << std::endl << "<foster_major>";
51  o << "</foster_major>";
52 }
53 
54 std::ostream& operator<<(std::ostream& o, const MasstreeIntermediatePage& v) {
55  o << "<MasstreeIntermediatePage>";
57  if (v.is_empty_range()) {
58  o << "<EmptyRangePage />";
59  } else {
60  for (uint16_t i = 0; i <= v.get_key_count(); ++i) {
61  const MasstreeIntermediatePage::MiniPage& minipage = v.get_minipage(i);
62  KeySlice minipage_low = i == 0 ? v.get_low_fence() : v.get_separator(i - 1);
63  o << std::endl << " <Minipage index=\"" << static_cast<int>(i)
64  << "\" low=\"" << assorted::Hex(minipage_low, 16)
65  << "\" count=\"" << static_cast<int>(minipage.key_count_)
66  << "\">";
67  for (uint16_t j = 0; j <= minipage.key_count_; ++j) {
68  o << std::endl << " <Pointer index=\"" << static_cast<int>(j)
69  << "\" low=\""
70  << assorted::Hex(j == 0 ? minipage_low : minipage.separators_[j - 1], 16)
71  << "\">" << minipage.pointers_[j] << "</Pointer>";
72  }
73  o << std::endl << " </Minipage>";
74  }
75  }
76  o << "</MasstreeIntermediatePage>";
77  return o;
78 }
79 
80 std::ostream& operator<<(std::ostream& o, const MasstreeBorderPage& v) {
81  o << "<MasstreeBorderPage>";
83  o << "<consecutive_inserts_>" << v.consecutive_inserts_ << "</consecutive_inserts_>";
84  o << std::endl << "<records>";
85  for (uint16_t i = 0; i < v.get_key_count(); ++i) {
86  o << std::endl << " <record index=\"" << i
87  << "\" slice=\"" << assorted::Hex(v.get_slice(i), 16)
88  << "\" remainder_len=\"" << static_cast<int>(v.get_remainder_length(i))
89  << "\" offset=\"" << v.get_offset_in_bytes(i)
90  << "\" physical_record_len=\"" << v.get_slot(i)->lengthes_.components.physical_record_length_
91  << "\" payload_len=\"" << v.get_payload_length(i)
92  << "\">";
93  if (v.does_point_to_layer(i)) {
94  o << "<next_layer>" << *v.get_next_layer(i) << "</next_layer>";
95  } else {
96  if (v.get_remainder_length(i) > sizeof(KeySlice)) {
97  std::string suffix(v.get_record(i), v.get_suffix_length(i));
98  o << "<key_suffix>" << assorted::HexString(suffix) << "</key_suffix>";
99  }
100  if (v.get_payload_length(i) > 0) {
101  std::string payload(v.get_record_payload(i), v.get_payload_length(i));
102  o << "<payload>" << assorted::HexString(payload) << "</payload>";
103  }
104  }
105  o << * v.get_owner_id(i);
106  o << "</record>";
107  }
108  o << std::endl << "</records>";
109  o << "</MasstreeBorderPage>";
110  return o;
111 }
112 
113 
115  // the following logic holds only when this page is locked
117  struct Sorter {
118  explicit Sorter(const MasstreeBorderPage* target) : target_(target) {}
119  bool operator() (SlotIndex left, SlotIndex right) {
120  KeySlice left_slice = target_->get_slice(left);
121  KeySlice right_slice = target_->get_slice(right);
122  if (left_slice < right_slice) {
123  return true;
124  } else if (left_slice == right_slice) {
125  return target_->get_remainder_length(left) < target_->get_remainder_length(right);
126  } else {
127  return false;
128  }
129  }
130  const MasstreeBorderPage* target_;
131  };
132  SlotIndex key_count = get_key_count();
134  for (SlotIndex i = 0; i < key_count; ++i) {
135  order[i] = i;
136  }
137  std::sort(order, order + key_count, Sorter(this));
138 
139  if (header_.snapshot_) {
140  // in snapshot page, all entries should be fully sorted
141  for (SlotIndex i = 0; i < key_count; ++i) {
142  ASSERT_ND(order[i] == i);
143  }
144  }
145 
146  for (SlotIndex i = 1; i < key_count; ++i) {
147  SlotIndex pre = order[i - 1];
148  SlotIndex cur = order[i];
149  const KeySlice pre_slice = get_slice(pre);
150  const KeySlice cur_slice = get_slice(cur);
151  ASSERT_ND(pre_slice <= cur_slice);
152  if (pre_slice == cur_slice) {
153  const KeyLength pre_klen = get_remainder_length(pre);
154  const KeyLength cur_klen = get_remainder_length(cur);
155  ASSERT_ND(pre_klen < cur_klen);
156  ASSERT_ND(pre_klen <= sizeof(KeySlice));
157  }
158  }
159 
160  // also check the padding between key suffix and payload
161  if (header_.snapshot_) { // this can't be checked in volatile pages that are being changed
162  for (SlotIndex i = 0; i < key_count; ++i) {
163  if (does_point_to_layer(i)) {
164  continue;
165  }
166  KeyLength suffix_length = get_suffix_length(i);
167  KeyLength suffix_length_aligned = get_suffix_length_aligned(i);
168  if (suffix_length > 0 && suffix_length != suffix_length_aligned) {
169  ASSERT_ND(suffix_length_aligned > suffix_length);
170  for (KeyLength pos = suffix_length; pos < suffix_length_aligned; ++pos) {
171  // must be zero-padded
172  ASSERT_ND(get_record(i)[pos] == 0);
173  }
174  }
175  PayloadLength payload_length = get_payload_length(i);
176  PayloadLength payload_length_aligned = assorted::align8(payload_length);
177  if (payload_length > 0 && payload_length != payload_length_aligned) {
178  ASSERT_ND(payload_length_aligned > payload_length);
179  for (PayloadLength pos = payload_length; pos < payload_length_aligned; ++pos) {
180  // must be zero-padded
181  ASSERT_ND(get_record(i)[suffix_length_aligned + pos] == 0);
182  }
183  }
184  }
185  }
186 }
187 
188 
189 } // namespace masstree
190 } // namespace storage
191 } // namespace foedus
KeyLength get_remainder_length(SlotIndex index) const __attribute__((always_inline))
DataOffset physical_record_length_
Byte count this record occupies.
SlotIndex get_key_count() const __attribute__((always_inline))
physical key count (those keys might be deleted) in this page.
void describe_masstree_page_common(std::ostream *o_ptr, const MasstreePage &v)
DataOffset get_offset_in_bytes(SlotIndex index) const __attribute__((always_inline))
KeySlice get_slice(SlotIndex index) const __attribute__((always_inline))
T align8(T value)
8-alignment.
SlotLengthUnion lengthes_
Stores mutable length information of the record.
void describe_volatile_pointer(std::ostream *o, VolatilePagePointer pointer)
Definition: storage_id.cpp:44
bool is_empty_range() const __attribute__((always_inline))
An empty-range page, either intermediate or border, never has any entries.
uint16_t PayloadLength
Represents a byte-length of a payload in this package.
Definition: masstree_id.hpp:92
uint16_t SlotIndex
Index of a record in a (border) page.
std::ostream & operator<<(std::ostream &o, const MasstreeComposeContext::PathLevel &v)
bool is_locked() const __attribute__((always_inline))
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
bool is_border() const __attribute__((always_inline))
MiniPage & get_minipage(uint8_t index) __attribute__((always_inline))
Represents one border page in Masstree Storage.
DualPagePointer * get_next_layer(SlotIndex index) __attribute__((always_inline))
uint64_t KeySlice
Each key slice is an 8-byte integer.
uint16_t KeyLength
Represents a byte-length of a key in this package.
Definition: masstree_id.hpp:69
Common base of MasstreeIntermediatePage and MasstreeBorderPage.
char * get_record(SlotIndex index) __attribute__((always_inline))
VolatilePagePointer get_foster_minor() const __attribute__((always_inline))
PayloadLength get_payload_length(SlotIndex index) const __attribute__((always_inline))
VolatilePagePointer get_foster_major() const __attribute__((always_inline))
KeySlice get_separator(uint8_t index) const __attribute__((always_inline))
KeyLength get_suffix_length(SlotIndex index) const __attribute__((always_inline))
DualPagePointer pointers_[kMaxIntermediateMiniSeparators+1]
void assert_entries_impl() const
defined in masstree_page_debug.cpp.
const Slot * get_slot(SlotIndex index) const __attribute__((always_inline))
const SlotIndex kBorderPageMaxSlots
Maximum number of slots in one MasstreeBorderPage.
KeySlice get_high_fence() const __attribute__((always_inline))
Equivalent to std::hex in case the stream doesn't support it.
KeySlice separators_[kMaxIntermediateMiniSeparators]
Same semantics as separators_ in enclosing class.
KeySlice get_low_fence() const __attribute__((always_inline))
KeySlice get_foster_fence() const __attribute__((always_inline))
char * get_record_payload(SlotIndex index) __attribute__((always_inline))
Convenient way of writing hex integers to stream.
KeyLength get_suffix_length_aligned(SlotIndex index) const __attribute__((always_inline))
xct::RwLockableXctId * get_owner_id(SlotIndex index) __attribute__((always_inline))
Represents one intermediate page in Masstree Storage.
bool snapshot_
Whether this page image is of a snapshot page.
Definition: page.hpp:211
#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
bool does_point_to_layer(SlotIndex index) const __attribute__((always_inline))