libfoedus-core
FOEDUS Core Library
hash_log_types.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_HASH_LOG_TYPES_HPP_
19 #define FOEDUS_STORAGE_HASH_LOG_TYPES_HPP_
20 #include <stdint.h>
21 
22 #include <cstring>
23 #include <iosfwd>
24 
25 #include "foedus/assert_nd.hpp"
26 #include "foedus/compiler.hpp"
29 #include "foedus/log/log_type.hpp"
36 #include "foedus/xct/xct_id.hpp"
37 
43 namespace foedus {
44 namespace storage {
45 namespace hash {
60 
61  void apply_storage(Engine* engine, StorageId storage_id);
62  void assert_valid();
63  friend std::ostream& operator<<(std::ostream& o, const HashCreateLogType& v);
64 };
65 
75 struct HashCommonLogType : public log::RecordLogType {
77  uint16_t key_length_; // +2 => 18
78  uint16_t payload_offset_; // +2 => 20
79  uint16_t payload_count_; // +2 => 22
81  uint8_t bin_bits_; // +1 => 23
82  uint8_t reserved_; // +1 => 24
87  HashValue hash_; // +8 => 32
88 
93  char aligned_data_[8]; // ~ (+align8(key_length_)+align8(payload_count_))
94 
95  static uint16_t calculate_log_length(uint16_t key_length, uint16_t payload_count) ALWAYS_INLINE {
96  return 32U + assorted::align8(key_length) + assorted::align8(payload_count);
97  }
98 
99  char* get_key() { return aligned_data_; }
100  const char* get_key() const { return aligned_data_; }
101  uint16_t get_key_length_aligned() const { return assorted::align8(key_length_); }
102  char* get_payload() { return aligned_data_ + get_key_length_aligned(); }
103  const char* get_payload() const { return aligned_data_ + get_key_length_aligned(); }
105  log::LogCode type,
106  StorageId storage_id,
107  const void* key,
108  uint16_t key_length,
109  uint8_t bin_bits,
110  HashValue hash,
111  const void* payload = CXX11_NULLPTR,
112  uint16_t payload_offset = 0,
113  uint16_t payload_count = 0) ALWAYS_INLINE {
114  header_.log_type_code_ = type;
115  header_.log_length_ = calculate_log_length(key_length, payload_count);
116  header_.storage_id_ = storage_id;
117  key_length_ = key_length;
118  payload_offset_ = payload_offset;
119  payload_count_ = payload_count;
120  bin_bits_ = bin_bits;
121  reserved_ = 0;
122  ASSERT_ND(hash == hashinate(key, key_length));
123  hash_ = hash;
124 
125  std::memcpy(aligned_data_, key, key_length);
126  uint16_t aligned_key_length = assorted::align8(key_length);
127  if (aligned_key_length != key_length) {
128  std::memset(aligned_data_ + key_length, 0, aligned_key_length - key_length);
129  }
130  if (payload_count > 0) {
131  uint16_t aligned_payload_count = assorted::align8(payload_count);
132  char* payload_base = aligned_data_ + aligned_key_length;
133  std::memcpy(payload_base, payload, payload_count);
134  if (aligned_payload_count != payload_count) {
135  std::memset(payload_base + payload_count, 0, aligned_payload_count - payload_count);
136  }
137  }
138  }
139 
141 #ifndef NDEBUG
142  void assert_record_and_log_keys(xct::RwLockableXctId* owner_id, const char* data) const {
143  const char* log_key = get_key();
144  ASSERT_ND(hash_ == hashinate(log_key, key_length_));
145  uint16_t log_key_length_aligned = get_key_length_aligned();
146 
147  // In HashDataPage::Slot, offset_ etc comes after owner_id. Let's do sanity checks.
148  uint16_t* lengthes = reinterpret_cast<uint16_t*>(owner_id + 1);
149  // physical length enough long?
150  ASSERT_ND(lengthes[1] >= log_key_length_aligned + assorted::align8(payload_count_));
151  ASSERT_ND(lengthes[2] == key_length_); // key length correct?
152 
153  // and then HashValue follows.
154  ASSERT_ND(hash_ == reinterpret_cast<HashValue*>(owner_id + 1)[1]);
155  // finally, does the key really match?
156  ASSERT_ND(std::memcmp(log_key, data, log_key_length_aligned) == 0);
157  }
158 #else // NDEBUG
159  void assert_record_and_log_keys(xct::RwLockableXctId* /*owner_id*/, const char* /*data*/) const {}
160 #endif // NDEBUG
161 
162  void assert_type() const ALWAYS_INLINE {
167  ASSERT_ND(hash_ == hashinate(get_key(), key_length_));
168  }
169 
178  inline static int compare_logs(
179  const HashCommonLogType* left,
180  const HashCommonLogType* right) ALWAYS_INLINE {
181  ASSERT_ND(left->header_.storage_id_ == right->header_.storage_id_);
182  ASSERT_ND(left->bin_bits_ == right->bin_bits_);
183  ASSERT_ND(left->hash_ == hashinate(left->get_key(), left->key_length_));
184  ASSERT_ND(right->hash_ == hashinate(right->get_key(), right->key_length_));
185  if (left == right) {
186  return 0;
187  }
188  HashBin left_bin = left->hash_ >> (64U - left->bin_bits_);
189  HashBin right_bin = right->hash_ >> (64U - right->bin_bits_);
190  if (left_bin != right_bin) {
191  if (left_bin < right_bin) {
192  return -1;
193  } else {
194  return 1;
195  }
196  }
197  return left->header_.xct_id_.compare_epoch_and_orginal(right->header_.xct_id_);
198  }
199 };
200 
201 
211 
212  void populate(
213  StorageId storage_id,
214  const void* key,
215  uint16_t key_length,
216  uint8_t bin_bits,
217  HashValue hash,
218  const void* payload,
219  uint16_t payload_count) ALWAYS_INLINE {
221  populate_base(type, storage_id, key, key_length, bin_bits, hash, payload, 0, payload_count);
222  }
223 
225  thread::Thread* /*context*/,
226  StorageId /*storage_id*/,
227  xct::RwLockableXctId* owner_id,
228  char* data) const ALWAYS_INLINE {
229  ASSERT_ND(owner_id->xct_id_.is_deleted()); // the physical record should be in 'deleted' status
230  ASSERT_ND(!owner_id->xct_id_.is_next_layer());
231  ASSERT_ND(!owner_id->xct_id_.is_moved());
232 
233  // no need to set key in apply(). it's already set when the record is physically inserted
234  // (or in other places if this is recovery).
235  assert_record_and_log_keys(owner_id, data);
236 
237  uint16_t* lengthes = reinterpret_cast<uint16_t*>(owner_id + 1);
238  // physical_record_length_ (lengthes[1]) is immutable, so this is
239  // guaranteed regardless of isolation levels. let's check.
240  ASSERT_ND(lengthes[1] >= assorted::align8(payload_count_) + lengthes[2]);
241  lengthes[3] = payload_count_; // set payload length
242 
243  if (payload_count_ > 0U) {
244  // record's payload is also 8-byte aligned, so copy multiply of 8 bytes.
245  // if the compiler is smart enough, it will do some optimization here.
246  uint16_t key_length_aligned = get_key_length_aligned();
247  void* data_payload = ASSUME_ALIGNED(data + key_length_aligned, 8U);
248  const void* log_payload = ASSUME_ALIGNED(get_payload(), 8U);
249  std::memcpy(data_payload, log_payload, assorted::align8(payload_count_));
250  }
251  assert_record_and_log_keys(owner_id, data);
252  owner_id->xct_id_.set_notdeleted();
253  }
254 
257  assert_type();
258  ASSERT_ND(header_.log_length_ == calculate_log_length(key_length_, payload_count_));
260  }
261 
262  friend std::ostream& operator<<(std::ostream& o, const HashInsertLogType& v);
263 };
264 
273 
274  void populate(
275  StorageId storage_id,
276  const void* key,
277  uint16_t key_length,
278  uint8_t bin_bits,
279  HashValue hash) ALWAYS_INLINE {
281  populate_base(type, storage_id, key, key_length, bin_bits, hash);
282  }
283 
285  thread::Thread* /*context*/,
286  StorageId /*storage_id*/,
287  xct::RwLockableXctId* owner_id,
288  char* data) const ALWAYS_INLINE {
289  ASSERT_ND(!owner_id->xct_id_.is_deleted());
290  ASSERT_ND(!owner_id->xct_id_.is_next_layer());
291  ASSERT_ND(!owner_id->xct_id_.is_moved());
292  assert_record_and_log_keys(owner_id, data);
293  owner_id->xct_id_.set_deleted();
294  }
295 
298  assert_type();
299  ASSERT_ND(header_.log_length_ == calculate_log_length(key_length_, payload_count_));
301  }
302 
303  friend std::ostream& operator<<(std::ostream& o, const HashDeleteLogType& v);
304 };
305 
317 
318  void populate(
319  StorageId storage_id,
320  const void* key,
321  uint16_t key_length,
322  uint8_t bin_bits,
323  HashValue hash,
324  const void* payload,
325  uint16_t payload_count) ALWAYS_INLINE {
327  populate_base(type, storage_id, key, key_length, bin_bits, hash, payload, 0, payload_count);
328  }
329 
331  thread::Thread* /*context*/,
332  StorageId /*storage_id*/,
333  xct::RwLockableXctId* owner_id,
334  char* data) const ALWAYS_INLINE {
335  ASSERT_ND(!owner_id->xct_id_.is_deleted());
336  ASSERT_ND(!owner_id->xct_id_.is_next_layer());
337  ASSERT_ND(!owner_id->xct_id_.is_moved());
338 
339  // no need to set key in apply(). it's already set when the record is physically inserted
340  // (or in other places if this is recovery).
341  assert_record_and_log_keys(owner_id, data);
342 
343  uint16_t* lengthes = reinterpret_cast<uint16_t*>(owner_id + 1);
344  // physical_record_length_ (lengthes[1]) is immutable, so this is
345  // guaranteed regardless of isolation levels. let's check.
346  ASSERT_ND(lengthes[1] >= assorted::align8(payload_count_) + lengthes[2]);
347  lengthes[3] = payload_count_; // set payload length
348 
349  if (payload_count_ > 0U) {
350  // record's payload is also 8-byte aligned, so copy multiply of 8 bytes.
351  // if the compiler is smart enough, it will do some optimization here.
352  uint16_t key_length_aligned = get_key_length_aligned();
353  void* data_payload = ASSUME_ALIGNED(data + key_length_aligned, 8U);
354  const void* log_payload = ASSUME_ALIGNED(get_payload(), 8U);
355  std::memcpy(data_payload, log_payload, assorted::align8(payload_count_));
356  }
357  assert_record_and_log_keys(owner_id, data);
358  }
359 
362  assert_type();
363  ASSERT_ND(header_.log_length_ == calculate_log_length(key_length_, payload_count_));
365  }
366 
367  friend std::ostream& operator<<(std::ostream& o, const HashUpdateLogType& v);
368 };
369 
379 
380  void populate(
381  StorageId storage_id,
382  const void* key,
383  uint16_t key_length,
384  uint8_t bin_bits,
385  HashValue hash,
386  const void* payload,
387  uint16_t payload_offset,
388  uint16_t payload_count) ALWAYS_INLINE {
390  populate_base(
391  type,
392  storage_id,
393  key,
394  key_length,
395  bin_bits,
396  hash,
397  payload,
398  payload_offset,
399  payload_count);
400  }
401 
403  thread::Thread* /*context*/,
404  StorageId /*storage_id*/,
405  xct::RwLockableXctId* owner_id,
406  char* data) ALWAYS_INLINE {
407  ASSERT_ND(!owner_id->xct_id_.is_deleted());
408  ASSERT_ND(!owner_id->xct_id_.is_next_layer());
409  ASSERT_ND(!owner_id->xct_id_.is_moved());
410 
411  uint16_t key_length_aligned = get_key_length_aligned();
412  assert_record_and_log_keys(owner_id, data);
413 
414 #ifndef NDEBUG
415  uint16_t* lengthes = reinterpret_cast<uint16_t*>(owner_id + 1);
416  ASSERT_ND(payload_offset_ + payload_count_ <= lengthes[3]); // aren't we over-running?
417 #endif // NDEBUG
418 
419  ASSERT_ND(payload_count_ > 0U);
420  // Unlike insert, we can't assume 8-bytes alignment because of payload_offset
421  std::memcpy(data + key_length_aligned + payload_offset_, get_payload(), payload_count_);
422  }
423 
426  assert_type();
427  ASSERT_ND(header_.log_length_ == calculate_log_length(key_length_, payload_count_));
429  }
430 
431  friend std::ostream& operator<<(std::ostream& o, const HashOverwriteLogType& v);
432 };
433 
434 } // namespace hash
435 } // namespace storage
436 } // namespace foedus
437 #endif // FOEDUS_STORAGE_HASH_LOG_TYPES_HPP_
LogCode
A unique identifier of all log types.
Definition: log_type.hpp:87
Base class for log type of storage-wide operation.
void assert_valid() __attribute__((always_inline))
T align8(T value)
8-alignment.
Definitions of IDs in this package and a few related constant values.
void assert_type() const __attribute__((always_inline))
#define CXX11_NULLPTR
Used in public headers in place of "nullptr" of C++11.
Definition: cxx11.hpp:132
uint32_t StorageId
Unique ID for storage.
Definition: storage_id.hpp:55
Root package of FOEDUS (Fast Optimistic Engine for Data Unification Services).
Definition: assert_nd.hpp:44
Represents one thread running on one NUMA core.
Definition: thread.hpp:48
void assert_valid() __attribute__((always_inline))
void apply_record(thread::Thread *, StorageId, xct::RwLockableXctId *owner_id, char *data) const __attribute__((always_inline))
STL namespace.
0x002A : foedus::storage::hash::HashDeleteLogType .
Definition: log_type.hpp:123
friend std::ostream & operator<<(std::ostream &o, const HashCreateLogType &v)
void apply_record(thread::Thread *, StorageId, xct::RwLockableXctId *owner_id, char *data) const __attribute__((always_inline))
Declares common log types used in all packages.
#define ASSUME_ALIGNED(x, y)
Wraps GCC's __builtin_assume_aligned.
Definition: compiler.hpp:111
The MCS reader-writer lock variant of LockableXctId.
Definition: xct_id.hpp:1132
void apply_storage(Engine *engine, StorageId storage_id)
void assert_valid() __attribute__((always_inline))
Independent utility methods/classes for hashination, or hash functions.
HashValue hashinate(const void *key, uint16_t key_length)
Calculates hash value for general input.
void assert_valid() __attribute__((always_inline))
Definitions of IDs in this package and a few related constant values.
Log type of hash-storage's update operation.
Database engine object that holds all resources and provides APIs.
Definition: engine.hpp:109
A base class for HashInsertLogType/HashDeleteLogType/HashOverwriteLogType.
void populate_base(log::LogCode type, StorageId storage_id, const void *key, uint16_t key_length, uint8_t bin_bits, HashValue hash, const void *payload=nullptr, uint16_t payload_offset=0, uint16_t payload_count=0) __attribute__((always_inline))
0x0029 : foedus::storage::hash::HashInsertLogType .
Definition: log_type.hpp:122
uint16_t log_type_code_
Actually of LogCode defined in the X-Macro, but we want to make sure the type size is 2 bytes...
uint16_t log_length_
Byte size of this log entry including this header itself and everything.
void assert_record_and_log_keys(xct::RwLockableXctId *owner_id, const char *data) const
used only for sanity check.
uint64_t HashBin
Represents a bin of a hash value.
Definition: hash_id.hpp:142
Log type of hash-storage's insert operation.
Log type of hash-storage's overwrite operation.
0x0028 : foedus::storage::hash::HashOverwriteLogType .
Definition: log_type.hpp:121
Metadata of an hash storage.
#define LOG_TYPE_NO_CONSTRUCT(clazz)
Macro to delete all constructors/destructors to prevent misuse for log type classes.
storage::StorageId storage_id_
The storage this loggable operation mainly affects.
LogCode get_type() const __attribute__((always_inline))
Convenience method to cast into LogCode.
void apply_record(thread::Thread *, StorageId, xct::RwLockableXctId *owner_id, char *data) __attribute__((always_inline))
static int compare_logs(const HashCommonLogType *left, const HashCommonLogType *right) __attribute__((always_inline))
Returns -1, 0, 1 when left is less than, same, larger than right in terms of bin and xct_id...
void apply_record(thread::Thread *, StorageId, xct::RwLockableXctId *owner_id, char *data) const __attribute__((always_inline))
#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
Definitions of IDs in this package and a few related constant values.
#define ALWAYS_INLINE
A function suffix to hint that the function should always be inlined.
Definition: compiler.hpp:106
0x002B : foedus::storage::hash::HashUpdateLogType .
Definition: log_type.hpp:124
void assert_valid_generic() __attribute__((always_inline))
Verifies the log contains essential fields set.
Forward declarations of classes in hash storage package.
Log type of hash-storage's delete operation.
Log type of CREATE HASH STORAGE operation.
uint64_t HashValue
Represents a full 64-bit hash value calculated from a key.
Definition: hash_id.hpp:129