libfoedus-core
FOEDUS Core Library
sequential_page_impl.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_SEQUENTIAL_SEQUENTIAL_PAGE_IMPL_HPP_
19 #define FOEDUS_STORAGE_SEQUENTIAL_SEQUENTIAL_PAGE_IMPL_HPP_
20 #include <stdint.h>
21 
22 #include <cstring>
23 
24 #include "foedus/assert_nd.hpp"
25 #include "foedus/compiler.hpp"
26 #include "foedus/epoch.hpp"
29 #include "foedus/storage/page.hpp"
33 #include "foedus/xct/xct_id.hpp"
34 
35 namespace foedus {
36 namespace storage {
37 namespace sequential {
38 
53 class SequentialPage final {
54  public:
55  // A page object is never explicitly instantiated. You must reinterpret_cast.
56  SequentialPage() = delete;
57  SequentialPage(const SequentialPage& other) = delete;
58  SequentialPage& operator=(const SequentialPage& other) = delete;
59 
60  // simple accessors
61  PageHeader& header() { return header_; }
62  const PageHeader& header() const { return header_; }
63 
71  uint16_t get_record_count() const { return record_count_; }
79  uint16_t get_used_data_bytes() const { return used_data_bytes_; }
80 
81  void assert_consistent() const {
82  ASSERT_ND(get_used_data_bytes() + get_record_count() * sizeof(PayloadLength) <= kDataSize);
83  }
84 
86  uint16_t get_payload_length(uint16_t record) const {
87  ASSERT_ND(record < get_record_count());
89  const PayloadLength* lengthes = reinterpret_cast<const PayloadLength*>(data_ + kDataSize);
90  PayloadLength length = *(lengthes - 1 - record);
91  return length;
92  }
94  void set_payload_length(uint16_t record, uint16_t length) {
96  PayloadLength* lengthes = reinterpret_cast<PayloadLength*>(data_ + kDataSize);
97  *(lengthes - 1 - record) = length;
98  }
100  uint16_t get_record_length(uint16_t record) const {
102  }
103 
106  uint16_t* record_count,
107  const char** record_pointers,
108  uint16_t* payload_lengthes) const {
110  *record_count = get_record_count();
111  uint16_t position = 0;
112  for (uint16_t i = 0; i < *record_count; ++i) {
113  record_pointers[i] = data_ + position;
114  payload_lengthes[i] = get_payload_length(i);
115  position += assorted::align8(payload_lengthes[i]) + foedus::storage::kRecordOverhead;
116  }
117  }
119  uint16_t get_record_offset(uint16_t record) const {
121  ASSERT_ND(record < get_record_count());
122  uint16_t offset = 0;
123  for (uint16_t i = 0; i < record; ++i) {
124  uint16_t payload_length = get_payload_length(i);
125  offset += assorted::align8(payload_length) + foedus::storage::kRecordOverhead;
126  }
127  return offset;
128  }
129 
130  DualPagePointer& next_page() { return next_page_; }
131  const DualPagePointer& next_page() const { return next_page_; }
132 
135  header_.init_volatile(page_id, storage_id, kSequentialPageType);
136  record_count_ = 0;
137  used_data_bytes_ = 0;
138  next_page_.snapshot_pointer_ = 0;
139  next_page_.volatile_pointer_.word = 0;
140  }
142  header_.init_snapshot(page_id, storage_id, kSequentialPageType);
143  record_count_ = 0;
144  used_data_bytes_ = 0;
145  next_page_.snapshot_pointer_ = 0;
146  next_page_.volatile_pointer_.word = 0;
147  }
148 
156  xct::XctId owner_id,
157  uint16_t payload_length,
158  const void* payload) {
159  uint16_t record = get_record_count();
160  ASSERT_ND(record < kMaxSlots);
161  ASSERT_ND(used_data_bytes_ + assorted::align8(payload_length) + kRecordOverhead <= kDataSize);
162  set_payload_length(record, payload_length);
163  xct::RwLockableXctId* owner_id_addr = owner_id_from_offset(used_data_bytes_);
164  owner_id_addr->xct_id_ = owner_id;
165  owner_id_addr->lock_.reset(); // not used...
166  std::memcpy(data_ + used_data_bytes_ + kRecordOverhead, payload, payload_length);
167  ++record_count_;
168  used_data_bytes_ += assorted::align8(payload_length) + kRecordOverhead;
169  header_.key_count_ = record_count_;
170  if (!header_.snapshot_) {
171  // to protect concurrent cursor, version counter must be written at last
173  }
174  // no need for lock to increment, just a barrier suffices. directly call status_.increment.
177  }
178 
184  bool can_insert_record(uint16_t payload_length) const {
185  uint16_t record_length = assorted::align8(payload_length) + kRecordOverhead;
186  return used_data_bytes_ + record_length
187  + sizeof(PayloadLength) * (record_count_ + 1) <= kDataSize && record_count_ < kMaxSlots;
188  }
195  const xct::RwLockableXctId* first_owner_id = owner_id_from_offset(0);
196  return first_owner_id->xct_id_.get_epoch();
197  }
198 
200  return reinterpret_cast<xct::RwLockableXctId*>(data_ + offset);
201  }
202  const xct::RwLockableXctId* owner_id_from_offset(uint16_t offset) const {
203  return reinterpret_cast<const xct::RwLockableXctId*>(data_ + offset);
204  }
205 
206  uint32_t unused_dummy_func_filler() const { return filler_; }
207 
208  private:
210  typedef uint16_t PayloadLength;
211 
212  PageHeader header_; // +40 -> 40
213 
214  uint16_t record_count_; // +2 -> 42
215  uint16_t used_data_bytes_; // +2 -> 44
216  uint32_t filler_; // +4 -> 48
217 
222  DualPagePointer next_page_; // +16 -> 64
223 
228  char data_[kDataSize];
229 };
230 
250 class SequentialRootPage final {
251  public:
252  // A page object is never explicitly instantiated. You must reinterpret_cast.
253  SequentialRootPage() = delete;
254  SequentialRootPage(const SequentialRootPage& other) = delete;
255  SequentialRootPage& operator=(const SequentialRootPage& other) = delete;
256 
257  // simple accessors
258  PageHeader& header() { return header_; }
259  const PageHeader& header() const { return header_; }
260 
262  uint16_t get_pointer_count() const { return pointer_count_; }
263  const HeadPagePointer* get_pointers() const { return head_page_pointers_; }
264 
265  void set_pointers(HeadPagePointer *pointers, uint16_t pointer_count) {
266  ASSERT_ND(pointer_count <= kRootPageMaxHeadPointers);
267  pointer_count_ = pointer_count;
268  std::memcpy(head_page_pointers_, pointers, sizeof(HeadPagePointer) * pointer_count);
269  }
270 
271  SnapshotPagePointer get_next_page() const { return next_page_; }
272  void set_next_page(SnapshotPagePointer page) { next_page_ = page; }
273 
276  header_.init_snapshot(page_id, storage_id, kSequentialRootPageType);
277  pointer_count_ = 0;
278  next_page_ = 0;
279  }
280 
281  const char* unused_dummy_func_filler() const { return filler_; }
282 
283  private:
284  PageHeader header_; // +40 -> 40
285 
290  uint64_t pointer_count_; // +8 -> 48
291 
293  SnapshotPagePointer next_page_; // +8 -> 56
294 
296  HeadPagePointer head_page_pointers_[kRootPageMaxHeadPointers];
297 
298  char filler_[kPageSize - kRootPageHeaderSize - sizeof(head_page_pointers_)];
299 };
300 
301 STATIC_SIZE_CHECK(sizeof(SequentialPage), 1 << 12)
302 STATIC_SIZE_CHECK(sizeof(SequentialRootPage), 1 << 12)
303 
304 } // namespace sequential
305 } // namespace storage
306 } // namespace foedus
307 #endif // FOEDUS_STORAGE_SEQUENTIAL_SEQUENTIAL_PAGE_IMPL_HPP_
T align8(T value)
8-alignment.
Represents a pointer to another page (usually a child page).
Definition: storage_id.hpp:271
Definitions of IDs in this package and a few related constant values.
const uint16_t kRecordOverhead
Byte size of system-managed region per each record.
Definition: record.hpp:56
uint32_t StorageId
Unique ID for storage.
Definition: storage_id.hpp:55
void init_volatile(VolatilePagePointer page_id, StorageId storage_id, PageType page_type) __attribute__((always_inline))
Definition: page.hpp:284
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
bool can_insert_record(uint16_t payload_length) const
Returns if this page has enough room to insert a record with the given payload length.
SequentialPage & operator=(const SequentialPage &other)=delete
Epoch get_first_record_epoch() const
Returns the epoch of the fist record in this page (undefined behavior if no record).
void get_all_records_nosync(uint16_t *record_count, const char **record_pointers, uint16_t *payload_lengthes) const
Retrieve positions and lengthes of all records in one batch.
Represents a pointer to a volatile page with modification count for preventing ABA.
Definition: storage_id.hpp:194
Persistent status part of Transaction ID.
Definition: xct_id.hpp:955
void append_record_nosync(xct::XctId owner_id, uint16_t payload_length, const void *payload)
Appends a record to this page.
Represents a time epoch.
Definition: epoch.hpp:61
XctId xct_id_
the second 64bit: Persistent status part of TID.
Definition: xct_id.hpp:1137
Represents one data page in Sequential Storage.
const uint16_t kRootPageMaxHeadPointers
Maximum number of head pointers in one root page.
Each pointer to a snapshot head page comes with a bit more information to help reading.
McsRwLock lock_
the first 64bit: Locking part of TID
Definition: xct_id.hpp:1134
The MCS reader-writer lock variant of LockableXctId.
Definition: xct_id.hpp:1132
uint16_t get_payload_length(uint16_t record) const
Returns byte length of payload of the specified record in this page.
const xct::RwLockableXctId * owner_id_from_offset(uint16_t offset) const
VolatilePagePointer volatile_pointer_
Definition: storage_id.hpp:308
xct::RwLockableXctId * owner_id_from_offset(uint16_t offset)
uint16_t key_count_
physical key count (those keys might be deleted) in this page.
Definition: page.hpp:219
Definitions of IDs in this package and a few related constant values.
uint16_t get_record_offset(uint16_t record) const
Returns beginning offset of the specified record.
uint64_t SnapshotPagePointer
Page ID of a snapshot page.
Definition: storage_id.hpp:79
SnapshotPagePointer snapshot_pointer_
Definition: storage_id.hpp:307
Epoch get_epoch() const __attribute__((always_inline))
Definition: xct_id.hpp:964
Just a marker to denote that a memory region represents a data page.
Definition: page.hpp:184
PageVersion page_version_
Used in several storage types as concurrency control mechanism for the page.
Definition: page.hpp:272
uint16_t get_record_length(uint16_t record) const
Returns byte length of the specified record in this page.
Definitions of IDs in this package and a few related constant values.
uint16_t get_pointer_count() const
Returns How many pointers to head pages exist in this page.
Represents one stable root page in Sequential Storage.
void set_pointers(HeadPagePointer *pointers, uint16_t pointer_count)
void initialize_snapshot_page(StorageId storage_id, SnapshotPagePointer page_id)
void init_snapshot(SnapshotPagePointer page_id, StorageId storage_id, PageType page_type) __attribute__((always_inline))
Definition: page.hpp:301
PageVersionStatus status_
Definition: page.hpp:172
void set_payload_length(uint16_t record, uint16_t length)
Sets byte length of payload of the specified record in this page.
uint16_t get_record_count() const
Returns how many records in this page placed so far.
Atomic fence methods and load/store with fences that work for both C++11/non-C++11 code...
const uint16_t kDataSize
Byte size of data region in each data page of sequential storage.
#define STATIC_SIZE_CHECK(desired, actual)
bool snapshot_
Whether this page image is of a snapshot page.
Definition: page.hpp:211
const uint16_t kRootPageHeaderSize
Byte size of header in each root page of sequential storage.
#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
void initialize_snapshot_page(StorageId storage_id, SnapshotPagePointer page_id)
Called only when this page is initialized.
void memory_fence_release()
Equivalent to std::atomic_thread_fence(std::memory_order_release).
SequentialRootPage & operator=(const SequentialRootPage &other)=delete
const uint16_t kPageSize
A constant defining the page size (in bytes) of both snapshot pages and volatile pages.
Definition: storage_id.hpp:45
const uint16_t kMaxSlots
We have to represent the record count in 15 bits.
uint16_t get_used_data_bytes() const
How many data bytes in this page consumed so far.
void increment_version_counter() __attribute__((always_inline))
Definition: page.hpp:103
void initialize_volatile_page(StorageId storage_id, VolatilePagePointer page_id)
Called only when this page is initialized.