libfoedus-core
FOEDUS Core Library
array_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_ARRAY_LOG_TYPES_HPP_
19 #define FOEDUS_STORAGE_ARRAY_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"
30 #include "foedus/log/log_type.hpp"
37 #include "foedus/xct/xct_id.hpp"
38 
44 namespace foedus {
45 namespace storage {
46 namespace array {
61 
62  void apply_storage(Engine* engine, StorageId storage_id);
63  void assert_valid();
64  friend std::ostream& operator<<(std::ostream& o, const ArrayCreateLogType& v);
65 };
66 
74 struct ArrayCommonUpdateLogType : public log::RecordLogType {
76  ArrayOffset offset_; // +8 => 24
77  // payload_offset_ is also a common property, but we can't include it here for alignment.
78 
84  inline static int compare_logs(
85  const ArrayCommonUpdateLogType* left,
87  ASSERT_ND(left->header_.storage_id_ == right->header_.storage_id_);
88  if (left == right) {
89  return 0;
90  }
91  if (left->offset_ != right->offset_) {
92  if (left->offset_ < right->offset_) {
93  return -1;
94  } else {
95  return 1;
96  }
97  }
98  return left->header_.xct_id_.compare_epoch_and_orginal(right->header_.xct_id_);
99  }
100 };
101 
111  uint16_t payload_offset_; // +2 => 26
112  uint16_t payload_count_; // +2 => 28
113  char payload_[4]; // +4 => 32
114 
115  static uint16_t calculate_log_length(uint16_t payload_count) ALWAYS_INLINE {
116  // we pad to 8 bytes so that we always have a room for FillerLogType to align.
117  return assorted::align8(28 + payload_count);
118  }
119 
120  void populate(
121  StorageId storage_id,
122  ArrayOffset offset,
123  const void *payload,
124  uint16_t payload_offset,
125  uint16_t payload_count) ALWAYS_INLINE;
126 
128  template <typename T>
129  void populate_primitive(
130  StorageId storage_id,
131  ArrayOffset offset,
132  T payload,
133  uint16_t payload_offset) ALWAYS_INLINE;
134 
135  void apply_record(
136  thread::Thread* context,
137  StorageId storage_id,
138  xct::RwLockableXctId* owner_id,
139  char* payload) const ALWAYS_INLINE;
140 
141  void assert_valid() const ALWAYS_INLINE;
142 
143  friend std::ostream& operator<<(std::ostream& o, const ArrayOverwriteLogType& v);
144 };
145 
147 enum ValueType {
148  kUnknown = 0,
149  kI8 = 1,
157  // above are 32bits or less, below are 64 bits
161 };
162 template <typename T> ValueType to_value_type();
163 template <> inline ValueType to_value_type<bool>() { return kBool; }
164 template <> inline ValueType to_value_type<int8_t>() { return kI8; }
165 template <> inline ValueType to_value_type<int16_t>() { return kI16; }
166 template <> inline ValueType to_value_type<int32_t>() { return kI32; }
167 template <> inline ValueType to_value_type<int64_t>() { return kI64; }
168 template <> inline ValueType to_value_type<uint8_t>() { return kU8; }
169 template <> inline ValueType to_value_type<uint16_t>() { return kU16; }
170 template <> inline ValueType to_value_type<uint32_t>() { return kU32; }
171 template <> inline ValueType to_value_type<uint64_t>() { return kU64; }
172 template <> inline ValueType to_value_type<float>() { return kFloat; }
173 template <> inline ValueType to_value_type<double>() { return kDouble ; }
174 
185  uint16_t payload_offset_; // +2 => 26
186  uint16_t value_type_; // +2 => 28
187  char addendum_[4]; // +4 => 32
188 
189  static uint16_t calculate_log_length(ValueType value_type) ALWAYS_INLINE {
190  if (value_type < kI64) {
191  return 32; // in this case we store it in first bytes of addendum
192  } else {
193  return 40; // in this case we store it in 32th-bytes (28-32th bytes are not used)
194  }
195  }
196 
197  template <typename T>
198  void populate(
199  StorageId storage_id,
200  ArrayOffset offset,
201  T payload,
202  uint16_t payload_offset) ALWAYS_INLINE;
203 
204  ValueType get_value_type() const ALWAYS_INLINE { return static_cast<ValueType>(value_type_); }
205  bool is_64b_type() const ALWAYS_INLINE { return get_value_type() >= kI64; }
206  void* addendum_64() { return addendum_ + 4; }
207  const void* addendum_64() const { return addendum_ + 4; }
208 
209  void apply_record(
210  thread::Thread* context,
211  StorageId storage_id,
212  xct::RwLockableXctId* owner_id,
213  char* payload) const ALWAYS_INLINE;
214 
222  void merge(const ArrayIncrementLogType& other) ALWAYS_INLINE;
223 
224  void assert_valid() const ALWAYS_INLINE;
225 
226  friend std::ostream& operator<<(std::ostream& o, const ArrayIncrementLogType& v);
227 };
228 
229 
230 inline void ArrayOverwriteLogType::populate(
231  StorageId storage_id,
232  ArrayOffset offset,
233  const void *payload,
234  uint16_t payload_offset,
235  uint16_t payload_count) {
237  header_.log_length_ = calculate_log_length(payload_count);
238  header_.storage_id_ = storage_id;
239  offset_ = offset;
240  payload_offset_ = payload_offset;
241  payload_count_ = payload_count;
242  std::memcpy(payload_, payload, payload_count);
243 }
244 
245 template <typename T>
247  StorageId storage_id,
248  ArrayOffset offset,
249  T payload,
250  uint16_t payload_offset) {
252  header_.log_length_ = calculate_log_length(sizeof(T));
253  header_.storage_id_ = storage_id;
254  offset_ = offset;
255  payload_offset_ = payload_offset;
256  payload_count_ = sizeof(T);
257  T* address = reinterpret_cast<T*>(payload_);
258  *address = payload;
259 }
260 
262  thread::Thread* /*context*/,
263  StorageId /*storage_id*/,
264  xct::RwLockableXctId* /*owner_id*/,
265  char* payload) const {
266  ASSERT_ND(payload_count_ < kDataSize);
267  std::memcpy(payload + payload_offset_, payload_, payload_count_);
268 }
269 
272  ASSERT_ND(header_.log_length_ == calculate_log_length(payload_count_));
274 }
275 
276 template <typename T>
278  StorageId storage_id,
279  ArrayOffset offset,
280  T payload,
281  uint16_t payload_offset) {
283  ValueType type = to_value_type<T>();
284  header_.log_length_ = calculate_log_length(type);
285  header_.storage_id_ = storage_id;
286  offset_ = offset;
287  payload_offset_ = payload_offset;
288  value_type_ = type;
289  if (is_64b_type()) {
290  T* address = reinterpret_cast<T*>(addendum_ + 4);
291  *address = payload;
292  } else {
293  T* address = reinterpret_cast<T*>(addendum_);
294  *address = payload;
295  }
296 }
297 
298 template <typename T>
299 inline void increment(T* payload, const T* addendum) {
300  *payload += *addendum;
301 }
302 
304  thread::Thread* /*context*/,
305  StorageId /*storage_id*/,
306  xct::RwLockableXctId* /*owner_id*/,
307  char* payload) const {
308  switch (get_value_type()) {
309  // 32 bit data types
310  case kI8:
311  increment<int8_t>(
312  reinterpret_cast<int8_t*>(payload + payload_offset_),
313  reinterpret_cast<const int8_t*>(addendum_));
314  break;
315  case kI16:
316  increment<int16_t>(
317  reinterpret_cast<int16_t*>(payload + payload_offset_),
318  reinterpret_cast<const int16_t*>(addendum_));
319  break;
320  case kI32:
321  increment<int32_t>(
322  reinterpret_cast<int32_t*>(payload + payload_offset_),
323  reinterpret_cast<const int32_t*>(addendum_));
324  break;
325  case kBool:
326  case kU8:
327  increment<uint8_t>(
328  reinterpret_cast<uint8_t*>(payload + payload_offset_),
329  reinterpret_cast<const uint8_t*>(addendum_));
330  break;
331  case kU16:
332  increment<uint16_t>(
333  reinterpret_cast<uint16_t*>(payload + payload_offset_),
334  reinterpret_cast<const uint16_t*>(addendum_));
335  break;
336  case kU32:
337  increment<uint32_t>(
338  reinterpret_cast<uint32_t*>(payload + payload_offset_),
339  reinterpret_cast<const uint32_t*>(addendum_));
340  break;
341  case kFloat:
342  increment<float>(
343  reinterpret_cast<float*>(payload + payload_offset_),
344  reinterpret_cast<const float*>(addendum_));
345  break;
346 
347  // 64 bit data types
348  case kI64:
349  increment<int64_t>(
350  reinterpret_cast<int64_t*>(payload + payload_offset_),
351  reinterpret_cast<const int64_t*>(addendum_ + 4));
352  break;
353  case kU64:
354  increment<uint64_t>(
355  reinterpret_cast<uint64_t*>(payload + payload_offset_),
356  reinterpret_cast<const uint64_t*>(addendum_ + 4));
357  break;
358  case kDouble:
359  increment<double>(
360  reinterpret_cast<double*>(payload + payload_offset_),
361  reinterpret_cast<const double*>(addendum_ + 4));
362  break;
363  default:
364  ASSERT_ND(false);
365  break;
366  }
367 }
368 
369 template <typename T>
370 inline void add_to(void* destination, const void* added) {
371  *(reinterpret_cast< T* >(destination)) += *(reinterpret_cast< const T* >(added));
372 }
373 
376  ASSERT_ND(value_type_ == other.value_type_);
377  ASSERT_ND(payload_offset_ == other.payload_offset_);
378  switch (get_value_type()) {
379  // 32 bit data types
380  case kI8:
381  add_to<int8_t>(addendum_, other.addendum_);
382  break;
383  case kI16:
384  add_to<int16_t>(addendum_, other.addendum_);
385  break;
386  case kI32:
387  add_to<int32_t>(addendum_, other.addendum_);
388  break;
389  case kBool:
390  case kU8:
391  add_to<uint8_t>(addendum_, other.addendum_);
392  break;
393  case kU16:
394  add_to<uint16_t>(addendum_, other.addendum_);
395  break;
396  case kU32:
397  add_to<uint32_t>(addendum_, other.addendum_);
398  break;
399  case kFloat:
400  add_to<float>(addendum_, other.addendum_);
401  break;
402 
403  // 64 bit data types
404  case kI64:
405  add_to<int64_t>(addendum_64(), other.addendum_64());
406  break;
407  case kU64:
408  add_to<uint64_t>(addendum_64(), other.addendum_64());
409  break;
410  case kDouble:
411  add_to<double>(addendum_64(), other.addendum_64());
412  break;
413  default:
414  ASSERT_ND(false);
415  break;
416  }
417 }
418 
421  ASSERT_ND(header_.log_length_ == calculate_log_length(get_value_type()));
423  ASSERT_ND(get_value_type() >= kI8 && get_value_type() <= kDouble);
424 }
425 
426 } // namespace array
427 } // namespace storage
428 } // namespace foedus
429 #endif // FOEDUS_STORAGE_ARRAY_LOG_TYPES_HPP_
ValueType to_value_type< int16_t >()
Base class for log type of storage-wide operation.
ValueType to_value_type< uint64_t >()
T align8(T value)
8-alignment.
Definitions of IDs in this package and a few related constant values.
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
ValueType to_value_type< double >()
ValueType to_value_type< int32_t >()
uint64_t ArrayOffset
The only key type in array storage.
Definition: array_id.hpp:48
void apply_record(thread::Thread *context, StorageId storage_id, xct::RwLockableXctId *owner_id, char *payload) const __attribute__((always_inline))
void populate_primitive(StorageId storage_id, ArrayOffset offset, T payload, uint16_t payload_offset) __attribute__((always_inline))
For primitive types.
void add_to(void *destination, const void *added)
STL namespace.
Forward declarations of classes in array storage package.
ValueType to_value_type< float >()
void assert_valid() const __attribute__((always_inline))
bool is_64b_type() const __attribute__((always_inline))
Declares common log types used in all packages.
ValueType to_value_type< int8_t >()
const uint16_t kDataSize
Byte size of data region in each page of array storage.
Definition: array_id.hpp:100
0x0023 : foedus::storage::array::ArrayIncrementLogType .
Definition: log_type.hpp:116
0x0022 : foedus::storage::array::ArrayOverwriteLogType .
Definition: log_type.hpp:115
void apply_record(thread::Thread *context, StorageId storage_id, xct::RwLockableXctId *owner_id, char *payload) const __attribute__((always_inline))
ValueType to_value_type< uint32_t >()
ValueType to_value_type< uint16_t >()
A base class for ArrayOverwriteLogType/ArrayIncrementLogType.
void apply_storage(Engine *engine, StorageId storage_id)
The MCS reader-writer lock variant of LockableXctId.
Definition: xct_id.hpp:1132
ValueType to_value_type< int64_t >()
Log type of array-storage's overwrite operation.
Definitions of IDs in this package and a few related constant values.
void merge(const ArrayIncrementLogType &other) __attribute__((always_inline))
A special optimization for increment logs in log gleaner.
Database engine object that holds all resources and provides APIs.
Definition: engine.hpp:109
Metadata of an array storage.
ValueType to_value_type< uint8_t >()
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...
Log type of array-storage's increment operation.
uint16_t log_length_
Byte size of this log entry including this header itself and everything.
void apply_record(thread::Thread *, storage::StorageId, xct::RwLockableXctId *, char *)
Log type of CREATE ARRAY STORAGE operation.
void populate(StorageId storage_id, ArrayOffset offset, T payload, uint16_t payload_offset) __attribute__((always_inline))
ValueType
Used in ArrayIncrementLogType.
#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.
Atomic fence methods and load/store with fences that work for both C++11/non-C++11 code...
LogCode get_type() const __attribute__((always_inline))
Convenience method to cast into LogCode.
void assert_valid() const __attribute__((always_inline))
Definitions of IDs in this package and a few related constant values.
ValueType get_value_type() const __attribute__((always_inline))
ValueType to_value_type()
void increment(T *payload, const T *addendum)
#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
#define ALWAYS_INLINE
A function suffix to hint that the function should always be inlined.
Definition: compiler.hpp:106
void assert_valid_generic() __attribute__((always_inline))
Verifies the log contains essential fields set.