libfoedus-core
FOEDUS Core Library
foedus::storage::hash::HashStoragePimpl Class Referencefinal

Pimpl object of HashStorage. More...

Detailed Description

Pimpl object of HashStorage.

A private pimpl object for HashStorage. Do not include this header from a client program unless you know what you are doing.

Definition at line 93 of file hash_storage_pimpl.hpp.

#include <hash_storage_pimpl.hpp>

Inheritance diagram for foedus::storage::hash::HashStoragePimpl:
Collaboration diagram for foedus::storage::hash::HashStoragePimpl:

Public Member Functions

 HashStoragePimpl ()
 
 HashStoragePimpl (HashStorage *storage)
 
void release_pages_recursive_root (memory::PageReleaseBatch *batch, HashIntermediatePage *page, VolatilePagePointer volatile_page_id)
 Used only from uninitialize() More...
 
void release_pages_recursive_intermediate (memory::PageReleaseBatch *batch, HashIntermediatePage *page, VolatilePagePointer volatile_page_id)
 
void release_pages_recursive_data (memory::PageReleaseBatch *batch, HashDataPage *page, VolatilePagePointer volatile_page_id)
 
xct::TrackMovedRecordResult track_moved_record (xct::RwLockableXctId *old_address, xct::WriteXctAccess *write_set)
 
xct::TrackMovedRecordResult track_moved_record_search (HashDataPage *page, const void *key, uint16_t key_length, const HashCombo &combo)
 
ErrorStack verify_single_thread (Engine *engine)
 These are defined in hash_storage_verify.cpp. More...
 
ErrorStack verify_single_thread (thread::Thread *context)
 
ErrorStack verify_single_thread_intermediate (Engine *engine, HashIntermediatePage *page)
 
ErrorStack verify_single_thread_data (Engine *engine, HashDataPage *head)
 
ErrorStack hcc_reset_all_temperature_stat ()
 For stupid reasons (I'm lazy!) these are defined in _debug.cpp. More...
 
ErrorStack hcc_reset_all_temperature_stat_intermediate (VolatilePagePointer intermediate_page_id)
 
ErrorStack hcc_reset_all_temperature_stat_data (VolatilePagePointer head_page_id)
 
ErrorStack debugout_single_thread (Engine *engine, bool volatile_only, bool intermediate_only, uint32_t max_pages)
 These are defined in hash_storage_debug.cpp. More...
 
ErrorStack debugout_single_thread_intermediate (Engine *engine, cache::SnapshotFileSet *fileset, HashIntermediatePage *parent, bool follow_volatile, bool intermediate_only, uint32_t *remaining_pages)
 
ErrorStack debugout_single_thread_data (Engine *engine, cache::SnapshotFileSet *fileset, HashDataPage *head, bool follow_volatile, uint32_t *remaining_pages)
 
ErrorStack create (const HashMetadata &metadata)
 
ErrorStack load (const StorageControlBlock &snapshot_block)
 
ErrorStack drop ()
 
bool exists () const
 
StorageId get_id () const
 
const StorageNameget_name () const
 
const HashMetadataget_meta () const
 
uint8_t get_levels () const
 
HashBin get_bin_count () const
 
uint8_t get_bin_bits () const
 
uint8_t get_bin_shifts () const
 
ErrorCode get_record (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, void *payload, uint16_t *payload_capacity, bool read_only)
 
template<typename PAYLOAD >
ErrorCode get_record_primitive (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, PAYLOAD *payload, uint16_t payload_offset, bool read_only)
 
ErrorCode get_record_part (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, void *payload, uint16_t payload_offset, uint16_t payload_count, bool read_only)
 
ErrorCode register_record_write_log (thread::Thread *context, const RecordLocation &location, log::RecordLogType *log_entry)
 Used in the following methods. More...
 
ErrorCode insert_record (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, const void *payload, uint16_t payload_count, uint16_t physical_payload_hint)
 
ErrorCode delete_record (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo)
 
ErrorCode upsert_record (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, const void *payload, uint16_t payload_count, uint16_t physical_payload_hint)
 
ErrorCode overwrite_record (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, const void *payload, uint16_t payload_offset, uint16_t payload_count)
 
template<typename PAYLOAD >
ErrorCode overwrite_record_primitive (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, PAYLOAD payload, uint16_t payload_offset)
 
template<typename PAYLOAD >
ErrorCode increment_record (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, PAYLOAD *value, uint16_t payload_offset)
 
ErrorCode get_root_page (thread::Thread *context, bool for_write, HashIntermediatePage **root)
 Retrieves the root page of this storage. More...
 
ErrorCode follow_page (thread::Thread *context, bool for_write, HashIntermediatePage *parent, uint16_t index_in_parent, Page **page)
 for non-root More...
 
ErrorCode follow_page_bin_head (thread::Thread *context, bool for_write, HashIntermediatePage *parent, uint16_t index_in_parent, Page **page)
 subroutine to follow a pointer to head of bin from a volatile parent More...
 
ErrorCode locate_bin (thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
 Find a pointer to the bin that contains records for the hash. More...
 
ErrorCode locate_record (thread::Thread *context, bool for_write, bool physical_only, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
 Usually follows locate_bin to locate the exact physical record for the key, or create a new one if not exists (only when for_write). More...
 
ErrorCode locate_record_physical_only (thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
 locate_record()'s physical_only version. More...
 
ErrorCode locate_record_logical (thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
 locate_record()'s logical+physical version. More...
 
ErrorCode locate_record_in_snapshot (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
 Simpler version of locate_record for when we are in snapshot world. More...
 
ErrorCode locate_record_reserve_physical (thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, uint16_t payload_length, HashDataPage **page_in_out, uint16_t examined_records, DataPageSlotIndex *new_location)
 Subroutine of locate_record() to create/migrate a physical record of the given key in the page or its next pages. More...
 
- Public Member Functions inherited from foedus::Attachable< HashStorageControlBlock >
 Attachable ()
 
 Attachable (Engine *engine)
 
 Attachable (Engine *engine, HashStorageControlBlock *control_block)
 
 Attachable (HashStorageControlBlock *control_block)
 
 Attachable (const Attachable &other)
 
virtual ~Attachable ()
 
Attachableoperator= (const Attachable &other)
 
virtual void attach (HashStorageControlBlock *control_block)
 Attaches to the given shared memory. More...
 
bool is_attached () const
 Returns whether the object has been already attached to some shared memory. More...
 
HashStorageControlBlock * get_control_block () const
 
Engineget_engine () const
 
void set_engine (Engine *engine)
 

Additional Inherited Members

- Protected Attributes inherited from foedus::Attachable< HashStorageControlBlock >
Engineengine_
 Most attachable object stores an engine pointer (local engine), so we define it here. More...
 
HashStorageControlBlock * control_block_
 The shared data on shared memory that has been initialized in some SOC or master engine. More...
 

Constructor & Destructor Documentation

foedus::storage::hash::HashStoragePimpl::HashStoragePimpl ( )
inline

Definition at line 95 of file hash_storage_pimpl.hpp.

95 : Attachable<HashStorageControlBlock>() {}
foedus::storage::hash::HashStoragePimpl::HashStoragePimpl ( HashStorage storage)
inlineexplicit

Definition at line 96 of file hash_storage_pimpl.hpp.

97  : Attachable<HashStorageControlBlock>(
98  storage->get_engine(),
99  storage->get_control_block()) {}

Member Function Documentation

ErrorStack foedus::storage::hash::HashStoragePimpl::create ( const HashMetadata metadata)

Definition at line 76 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashIntermediatePage::assert_range(), foedus::storage::hash::bins_to_level(), foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::Attachable< HashStorageControlBlock >::engine_, ERROR_STACK, ERROR_STACK_MSG, exists(), foedus::storage::hash::fanout_power(), get_bin_bits(), foedus::storage::hash::HashMetadata::get_bin_count(), get_bin_count(), get_id(), get_levels(), foedus::Engine::get_memory_manager(), get_name(), foedus::memory::EngineMemory::get_node_memory(), foedus::Engine::get_options(), foedus::memory::PagePool::get_resolver(), foedus::memory::NumaNodeMemoryRef::get_volatile_pool(), foedus::memory::PagePool::grab_one(), foedus::storage::hash::HashIntermediatePage::initialize_volatile_page(), foedus::kErrorCodeStrAlreadyExists, foedus::kErrorCodeStrHashBinsTooMany, foedus::storage::kExists, foedus::kRetOk, foedus::storage::StorageOptions::partitioner_data_memory_mb_, foedus::memory::LocalPageResolver::resolve_offset_newpage(), foedus::EngineOptions::storage_, and WRAP_ERROR_CODE.

Referenced by foedus::storage::hash::HashStorage::create().

76  {
77  if (exists()) {
78  LOG(ERROR) << "This hash-storage already exists: " << get_name();
80  }
81 
82  // hash-specific check.
83  // Due to the current design of hash_partitioner, we spend hashbins bytes
84  // out of the partitioner memory.
85  uint64_t required_partitioner_bytes = metadata.get_bin_count() + 4096ULL;
86  uint64_t partitioner_bytes
88  // we don't bother checking other storages' consumption. the config might later change anyways.
89  // Instead, leave a bit of margin (25%) for others.
90  if (partitioner_bytes < required_partitioner_bytes * 1.25) {
91  std::stringstream str;
92  str << metadata << ".\n"
93  << "To accomodate this number of hash bins, partitioner_data_memory_mb_ must be"
94  << " at least " << (required_partitioner_bytes * 1.25 / (1ULL << 20));
95  return ERROR_STACK_MSG(kErrorCodeStrHashBinsTooMany, str.str().c_str());
96  }
97 
98  control_block_->meta_ = metadata;
99  LOG(INFO) << "Newly creating an hash-storage " << get_name();
100  control_block_->bin_count_ = 1ULL << get_bin_bits();
101  control_block_->levels_ = bins_to_level(control_block_->bin_count_);
102  ASSERT_ND(control_block_->levels_ >= 1U);
103  ASSERT_ND(control_block_->bin_count_ <= fanout_power(control_block_->levels_));
104  ASSERT_ND(control_block_->bin_count_ > fanout_power(control_block_->levels_ - 1U));
105  LOG(INFO) << "bin_count=" << get_bin_count() << ", levels=" << static_cast<int>(get_levels());
106 
107  // small number of root pages. we should at least have that many free pages.
108  // so far grab all of them from node 0. no round robbin
109  const uint16_t kTheNode = 0;
110  memory::PagePool* pool
112  const memory::LocalPageResolver &local_resolver = pool->get_resolver();
113 
114  // allocate only the root page
115  memory::PagePoolOffset root_offset;
116  WRAP_ERROR_CODE(pool->grab_one(&root_offset));
117  ASSERT_ND(root_offset);
118  HashIntermediatePage* root_page = reinterpret_cast<HashIntermediatePage*>(
119  local_resolver.resolve_offset_newpage(root_offset));
120  control_block_->root_page_pointer_.snapshot_pointer_ = 0;
121  control_block_->root_page_pointer_.volatile_pointer_.set(kTheNode, root_offset);
122  root_page->initialize_volatile_page(
123  get_id(),
124  control_block_->root_page_pointer_.volatile_pointer_,
125  nullptr,
126  control_block_->levels_ - 1U,
127  0);
128  root_page->assert_range();
129 
130  LOG(INFO) << "Newly created an hash-storage " << get_name();
131  control_block_->status_ = kExists;
132  return kRetOk;
133 }
0x080D : "STORAGE: HASH: Number of hash-bins too large compared to storage.partitioner_data_memory_mb...
Definition: error_code.hpp:179
#define ERROR_STACK(e)
Instantiates ErrorStack with the given foedus::error_code, creating an error stack with the current f...
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
The storage has been created and ready for use.
Definition: storage_id.hpp:158
uint8_t bins_to_level(uint64_t bins)
Definition: hash_id.hpp:90
const EngineOptions & get_options() const
Definition: engine.cpp:39
uint32_t partitioner_data_memory_mb_
Size in MB of a shared memory buffer allocated for all partitioners during log gleaning.
uint64_t fanout_power(uint8_t exponent)
Definition: hash_id.hpp:56
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
storage::StorageOptions storage_
0x0802 : "STORAGE: This storage already exists" .
Definition: error_code.hpp:168
NumaNodeMemoryRef * get_node_memory(foedus::thread::ThreadGroupId group) const
const ErrorStack kRetOk
Normal return value for no-error case.
#define ERROR_STACK_MSG(e, m)
Overload of ERROR_STACK(e) to receive a custom error message.
const LocalPageResolver & get_resolver() const
Gives an object to resolve an offset in this page pool (thus local) to an actual pointer and vice ver...
Definition: page_pool.cpp:146
#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 WRAP_ERROR_CODE(x)
Same as CHECK_ERROR(x) except it receives only an error code, thus more efficient.
memory::EngineMemory * get_memory_manager() const
See Memory Manager.
Definition: engine.cpp:50

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::debugout_single_thread ( Engine engine,
bool  volatile_only,
bool  intermediate_only,
uint32_t  max_pages 
)

These are defined in hash_storage_debug.cpp.

Definition at line 53 of file hash_storage_debug.cpp.

References foedus::storage::hash::TmpSnashotPage::as_intermediate(), CHECK_ERROR, foedus::Attachable< HashStorageControlBlock >::control_block_, debugout_single_thread_intermediate(), foedus::Attachable< HashStorageControlBlock >::engine_, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::Engine::get_memory_manager(), foedus::storage::hash::TmpSnashotPage::init(), foedus::DefaultInitializable::initialize(), foedus::storage::VolatilePagePointer::is_null(), foedus::kRetOk, foedus::UninitializeGuard::kWarnIfUninitializeError, foedus::memory::GlobalVolatilePageResolver::resolve_offset(), foedus::storage::DualPagePointer::snapshot_pointer_, foedus::DefaultInitializable::uninitialize(), and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by foedus::storage::hash::HashStorage::debugout_single_thread().

57  {
58  LOG(INFO) << "**"
59  << std::endl << "***************************************************************"
60  << std::endl << "*** Dumping " << HashStorage(engine_, control_block_) << " in details. "
61  << std::endl << "*** volatile_only=" << volatile_only
62  << ", intermediate_only=" << intermediate_only << ", max_pages=" << max_pages
63  << std::endl << "***************************************************************";
64 
65  if (max_pages == 0) {
66  return kRetOk;
67  }
68 
69  cache::SnapshotFileSet files(engine);
70  CHECK_ERROR(files.initialize());
71  UninitializeGuard files_guard(&files, UninitializeGuard::kWarnIfUninitializeError);
72 
73  LOG(INFO) << "First, dumping volatile pages...";
74  DualPagePointer pointer = control_block_->root_page_pointer_;
75  if (pointer.volatile_pointer_.is_null()) {
76  LOG(INFO) << "No volatile pages.";
77  } else {
78  HashIntermediatePage* root = reinterpret_cast<HashIntermediatePage*>(
79  engine->get_memory_manager()->get_global_volatile_page_resolver().resolve_offset(
80  pointer.volatile_pointer_));
81  uint32_t remaining = max_pages - 1U;
83  engine,
84  &files,
85  root,
86  true,
87  intermediate_only,
88  &remaining));
89  }
90  LOG(INFO) << "Dumped volatile pages.";
91  if (!volatile_only) {
92  LOG(INFO) << "Now dumping snapshot pages...";
93  if (pointer.snapshot_pointer_ == 0) {
94  LOG(INFO) << "No snapshot pages.";
95  } else {
96  TmpSnashotPage tmp;
97  CHECK_ERROR(tmp.init(&files, pointer.snapshot_pointer_));
98  HashIntermediatePage* root = tmp.as_intermediate();
99  uint32_t remaining = max_pages - 1U;
101  engine,
102  &files,
103  root,
104  false,
105  intermediate_only,
106  &remaining));
107  }
108  LOG(INFO) << "Dumped snapshot pages.";
109  }
110 
111  CHECK_ERROR(files.uninitialize());
112  return kRetOk;
113 }
Automatically calls if uninitialize() wasn't called when it gets out of scope, and just complains whe...
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
ErrorStack debugout_single_thread_intermediate(Engine *engine, cache::SnapshotFileSet *fileset, HashIntermediatePage *parent, bool follow_volatile, bool intermediate_only, uint32_t *remaining_pages)
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::debugout_single_thread_data ( Engine engine,
cache::SnapshotFileSet fileset,
HashDataPage head,
bool  follow_volatile,
uint32_t *  remaining_pages 
)

Definition at line 181 of file hash_storage_debug.cpp.

References foedus::storage::hash::TmpSnashotPage::as_data(), CHECK_ERROR, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::Engine::get_memory_manager(), foedus::storage::hash::TmpSnashotPage::init(), foedus::storage::VolatilePagePointer::is_null(), foedus::kRetOk, foedus::storage::DualPagePointer::snapshot_pointer_, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by debugout_single_thread_intermediate().

186  {
187  TmpSnashotPage tmp;
188  const auto& resolver = engine->get_memory_manager()->get_global_volatile_page_resolver();
189  for (HashDataPage* cur = head; cur;) {
190  LOG(INFO) << *cur;
191  if ((*remaining) == 0 || --(*remaining) == 0) {
192  LOG(INFO) << "Reached write-out max. skip the following";
193  return kRetOk;
194  }
195 
196  // here, we take a copy of pointer so that "cur" might be okay to become invalid after here.
197  DualPagePointer pointer = cur->next_page();
198  cur = nullptr;
199  if (follow_volatile) {
200  if (!pointer.volatile_pointer_.is_null()) {
201  cur = reinterpret_cast<HashDataPage*>(resolver.resolve_offset(pointer.volatile_pointer_));
202  }
203  } else {
204  if (pointer.snapshot_pointer_) {
205  CHECK_ERROR(tmp.init(files, pointer.snapshot_pointer_)); // note, this overwrites tmp
206  cur = tmp.as_data();
207  }
208  }
209  }
210  return kRetOk;
211 }
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::debugout_single_thread_intermediate ( Engine engine,
cache::SnapshotFileSet fileset,
HashIntermediatePage parent,
bool  follow_volatile,
bool  intermediate_only,
uint32_t *  remaining_pages 
)

Definition at line 116 of file hash_storage_debug.cpp.

References foedus::storage::hash::TmpSnashotPage::as_data(), foedus::storage::hash::TmpSnashotPage::as_intermediate(), CHECK_ERROR, debugout_single_thread_data(), foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::Engine::get_memory_manager(), foedus::storage::hash::HashIntermediatePage::get_pointer(), foedus::storage::hash::TmpSnashotPage::init(), foedus::storage::VolatilePagePointer::is_null(), foedus::kRetOk, foedus::storage::DualPagePointer::snapshot_pointer_, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by debugout_single_thread().

122  {
123  if (((*remaining) == 0) || --(*remaining) == 0) {
124  LOG(INFO) << "Reached write-out max. skip the following";
125  return kRetOk;
126  }
127 
128  LOG(INFO) << *parent;
129  bool bottom = parent->get_level() == 0;
130  if (bottom && intermediate_only) {
131  return kRetOk;
132  }
133 
134  const auto& resolver = engine->get_memory_manager()->get_global_volatile_page_resolver();
135  TmpSnashotPage tmp;
136  for (uint8_t i = 0; i < kHashIntermediatePageFanout && ((*remaining) > 0); ++i) {
137  DualPagePointer pointer = parent->get_pointer(i);
138  if (follow_volatile) {
139  if (pointer.volatile_pointer_.is_null()) {
140  continue;
141  }
142  if (bottom) {
143  HashDataPage* page = reinterpret_cast<HashDataPage*>(
144  resolver.resolve_offset(pointer.volatile_pointer_));
145  CHECK_ERROR(debugout_single_thread_data(engine, files, page, true, remaining));
146  } else {
147  HashIntermediatePage* page = reinterpret_cast<HashIntermediatePage*>(
148  resolver.resolve_offset(pointer.volatile_pointer_));
150  engine,
151  files,
152  page,
153  true,
154  intermediate_only,
155  remaining));
156  }
157  } else {
158  if (pointer.snapshot_pointer_ == 0) {
159  continue;
160  }
161  CHECK_ERROR(tmp.init(files, pointer.snapshot_pointer_));
162  if (bottom) {
163  HashDataPage* page = tmp.as_data();
164  CHECK_ERROR(debugout_single_thread_data(engine, files, page, false, remaining));
165  } else {
166  HashIntermediatePage* page = tmp.as_intermediate();
168  engine,
169  files,
170  page,
171  false,
172  intermediate_only,
173  remaining));
174  }
175  }
176  }
177 
178  return kRetOk;
179 }
ErrorStack debugout_single_thread_data(Engine *engine, cache::SnapshotFileSet *fileset, HashDataPage *head, bool follow_volatile, uint32_t *remaining_pages)
ErrorStack debugout_single_thread_intermediate(Engine *engine, cache::SnapshotFileSet *fileset, HashIntermediatePage *parent, bool follow_volatile, bool intermediate_only, uint32_t *remaining_pages)
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::delete_record ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo 
)
See also
foedus::storage::hash::HashStorage::delete_record()

Definition at line 356 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashCommonLogType::calculate_log_length(), CHECK_ERROR_CODE, get_bin_bits(), get_id(), foedus::thread::Thread::get_thread_log_buffer(), foedus::storage::hash::HashCombo::hash_, foedus::xct::XctId::is_deleted(), foedus::storage::hash::RecordLocation::is_found(), foedus::kErrorCodeStrKeyNotFound, locate_bin(), locate_record_logical(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::hash::HashDeleteLogType::populate(), register_record_write_log(), and foedus::log::ThreadLogBuffer::reserve_new_log().

Referenced by foedus::storage::hash::HashStorage::delete_record().

360  {
361  HashDataPage* bin_head;
362  CHECK_ERROR_CODE(locate_bin(context, true, combo, &bin_head));
363  ASSERT_ND(bin_head);
364  RecordLocation location;
366  context,
367  true,
368  false,
369  0,
370  key,
371  key_length,
372  combo,
373  bin_head,
374  &location));
375 
376  if (!location.is_found()) {
377  return kErrorCodeStrKeyNotFound; // protected by page version set, so we are done
378  } else if (location.observed_.is_deleted()) {
379  return kErrorCodeStrKeyNotFound; // protected by the read set
380  }
381 
382  uint16_t log_length = HashDeleteLogType::calculate_log_length(key_length, 0);
383  HashDeleteLogType* log_entry = reinterpret_cast<HashDeleteLogType*>(
384  context->get_thread_log_buffer().reserve_new_log(log_length));
385  log_entry->populate(get_id(), key, key_length, get_bin_bits(), combo.hash_);
386 
387  return register_record_write_log(context, location, log_entry);
388 }
0x080C : "STORAGE: This key is not found in this storage" .
Definition: error_code.hpp:178
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
ErrorCode register_record_write_log(thread::Thread *context, const RecordLocation &location, log::RecordLogType *log_entry)
Used in the following methods.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
static uint16_t calculate_log_length(uint16_t key_length, uint16_t payload_count) __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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::drop ( )

Definition at line 59 of file hash_storage_pimpl.cpp.

References foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::Attachable< HashStorageControlBlock >::engine_, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::Engine::get_memory_manager(), get_name(), foedus::kRetOk, foedus::storage::hash::HashIntermediatePage::release_pages_recursive_parallel(), and foedus::memory::GlobalVolatilePageResolver::resolve_offset().

Referenced by foedus::storage::hash::HashStorage::drop().

59  {
60  LOG(INFO) << "Uninitializing an hash-storage " << get_name();
61 
62  if (!control_block_->root_page_pointer_.volatile_pointer_.is_null()) {
63  // release volatile pages
64  const memory::GlobalVolatilePageResolver& page_resolver
66  HashIntermediatePage* root = reinterpret_cast<HashIntermediatePage*>(
67  page_resolver.resolve_offset(control_block_->root_page_pointer_.volatile_pointer_));
68  root->release_pages_recursive_parallel(engine_);
69  control_block_->root_page_pointer_.volatile_pointer_.word = 0;
70  }
71 
72  return kRetOk;
73 }
const GlobalVolatilePageResolver & get_global_volatile_page_resolver() const
Returns the page resolver to convert volatile page ID to page pointer.
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
const ErrorStack kRetOk
Normal return value for no-error case.
memory::EngineMemory * get_memory_manager() const
See Memory Manager.
Definition: engine.cpp:50

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::storage::hash::HashStoragePimpl::exists ( ) const
inline

Definition at line 160 of file hash_storage_pimpl.hpp.

References foedus::Attachable< HashStorageControlBlock >::control_block_.

Referenced by create().

160 { return control_block_->exists(); }
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::follow_page ( thread::Thread context,
bool  for_write,
HashIntermediatePage parent,
uint16_t  index_in_parent,
Page **  page 
)

for non-root

Definition at line 625 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashBinRange::begin_, CHECK_ERROR_CODE, foedus::thread::Thread::find_or_read_a_snapshot_page(), follow_page_bin_head(), foedus::thread::Thread::follow_page_pointer(), foedus::storage::hash::HashIntermediatePage::get_bin_range(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::storage::PageHeader::get_page_type(), foedus::storage::hash::HashIntermediatePage::get_pointer(), foedus::storage::hash::hash_intermediate_volatile_page_init(), foedus::storage::hash::HashIntermediatePage::header(), foedus::kErrorCodeOk, foedus::storage::kHashDataPageType, foedus::storage::hash::kHashIntermediatePageFanout, foedus::storage::kHashIntermediatePageType, foedus::storage::PageHeader::snapshot_, and foedus::storage::DualPagePointer::snapshot_pointer_.

Referenced by locate_bin().

630  {
631  ASSERT_ND(index_in_parent < kHashIntermediatePageFanout);
632  ASSERT_ND(parent);
633  ASSERT_ND(parent->header().get_page_type() == kHashIntermediatePageType);
634  bool is_parent_snapshot = parent->header().snapshot_;
635  uint8_t parent_level = parent->get_level();
636  ASSERT_ND(!is_parent_snapshot || !for_write);
637 
638  DualPagePointer& pointer = parent->get_pointer(index_in_parent);
639  bool child_intermediate = (parent_level > 0);
640  if (is_parent_snapshot) {
641  // if we are in snapshot world, there is no choice.
642  // separating this out also handles SI level well.
643  ASSERT_ND(!for_write);
644  if (pointer.snapshot_pointer_ == 0) {
645  *page = nullptr;
646  } else {
647  CHECK_ERROR_CODE(context->find_or_read_a_snapshot_page(pointer.snapshot_pointer_, page));
648  ASSERT_ND((*page)->get_header().snapshot_);
649  }
650  } else if (child_intermediate) {
651  CHECK_ERROR_CODE(context->follow_page_pointer(
653  !for_write, // null page is a valid result only for reads ("not found")
654  for_write,
655  true, // if we jump to snapshot page, we need to add it to pointer set for serializability.
656  &pointer,
657  page,
658  reinterpret_cast<Page*>(parent),
659  index_in_parent));
660  } else {
661  // we are in a level-0 volatile page. so the pointee is a bin-head.
662  // we need a bit special handling in this case
663  CHECK_ERROR_CODE(follow_page_bin_head(context, for_write, parent, index_in_parent, page));
664  }
665 
666  if (*page) {
667  if (child_intermediate) {
668  ASSERT_ND((*page)->get_page_type() == kHashIntermediatePageType);
669  ASSERT_ND((*page)->get_header().get_in_layer_level() + 1U == parent_level);
670  } else {
671  ASSERT_ND((*page)->get_page_type() == kHashDataPageType);
672  ASSERT_ND(reinterpret_cast<HashDataPage*>(*page)->get_bin()
673  == parent->get_bin_range().begin_ + index_in_parent);
674  }
675  }
676  return kErrorCodeOk;
677 }
ErrorCode follow_page_bin_head(thread::Thread *context, bool for_write, HashIntermediatePage *parent, uint16_t index_in_parent, Page **page)
subroutine to follow a pointer to head of bin from a volatile parent
0 means no-error.
Definition: error_code.hpp:87
void hash_intermediate_volatile_page_init(const VolatilePageInitArguments &args)
volatile page initialize callback for HashIntermediatePage.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
const uint8_t kHashIntermediatePageFanout
Number of pointers in an intermediate page of hash storage.
Definition: hash_id.hpp:49
#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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::follow_page_bin_head ( thread::Thread context,
bool  for_write,
HashIntermediatePage parent,
uint16_t  index_in_parent,
Page **  page 
)

subroutine to follow a pointer to head of bin from a volatile parent

Definition at line 679 of file hash_storage_pimpl.cpp.

References ASSERT_ND, CHECK_ERROR_CODE, foedus::storage::VolatilePagePointer::clear(), foedus::storage::construct_volatile_page_pointer(), foedus::thread::Thread::find_or_read_a_snapshot_page(), foedus::thread::Thread::follow_page_pointer(), foedus::storage::hash::HashDataPage::get_bin(), foedus::thread::Thread::get_current_xct(), foedus::xct::Xct::get_isolation_level(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::thread::Thread::get_local_volatile_page_resolver(), foedus::thread::Thread::get_numa_node(), foedus::storage::VolatilePagePointer::get_numa_node(), foedus::storage::VolatilePagePointer::get_offset(), foedus::storage::PageHeader::get_page_type(), foedus::storage::hash::HashIntermediatePage::get_pointer_address(), foedus::thread::Thread::get_thread_memory(), foedus::memory::NumaCoreMemory::grab_free_volatile_page_pointer(), foedus::storage::hash::hash_data_volatile_page_init(), foedus::storage::hash::HashIntermediatePage::header(), foedus::storage::hash::HashDataPage::header(), foedus::storage::VolatilePagePointer::is_null(), foedus::kErrorCodeMemoryNoFreePages, foedus::kErrorCodeOk, foedus::storage::kHashIntermediatePageType, foedus::storage::kPageSize, foedus::xct::kSerializable, foedus::xct::kSnapshot, foedus::storage::hash::HashDataPage::next_page(), foedus::storage::hash::HashDataPage::next_page_address(), foedus::storage::PageHeader::page_id_, foedus::memory::NumaCoreMemory::release_free_volatile_page(), foedus::thread::Thread::resolve(), foedus::thread::Thread::resolve_cast(), foedus::memory::LocalPageResolver::resolve_offset_newpage(), foedus::storage::PageHeader::snapshot_, foedus::storage::DualPagePointer::snapshot_pointer_, UNLIKELY, foedus::storage::DualPagePointer::volatile_pointer_, and foedus::storage::VolatilePagePointer::word.

Referenced by follow_page().

684  {
685  // do we have to newly create a volatile version of the pointed bin?
686  ASSERT_ND(!parent->header().snapshot_);
687  ASSERT_ND(parent->header().get_page_type() == kHashIntermediatePageType);
688  ASSERT_ND(parent->get_level() == 0);
689  xct::Xct& cur_xct = context->get_current_xct();
690  xct::IsolationLevel isolation = cur_xct.get_isolation_level();
691  DualPagePointer* pointer = parent->get_pointer_address(index_in_parent);
692 
693  // otherwise why in volatile page.
694  ASSERT_ND(for_write || isolation != xct::kSnapshot || pointer->snapshot_pointer_ == 0);
695  // in other words, we can safely "prefer" volatile page here.
696  if (!pointer->volatile_pointer_.is_null()) {
697  *page = context->resolve(pointer->volatile_pointer_);
698  } else {
699  SnapshotPagePointer snapshot_pointer = pointer->snapshot_pointer_;
700  if (!for_write) {
701  // reads don't have to create a new page. easy
702  if (snapshot_pointer == 0) {
703  *page = nullptr;
704  } else {
705  CHECK_ERROR_CODE(context->find_or_read_a_snapshot_page(snapshot_pointer, page));
706  }
707 
708  if (isolation == xct::kSerializable) {
709  VolatilePagePointer null_pointer;
710  null_pointer.clear();
711  cur_xct.add_to_pointer_set(&(pointer->volatile_pointer_), null_pointer);
712  }
713  } else {
714  // writes need the volatile version.
715  if (snapshot_pointer == 0) {
716  // The bin is completely empty. we just make a new empty page.
717  CHECK_ERROR_CODE(context->follow_page_pointer(
719  false,
720  true,
721  true,
722  pointer,
723  page,
724  reinterpret_cast<Page*>(parent),
725  index_in_parent));
726  } else {
727  // Otherwise, we must create a volatile version of the existing page.
728  // a special rule for hash storage in this case: we create/drop volatile versions
729  // in the granularity of hash bin. all or nothing.
730  // thus, not just the head page of the bin, we have to volatilize the entire bin.
731  memory::NumaCoreMemory* core_memory = context->get_thread_memory();
732  const memory::LocalPageResolver& local_resolver
733  = context->get_local_volatile_page_resolver();
734  VolatilePagePointer head_page_id = core_memory->grab_free_volatile_page_pointer();
735  const auto offset = head_page_id.get_offset();
736  if (UNLIKELY(head_page_id.is_null())) {
738  }
739 
740  HashDataPage* head_page
741  = reinterpret_cast<HashDataPage*>(local_resolver.resolve_offset_newpage(offset));
742  storage::Page* snapshot_head;
743  ErrorCode code = context->find_or_read_a_snapshot_page(snapshot_pointer, &snapshot_head);
744  if (code != kErrorCodeOk) {
745  core_memory->release_free_volatile_page(offset);
746  return code;
747  }
748 
749  std::memcpy(head_page, snapshot_head, kPageSize);
750  ASSERT_ND(head_page->header().snapshot_);
751  head_page->header().snapshot_ = false;
752  head_page->header().page_id_ = head_page_id.word;
753 
754  // load following pages. hopefully this is a rare case.
755  ErrorCode last_error = kErrorCodeOk;
756  if (UNLIKELY(head_page->next_page().snapshot_pointer_)) {
757  HashDataPage* cur_page = head_page;
758  while (true) {
759  ASSERT_ND(last_error == kErrorCodeOk);
760  SnapshotPagePointer next = cur_page->next_page().snapshot_pointer_;
761  if (next == 0) {
762  break;
763  }
764 
765  DVLOG(1) << "Following next-link in hash data pages. Hopefully it's not that long..";
766  VolatilePagePointer next_page_id = core_memory->grab_free_volatile_page_pointer();
767  memory::PagePoolOffset next_offset = next_page_id.get_offset();
768  if (UNLIKELY(next_page_id.is_null())) {
769  // we have to release preceding pages too
770  last_error = kErrorCodeMemoryNoFreePages;
771  break;
772  }
773  HashDataPage* next_page
774  = reinterpret_cast<HashDataPage*>(local_resolver.resolve_offset_newpage(next_offset));
775  // immediately install because:
776  // 1) we don't have any race here, 2) we need to follow them to release on error.
777  DualPagePointer* target = cur_page->next_page_address();
778  ASSERT_ND(target->volatile_pointer_.is_null());
779  target->volatile_pointer_ = next_page_id;
780  target->snapshot_pointer_ = 0; // will be no longer used, let's clear them
781 
782  storage::Page* snapshot_page;
783  last_error = context->find_or_read_a_snapshot_page(next, &snapshot_page);
784  if (last_error != kErrorCodeOk) {
785  break;
786  }
787  std::memcpy(next_page, snapshot_page, kPageSize);
788  ASSERT_ND(next_page->header().snapshot_);
789  ASSERT_ND(next_page->get_bin() == cur_page->get_bin());
790  next_page->header().snapshot_ = false;
791  next_page->header().page_id_ = next_page_id.word;
792  cur_page = next_page;
793  }
794  }
795 
796  // all rihgt, now atomically install the pointer to the volatile head page.
797  bool must_release_pages = false;
798  if (last_error == kErrorCodeOk) {
799  uint64_t expected = 0;
800  if (assorted::raw_atomic_compare_exchange_strong<uint64_t>(
801  &(pointer->volatile_pointer_.word),
802  &expected,
803  head_page_id.word)) {
804  // successfully installed the head pointer. fine.
805  *page = reinterpret_cast<Page*>(head_page);
806  } else {
807  ASSERT_ND(expected);
808  // someone else has installed it, which is also fine.
809  // but, we must release pages we created (which turned out to be a waste effort)
810  LOG(INFO) << "Interesting. Someone else has installed a volatile version.";
811  *page = context->resolve(pointer->volatile_pointer_);
812  must_release_pages = true;
813  }
814  } else {
815  must_release_pages = true;
816  }
817 
818  if (must_release_pages) {
819  HashDataPage* cur = head_page;
820  while (true) {
821  VolatilePagePointer cur_id = construct_volatile_page_pointer(cur->header().page_id_);
822  ASSERT_ND(cur_id.get_numa_node() == context->get_numa_node());
823  ASSERT_ND(!cur_id.is_null());
824  // retrieve next_id BEFORE releasing (revoking) cur page.
825  VolatilePagePointer next_id = cur->next_page().volatile_pointer_;
826  core_memory->release_free_volatile_page(cur_id.get_offset());
827  if (next_id.is_null()) {
828  break;
829  }
830  cur = context->resolve_cast<HashDataPage>(next_id);
831  }
832  }
833 
834  CHECK_ERROR_CODE(last_error);
835  }
836  }
837  }
838 
839  return kErrorCodeOk;
840 }
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
Snapshot isolation (SI), meaning the transaction reads a consistent and complete image of the databas...
Definition: xct_id.hpp:78
0 means no-error.
Definition: error_code.hpp:87
uint64_t SnapshotPagePointer
Page ID of a snapshot page.
Definition: storage_id.hpp:79
0x0301 : "MEMORY : Not enough free volatile pages. Check the config of MemoryOptions" ...
Definition: error_code.hpp:142
IsolationLevel
Specifies the level of isolation during transaction processing.
Definition: xct_id.hpp:55
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
void hash_data_volatile_page_init(const VolatilePageInitArguments &args)
volatile page initialize callback for HashDataPage.
VolatilePagePointer construct_volatile_page_pointer(uint64_t word)
Definition: storage_id.hpp:230
#define UNLIKELY(x)
Hints that x is highly likely false.
Definition: compiler.hpp:104
#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
const uint16_t kPageSize
A constant defining the page size (in bytes) of both snapshot pages and volatile pages.
Definition: storage_id.hpp:45
ErrorCode
Enum of error codes defined in error_code.xmacro.
Definition: error_code.hpp:85
Protects against all anomalies in all situations.
Definition: xct_id.hpp:86

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t foedus::storage::hash::HashStoragePimpl::get_bin_bits ( ) const
inline

Definition at line 166 of file hash_storage_pimpl.hpp.

References foedus::storage::hash::HashMetadata::bin_bits_, and get_meta().

Referenced by create(), delete_record(), increment_record(), insert_record(), load(), overwrite_record(), and upsert_record().

166 { return get_meta().bin_bits_; }
uint8_t bin_bits_
Number of bins in exponent of two.
const HashMetadata & get_meta() const

Here is the call graph for this function:

Here is the caller graph for this function:

HashBin foedus::storage::hash::HashStoragePimpl::get_bin_count ( ) const
inline

Definition at line 165 of file hash_storage_pimpl.hpp.

References foedus::storage::hash::HashMetadata::get_bin_count(), and get_meta().

Referenced by create().

165 { return get_meta().get_bin_count(); }
const HashMetadata & get_meta() const
uint64_t get_bin_count() const
Number of bins in this hash storage.

Here is the call graph for this function:

Here is the caller graph for this function:

uint8_t foedus::storage::hash::HashStoragePimpl::get_bin_shifts ( ) const
inline

Definition at line 167 of file hash_storage_pimpl.hpp.

References foedus::storage::hash::HashMetadata::get_bin_shifts(), and get_meta().

167 { return get_meta().get_bin_shifts(); }
const HashMetadata & get_meta() const

Here is the call graph for this function:

StorageId foedus::storage::hash::HashStoragePimpl::get_id ( ) const
inline

Definition at line 161 of file hash_storage_pimpl.hpp.

References foedus::Attachable< HashStorageControlBlock >::control_block_.

Referenced by create(), delete_record(), increment_record(), insert_record(), overwrite_record(), register_record_write_log(), and upsert_record().

161 { return control_block_->meta_.id_; }
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111

Here is the caller graph for this function:

uint8_t foedus::storage::hash::HashStoragePimpl::get_levels ( ) const
inline

Definition at line 164 of file hash_storage_pimpl.hpp.

References foedus::Attachable< HashStorageControlBlock >::control_block_.

Referenced by create().

164 { return control_block_->levels_; }
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111

Here is the caller graph for this function:

const HashMetadata& foedus::storage::hash::HashStoragePimpl::get_meta ( ) const
inline

Definition at line 163 of file hash_storage_pimpl.hpp.

References foedus::Attachable< HashStorageControlBlock >::control_block_.

Referenced by get_bin_bits(), get_bin_count(), and get_bin_shifts().

163 { return control_block_->meta_; }
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111

Here is the caller graph for this function:

const StorageName& foedus::storage::hash::HashStoragePimpl::get_name ( ) const
inline

Definition at line 162 of file hash_storage_pimpl.hpp.

References foedus::Attachable< HashStorageControlBlock >::control_block_.

Referenced by create(), drop(), and load().

162 { return control_block_->meta_.name_; }
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::get_record ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
void *  payload,
uint16_t *  payload_capacity,
bool  read_only 
)
See also
foedus::storage::hash::HashStorage::get_record()

Definition at line 166 of file hash_storage_pimpl.cpp.

References CHECK_ERROR_CODE, foedus::storage::hash::RecordLocation::cur_payload_length_, foedus::storage::hash::RecordLocation::get_aligned_key_length(), foedus::storage::hash::RecordLocation::is_found(), foedus::kErrorCodeOk, foedus::kErrorCodeStrKeyNotFound, foedus::kErrorCodeStrTooSmallPayloadBuffer, locate_bin(), locate_record_logical(), and foedus::storage::hash::RecordLocation::record_.

Referenced by foedus::storage::hash::HashStorage::get_record().

173  {
174  HashDataPage* bin_head;
175  CHECK_ERROR_CODE(locate_bin(context, !read_only, combo, &bin_head));
176  if (!bin_head) {
177  return kErrorCodeStrKeyNotFound; // protected by pointer set, so we are done
178  }
179  RecordLocation location;
181  context,
182  !read_only,
183  false,
184  0,
185  key,
186  key_length,
187  combo,
188  bin_head,
189  &location));
190  if (!location.is_found()) {
191  return kErrorCodeStrKeyNotFound; // protected by page version set, so we are done
192  }
193 
194  // here, we do NOT have to do another optimistic-read protocol because we already took
195  // the owner_id into read-set. If this read is corrupted, we will be aware of it at commit time.
196  uint16_t payload_length = location.cur_payload_length_;
197  if (payload_length > *payload_capacity) {
198  // buffer too small
199  DVLOG(0) << "buffer too small??" << payload_length << ":" << *payload_capacity;
200  *payload_capacity = payload_length;
202  }
203 
204  *payload_capacity = payload_length;
205  uint16_t key_offset = location.get_aligned_key_length();
206  std::memcpy(payload, location.record_ + key_offset, payload_length);
207  return kErrorCodeOk;
208 }
0x080C : "STORAGE: This key is not found in this storage" .
Definition: error_code.hpp:178
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
0 means no-error.
Definition: error_code.hpp:87
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
0x0809 : "STORAGE: The record's payload is larger than the buffer" .
Definition: error_code.hpp:175

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::get_record_part ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
void *  payload,
uint16_t  payload_offset,
uint16_t  payload_count,
bool  read_only 
)
See also
foedus::storage::hash::HashStorage::get_record_part()

Definition at line 210 of file hash_storage_pimpl.cpp.

References CHECK_ERROR_CODE, foedus::storage::hash::RecordLocation::cur_payload_length_, foedus::storage::hash::RecordLocation::get_aligned_key_length(), foedus::storage::hash::RecordLocation::is_found(), foedus::kErrorCodeOk, foedus::kErrorCodeStrKeyNotFound, foedus::kErrorCodeStrTooShortPayload, locate_bin(), locate_record_logical(), and foedus::storage::hash::RecordLocation::record_.

Referenced by foedus::storage::hash::HashStorage::get_record_part(), and get_record_primitive().

218  {
219  HashDataPage* bin_head;
220  CHECK_ERROR_CODE(locate_bin(context, !read_only, combo, &bin_head));
221  if (!bin_head) {
222  return kErrorCodeStrKeyNotFound; // protected by pointer set, so we are done
223  }
224  RecordLocation location;
226  context,
227  !read_only,
228  false,
229  0,
230  key,
231  key_length,
232  combo,
233  bin_head,
234  &location));
235  if (!location.is_found()) {
236  return kErrorCodeStrKeyNotFound; // protected by page version set, so we are done
237  }
238 
239  uint16_t payload_length = location.cur_payload_length_;
240  if (payload_length < payload_offset + payload_count) {
241  LOG(WARNING) << "short record " << combo; // probably this is a rare error. so warn.
243  }
244 
245  uint16_t key_offset = location.get_aligned_key_length();
246  std::memcpy(payload, location.record_ + key_offset + payload_offset, payload_count);
247  return kErrorCodeOk;
248 }
0x080A : "STORAGE: The record's payload is smaller than requested" .
Definition: error_code.hpp:176
0x080C : "STORAGE: This key is not found in this storage" .
Definition: error_code.hpp:178
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
0 means no-error.
Definition: error_code.hpp:87
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155

Here is the call graph for this function:

Here is the caller graph for this function:

template<typename PAYLOAD >
ErrorCode foedus::storage::hash::HashStoragePimpl::get_record_primitive ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
PAYLOAD *  payload,
uint16_t  payload_offset,
bool  read_only 
)
inline
See also
foedus::storage::hash::HashStorage::get_record_primitive()

Definition at line 181 of file hash_storage_pimpl.hpp.

References get_record_part().

Referenced by foedus::storage::hash::HashStorage::get_record_primitive().

188  {
189  // at this point, there isn't enough benefit to do optimization specific to this case.
190  // hash-lookup is anyway dominant. memcpy-vs-primitive is not the issue.
191  return get_record_part(
192  context,
193  key,
194  key_length,
195  combo,
196  payload,
197  payload_offset,
198  sizeof(PAYLOAD),
199  read_only);
200  }
ErrorCode get_record_part(thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, void *payload, uint16_t payload_offset, uint16_t payload_count, bool read_only)

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::get_root_page ( thread::Thread context,
bool  for_write,
HashIntermediatePage **  root 
)

Retrieves the root page of this storage.

Definition at line 607 of file hash_storage_pimpl.cpp.

References ASSERT_ND, CHECK_ERROR_CODE, foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::thread::Thread::follow_page_pointer(), foedus::kErrorCodeOk, and foedus::storage::kHashIntermediatePageType.

Referenced by locate_bin().

610  {
611  CHECK_ERROR_CODE(context->follow_page_pointer(
612  nullptr, // guaranteed to be non-null
613  false, // guaranteed to be non-null
614  for_write,
615  false, // guaranteed to be non-null
616  &control_block_->root_page_pointer_,
617  reinterpret_cast<Page**>(root),
618  nullptr, // no parent. it's root.
619  0));
620  ASSERT_ND((*root)->header().get_page_type() == kHashIntermediatePageType);
621  ASSERT_ND((*root)->get_level() + 1U == control_block_->levels_);
622  return kErrorCodeOk;
623 }
0 means no-error.
Definition: error_code.hpp:87
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
#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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::hcc_reset_all_temperature_stat ( )

For stupid reasons (I'm lazy!) these are defined in _debug.cpp.

Definition at line 213 of file hash_storage_debug.cpp.

References CHECK_ERROR, foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::Attachable< HashStorageControlBlock >::engine_, hcc_reset_all_temperature_stat_intermediate(), foedus::storage::VolatilePagePointer::is_null(), foedus::kRetOk, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by foedus::storage::hash::HashStorage::hcc_reset_all_temperature_stat().

213  {
214  LOG(INFO) << "**"
215  << std::endl << "***************************************************************"
216  << std::endl << "*** Reseting " << HashStorage(engine_, control_block_) << "'s "
217  << std::endl << "*** temperature stat for HCC"
218  << std::endl << "***************************************************************";
219 
220  DualPagePointer pointer = control_block_->root_page_pointer_;
221  if (pointer.volatile_pointer_.is_null()) {
222  LOG(INFO) << "No volatile pages.";
223  } else {
224  CHECK_ERROR(hcc_reset_all_temperature_stat_intermediate(pointer.volatile_pointer_));
225  }
226 
227  LOG(INFO) << "Done resettting";
228  return kRetOk;
229 }
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
ErrorStack hcc_reset_all_temperature_stat_intermediate(VolatilePagePointer intermediate_page_id)
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::hcc_reset_all_temperature_stat_data ( VolatilePagePointer  head_page_id)

Definition at line 253 of file hash_storage_debug.cpp.

References foedus::Attachable< HashStorageControlBlock >::engine_, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::Engine::get_memory_manager(), foedus::storage::hash::HashDataPage::header(), foedus::storage::PageHeader::hotness_, foedus::storage::VolatilePagePointer::is_null(), foedus::kRetOk, and foedus::assorted::ProbCounter::reset().

Referenced by hcc_reset_all_temperature_stat_intermediate().

253  {
254  const auto& resolver = engine_->get_memory_manager()->get_global_volatile_page_resolver();
255  HashDataPage* head = reinterpret_cast<HashDataPage*>(resolver.resolve_offset(head_page_id));
256  for (HashDataPage* cur = head; cur;) {
257  cur->header().hotness_.reset();
258  VolatilePagePointer next_id = cur->next_page().volatile_pointer_;
259  cur = nullptr;
260  if (!next_id.is_null()) {
261  cur = reinterpret_cast<HashDataPage*>(resolver.resolve_offset(next_id));
262  }
263  }
264  return kRetOk;
265 }
const GlobalVolatilePageResolver & get_global_volatile_page_resolver() const
Returns the page resolver to convert volatile page ID to page pointer.
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
const ErrorStack kRetOk
Normal return value for no-error case.
memory::EngineMemory * get_memory_manager() const
See Memory Manager.
Definition: engine.cpp:50

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::hcc_reset_all_temperature_stat_intermediate ( VolatilePagePointer  intermediate_page_id)

Definition at line 231 of file hash_storage_debug.cpp.

References ASSERT_ND, CHECK_ERROR, foedus::Attachable< HashStorageControlBlock >::engine_, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::Engine::get_memory_manager(), foedus::storage::hash::HashIntermediatePage::get_pointer(), hcc_reset_all_temperature_stat_data(), foedus::storage::VolatilePagePointer::is_null(), foedus::storage::hash::kHashIntermediatePageFanout, foedus::kRetOk, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by hcc_reset_all_temperature_stat().

232  {
233  const auto& resolver = engine_->get_memory_manager()->get_global_volatile_page_resolver();
234  HashIntermediatePage* page
235  = reinterpret_cast<HashIntermediatePage*>(resolver.resolve_offset(intermediate_page_id));
236  ASSERT_ND(page);
237  const bool bottom = page->get_level() == 0;
238  for (uint8_t i = 0; i < kHashIntermediatePageFanout; ++i) {
239  DualPagePointer pointer = page->get_pointer(i);
240  if (pointer.volatile_pointer_.is_null()) {
241  continue;
242  }
243  if (bottom) {
244  CHECK_ERROR(hcc_reset_all_temperature_stat_data(pointer.volatile_pointer_));
245  } else {
246  CHECK_ERROR(hcc_reset_all_temperature_stat_intermediate(pointer.volatile_pointer_));
247  }
248  }
249 
250  return kRetOk;
251 }
const GlobalVolatilePageResolver & get_global_volatile_page_resolver() const
Returns the page resolver to convert volatile page ID to page pointer.
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
ErrorStack hcc_reset_all_temperature_stat_intermediate(VolatilePagePointer intermediate_page_id)
ErrorStack hcc_reset_all_temperature_stat_data(VolatilePagePointer head_page_id)
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.
const uint8_t kHashIntermediatePageFanout
Number of pointers in an intermediate page of hash storage.
Definition: hash_id.hpp:49
#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
memory::EngineMemory * get_memory_manager() const
See Memory Manager.
Definition: engine.cpp:50

Here is the call graph for this function:

Here is the caller graph for this function:

template<typename PAYLOAD >
ErrorCode foedus::storage::hash::HashStoragePimpl::increment_record ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
PAYLOAD *  value,
uint16_t  payload_offset 
)
See also
foedus::storage::hash::HashStorage::increment_record()

Definition at line 554 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashCommonLogType::calculate_log_length(), CHECK_ERROR_CODE, foedus::storage::hash::RecordLocation::cur_payload_length_, foedus::storage::hash::RecordLocation::get_aligned_key_length(), get_bin_bits(), get_id(), foedus::thread::Thread::get_thread_log_buffer(), foedus::storage::hash::HashCombo::hash_, foedus::xct::XctId::is_deleted(), foedus::storage::hash::RecordLocation::is_found(), foedus::kErrorCodeStrKeyNotFound, foedus::kErrorCodeStrTooShortPayload, locate_bin(), locate_record_logical(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::hash::HashOverwriteLogType::populate(), foedus::storage::hash::RecordLocation::record_, register_record_write_log(), and foedus::log::ThreadLogBuffer::reserve_new_log().

Referenced by foedus::storage::hash::HashStorage::increment_record().

560  {
561  HashDataPage* bin_head;
562  CHECK_ERROR_CODE(locate_bin(context, true, combo, &bin_head));
563  ASSERT_ND(bin_head);
564  RecordLocation location;
566  context,
567  true,
568  false,
569  0,
570  key,
571  key_length,
572  combo,
573  bin_head,
574  &location));
575 
576  if (!location.is_found()) {
577  return kErrorCodeStrKeyNotFound; // protected by page version set, so we are done
578  } else if (location.observed_.is_deleted()) {
579  return kErrorCodeStrKeyNotFound; // protected by the read set
580  } else if (location.cur_payload_length_ < payload_offset + sizeof(PAYLOAD)) {
581  LOG(WARNING) << "short record " << combo; // probably this is a rare error. so warn.
582  return kErrorCodeStrTooShortPayload; // protected by the read set
583  }
584 
585  // value: (in) addendum, (out) value after addition.
586  PAYLOAD* current = reinterpret_cast<PAYLOAD*>(
587  location.record_ + location.get_aligned_key_length() + payload_offset);
588  *value += *current;
589 
590  uint16_t log_length
591  = HashOverwriteLogType::calculate_log_length(key_length, sizeof(PAYLOAD));
592  HashOverwriteLogType* log_entry = reinterpret_cast<HashOverwriteLogType*>(
593  context->get_thread_log_buffer().reserve_new_log(log_length));
594  log_entry->populate(
595  get_id(),
596  key,
597  key_length,
598  get_bin_bits(),
599  combo.hash_,
600  value,
601  payload_offset,
602  sizeof(PAYLOAD));
603 
604  return register_record_write_log(context, location, log_entry);
605 }
0x080A : "STORAGE: The record's payload is smaller than requested" .
Definition: error_code.hpp:176
0x080C : "STORAGE: This key is not found in this storage" .
Definition: error_code.hpp:178
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
ErrorCode register_record_write_log(thread::Thread *context, const RecordLocation &location, log::RecordLogType *log_entry)
Used in the following methods.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
static uint16_t calculate_log_length(uint16_t key_length, uint16_t payload_count) __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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::insert_record ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
const void *  payload,
uint16_t  payload_count,
uint16_t  physical_payload_hint 
)
See also
foedus::storage::hash::HashStorage::insert_record()

Definition at line 277 of file hash_storage_pimpl.cpp.

References foedus::storage::hash::adjust_payload_hint(), ASSERT_ND, foedus::storage::hash::HashDataPage::bloom_filter(), foedus::storage::hash::HashCommonLogType::calculate_log_length(), CHECK_ERROR_CODE, foedus::storage::hash::DataPageBloomFilter::contains(), foedus::storage::hash::HashCombo::fingerprint_, get_bin_bits(), get_id(), foedus::storage::hash::RecordLocation::get_max_payload(), foedus::thread::Thread::get_thread_log_buffer(), foedus::storage::hash::HashCombo::hash_, foedus::storage::hash::HashDataPage::header(), foedus::storage::hash::RecordLocation::index_, foedus::xct::XctId::is_deleted(), foedus::storage::hash::RecordLocation::is_found(), foedus::kErrorCodeStrKeyAlreadyExists, locate_bin(), locate_record_logical(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::hash::RecordLocation::page_, foedus::storage::hash::HashInsertLogType::populate(), foedus::storage::hash::RecordLocation::record_, register_record_write_log(), foedus::log::ThreadLogBuffer::reserve_new_log(), foedus::thread::Thread::run_nested_sysxct(), and foedus::storage::PageHeader::snapshot_.

Referenced by foedus::storage::hash::HashStorage::insert_record().

284  {
285  physical_payload_hint = adjust_payload_hint(payload_count, physical_payload_hint);
286 
287  HashDataPage* bin_head;
288  CHECK_ERROR_CODE(locate_bin(context, true, combo, &bin_head));
289  ASSERT_ND(bin_head);
290 
291  while (true) { // we might retry due to migrate_record. not that often, tho.
292  RecordLocation location;
294  context,
295  true,
296  true,
297  physical_payload_hint,
298  key,
299  key_length,
300  combo,
301  bin_head,
302  &location));
303 
304  // we create if not exists, these are surely non-null
305  ASSERT_ND(location.is_found());
306  ASSERT_ND(location.record_);
307 
308  // but, that record might be not logically deleted
309  if (!location.observed_.is_deleted()) {
310  return kErrorCodeStrKeyAlreadyExists; // protected by the read set
311  }
312 
313  if (payload_count > location.get_max_payload()) {
314  // The physical record is too short. It will trigger a record expansion, which is a
315  // system transaction (logically does nothing!) to migrate this deleted record.
316  HashDataPage* cur_page = location.page_;
317  ASSERT_ND(!cur_page->header().snapshot_);
318  ASSERT_ND(cur_page->bloom_filter().contains(combo.fingerprint_));
319  DataPageSlotIndex cur_index = location.index_;
320  DVLOG(2) << "Record expansion triggered. payload_count=" << payload_count
321  << ", current max=" << location.get_max_payload()
322  << ", size hint=" << physical_payload_hint;
323 
324  ReserveRecords functor(
325  context,
326  cur_page,
327  key,
328  key_length,
329  combo,
330  payload_count,
331  physical_payload_hint,
332  cur_index);
333  CHECK_ERROR_CODE(context->run_nested_sysxct(&functor, 5U));
334  DVLOG(2) << "Expanded record!";
335  // need to re-locate. also, beacuse the above method is physical-only,
336  // the moved location might be again moved or now deleted. easise to just retry.
337  continue;
338  }
339 
340  uint16_t log_length = HashInsertLogType::calculate_log_length(key_length, payload_count);
341  HashInsertLogType* log_entry = reinterpret_cast<HashInsertLogType*>(
342  context->get_thread_log_buffer().reserve_new_log(log_length));
343  log_entry->populate(
344  get_id(),
345  key,
346  key_length,
347  get_bin_bits(),
348  combo.hash_,
349  payload,
350  payload_count);
351 
352  return register_record_write_log(context, location, log_entry);
353  }
354 }
uint16_t adjust_payload_hint(uint16_t payload_count, uint16_t physical_payload_hint)
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
ErrorCode register_record_write_log(thread::Thread *context, const RecordLocation &location, log::RecordLogType *log_entry)
Used in the following methods.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
static uint16_t calculate_log_length(uint16_t key_length, uint16_t payload_count) __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
0x080B : "STORAGE: This key already exists in this storage" .
Definition: error_code.hpp:177

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::load ( const StorageControlBlock snapshot_block)

Definition at line 135 of file hash_storage_pimpl.cpp.

References foedus::storage::hash::bins_to_level(), CHECK_ERROR, foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::Attachable< HashStorageControlBlock >::engine_, get_bin_bits(), foedus::Engine::get_memory_manager(), get_name(), foedus::DefaultInitializable::initialize(), foedus::storage::kExists, foedus::kRetOk, foedus::UninitializeGuard::kWarnIfUninitializeError, foedus::memory::EngineMemory::load_one_volatile_page(), foedus::storage::StorageControlBlock::meta_, foedus::storage::Metadata::root_snapshot_page_id_, and foedus::DefaultInitializable::uninitialize().

Referenced by foedus::storage::hash::HashStorage::load().

135  {
136  control_block_->meta_ = static_cast<const HashMetadata&>(snapshot_block.meta_);
137  const HashMetadata& meta = control_block_->meta_;
138  control_block_->bin_count_ = 1ULL << get_bin_bits();
139  control_block_->levels_ = bins_to_level(control_block_->bin_count_);
140  control_block_->root_page_pointer_.snapshot_pointer_ = meta.root_snapshot_page_id_;
141  control_block_->root_page_pointer_.volatile_pointer_.word = 0;
142 
143  // Root page always has volatile version.
144  // Construct it from snapshot version.
145  cache::SnapshotFileSet fileset(engine_);
146  CHECK_ERROR(fileset.initialize());
147  UninitializeGuard fileset_guard(&fileset, UninitializeGuard::kWarnIfUninitializeError);
148 
149  // load root page
150  VolatilePagePointer volatile_pointer;
151  HashIntermediatePage* volatile_root;
153  &fileset,
154  meta.root_snapshot_page_id_,
155  &volatile_pointer,
156  reinterpret_cast<Page**>(&volatile_root)));
157  control_block_->root_page_pointer_.volatile_pointer_ = volatile_pointer;
158 
159  CHECK_ERROR(fileset.uninitialize());
160 
161  LOG(INFO) << "Loaded a hash-storage " << get_name();
162  control_block_->status_ = kExists;
163  return kRetOk;
164 }
Automatically calls if uninitialize() wasn't called when it gets out of scope, and just complains whe...
ErrorStack load_one_volatile_page(cache::SnapshotFileSet *fileset, storage::SnapshotPagePointer snapshot_pointer, storage::VolatilePagePointer *pointer, storage::Page **page)
Another convenience method that also reads an existing snapshot page to the volatile page...
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
The storage has been created and ready for use.
Definition: storage_id.hpp:158
uint8_t bins_to_level(uint64_t bins)
Definition: hash_id.hpp:90
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.
memory::EngineMemory * get_memory_manager() const
See Memory Manager.
Definition: engine.cpp:50

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::locate_bin ( thread::Thread context,
bool  for_write,
const HashCombo combo,
HashDataPage **  bin_head 
)

Find a pointer to the bin that contains records for the hash.

Parameters
[in]contextThread context
[in]for_writeWhether we are reading these pages to modify
[in]comboHash values.
[out]bin_headPointer to the first data page of the bin. Might be null.

If the search is for-write search, we always create a volatile page, even recursively, thus *bin_head!= null.

If the search is a for-read search and also the corresponding data page or its ascendants do not exist yet, *bin_head returns null. In that case, you can just return "not found" as a result. locate_bin() internally adds a pointer set to protect the result, too.

Note
Although the above rule is simple, this might be wasteful in some situation. Deletions and updates for non-existing keys do not need to instantiate volatile pages. It can be handled like read access in that case. But, to really achieve it, delete/update have to be 2-path. Search it using snapshot pages, then goes through volatile path when found. Rather, let's always create volatile pages for all writes. It's simple and performs the best except a very unlucky case. If miss-delete/update is really the common path, the user code can manually achieve the same thing by get() first, then delete/update().

Definition at line 842 of file hash_storage_pimpl.cpp.

References foedus::xct::Xct::add_to_pointer_set(), ASSERT_ND, foedus::storage::hash::HashCombo::bin_, CHECK_ERROR_CODE, foedus::storage::VolatilePagePointer::clear(), follow_page(), foedus::storage::hash::HashDataPage::get_bin(), foedus::thread::Thread::get_current_xct(), foedus::xct::Xct::get_isolation_level(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::storage::hash::HashIntermediatePage::get_pointer(), get_root_page(), foedus::storage::hash::HashIntermediatePage::header(), foedus::kErrorCodeOk, foedus::xct::kSerializable, foedus::storage::hash::IntermediateRoute::route, foedus::storage::hash::HashCombo::route_, foedus::storage::PageHeader::snapshot_, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by delete_record(), get_record(), get_record_part(), increment_record(), insert_record(), overwrite_record(), and upsert_record().

846  {
847  HashIntermediatePage* root;
848  CHECK_ERROR_CODE(get_root_page(context, for_write, &root));
849  ASSERT_ND(root);
850  *bin_head = nullptr;
851  xct::Xct& current_xct = context->get_current_xct();
852 
853  HashIntermediatePage* parent = root;
854  while (true) {
855  ASSERT_ND(parent);
856  uint8_t parent_level = parent->get_level();
857  uint16_t index = combo.route_.route[parent_level];
858  Page* next;
859  CHECK_ERROR_CODE(follow_page(context, for_write, parent, index, &next));
860  if (!next) {
861  // if this is a read-access, it is possible that the page even doesn't exist.
862  // it is a valid result (not found). we just have to add a pointer set to protect the result.
863  ASSERT_ND(!for_write);
864  if (!parent->header().snapshot_ // then we already added a pointer set in higher level
865  && current_xct.get_isolation_level() == xct::kSerializable) {
866  VolatilePagePointer volatile_null;
867  volatile_null.clear();
869  current_xct.add_to_pointer_set(
870  &parent->get_pointer(index).volatile_pointer_,
871  volatile_null));
872  }
873  break;
874  } else {
875  if (parent_level == 0) {
876  *bin_head = reinterpret_cast<HashDataPage*>(next);
877  break;
878  } else {
879  parent = reinterpret_cast<HashIntermediatePage*>(next);
880  }
881  }
882  }
883 
884  ASSERT_ND(*bin_head != nullptr || !for_write);
885  ASSERT_ND(*bin_head == nullptr || (*bin_head)->get_bin() == combo.bin_);
886  return kErrorCodeOk;
887 }
ErrorCode get_root_page(thread::Thread *context, bool for_write, HashIntermediatePage **root)
Retrieves the root page of this storage.
ErrorCode follow_page(thread::Thread *context, bool for_write, HashIntermediatePage *parent, uint16_t index_in_parent, Page **page)
for non-root
0 means no-error.
Definition: error_code.hpp:87
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
#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
Protects against all anomalies in all situations.
Definition: xct_id.hpp:86

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::locate_record ( thread::Thread context,
bool  for_write,
bool  physical_only,
bool  create_if_notfound,
uint16_t  create_payload_length,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
HashDataPage bin_head,
RecordLocation result 
)

Usually follows locate_bin to locate the exact physical record for the key, or create a new one if not exists (only when for_write).

Parameters
[in]contextThread context
[in]for_writeWhether we are seeking the record to modify
[in]physical_onlyIf true, we skip observing XID and registering readset in a finalized fashion, see RecordLocation.
[in]create_if_notfoundWhether we will create a new physical record if not exists
[in]create_payload_lengthIf this method creates a physical record, it makes sure the record can accomodate at least this size of payload.
[in]keyThe searching key.
[in]key_lengthByte length of the searching key.
[in]comboHash values. Also the result of this method.
[in]bin_headPointer to the first data page of the bin.
[out]resultInformation on the found slot.
Precondition
bin_head->get_bin() == combo.bin_
bin_head != nullptr
bin_head must be volatile page if for_write

If the exact record is not found, this method protects the result by adding page version set if physical_only is false. If create_if_notfound is true (an insert case), this method creates a new physical record for the key with a deleted-state as a system transaction.

See also
RecordLocation

Definition at line 936 of file hash_storage_pimpl.cpp.

References foedus::xct::Xct::add_to_page_version_set(), ASSERT_ND, foedus::storage::hash::HashCombo::bin_, CHECK_ERROR_CODE, foedus::storage::hash::RecordLocation::clear(), foedus::storage::hash::HashDataPage::compare_slot_key(), foedus::storage::hash::HashCombo::fingerprint_, foedus::storage::hash::HashDataPage::get_bin(), foedus::thread::Thread::get_current_xct(), foedus::thread::Thread::get_numa_node(), foedus::storage::hash::HashDataPage::get_record_count(), foedus::storage::PageVersionStatus::has_next_page(), foedus::storage::hash::HashCombo::hash_, foedus::storage::hash::HashDataPage::header(), foedus::xct::XctId::is_moved(), foedus::storage::VolatilePagePointer::is_null(), foedus::kErrorCodeOk, foedus::storage::hash::kSlotNotFound, locate_record_in_snapshot(), locate_record_reserve_physical(), foedus::assorted::memory_fence_acquire(), foedus::storage::hash::HashDataPage::next_page_address(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::PageHeader::page_version_, foedus::storage::hash::RecordLocation::populate_logical(), foedus::storage::hash::RecordLocation::populate_physical(), foedus::thread::Thread::resolve_cast(), foedus::storage::hash::HashDataPage::search_key_physical(), foedus::storage::PageHeader::snapshot_, foedus::storage::PageHeader::stat_last_updater_node_, foedus::storage::PageVersion::status_, UNLIKELY, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by locate_record_logical(), and locate_record_physical_only().

946  {
947  ASSERT_ND(bin_head);
948  ASSERT_ND(bin_head->get_bin() == combo.bin_);
949  ASSERT_ND(for_write || !create_if_notfound); // create_if_notfound implies for_write
950 
951  // Snapshot case is way easier. Separtely handle that case.
952  if (bin_head->header().snapshot_) {
953  ASSERT_ND(!for_write);
954  ASSERT_ND(!create_if_notfound);
955  return locate_record_in_snapshot(context, key, key_length, combo, bin_head, result);
956  }
957 
958  xct::Xct* cur_xct = &context->get_current_xct();
959 
960  // in hash storage, we maintain only bin_head's stat. it's enough
961  if (for_write) {
962  bin_head->header().stat_last_updater_node_ = context->get_numa_node();
963  }
964 
965  HashDataPage* page = bin_head;
966  while (true) {
967  // Start with a physical-only search. We will re-check our observation below.
968  const uint16_t record_count = page->get_record_count();
969  const DataPageSlotIndex index = page->search_key_physical(
970  combo.hash_,
971  combo.fingerprint_,
972  key,
973  key_length,
974  record_count);
975  if (index != kSlotNotFound) {
976  // found! but it might be now being logically moved/deleted.
977  ASSERT_ND(page->compare_slot_key(index, combo.hash_, key, key_length));
978  if (physical_only) {
979  // we don't care. the caller is responsible to do logical operation
980  result->populate_physical(page, index);
981  return kErrorCodeOk;
982  } else {
983  CHECK_ERROR_CODE(result->populate_logical(cur_xct, page, index, for_write));
984  if (UNLIKELY(result->observed_.is_moved())) {
985  LOG(INFO) << "Interesting. The record has been just moved";
986  continue;
987  }
988  return kErrorCodeOk;
989  }
990  }
991 
992  // Apparently not in this page, now on to next page. We have to be a bit careful
993  // in this case. Non-null next page means this page is already static, but we
994  // have to make sure we confirmed it in a right order.
995  DualPagePointer* next_page = page->next_page_address();
996 
997  // we are in volatile page, there might be a race!
998  PageVersionStatus page_status = page->header().page_version_.status_;
999  assorted::memory_fence_acquire(); // from now on, page_status is the ground truth here.
1000  // check a few things after the fence.
1001  // invariant: we never move on to next page without guaranteeing that this page does not
1002  // contain a physical non-moved record with the key.
1003 
1004  // did someone insert a new record at this moment?
1005  uint16_t record_count_again = page->get_record_count();
1006  if (UNLIKELY(record_count != record_count_again)) {
1007  LOG(INFO) << "Interesting. concurrent insertion just happend to the page";
1009  continue; // just retry to make it sure. this is rare.
1010  }
1011 
1012  // did someone install a new page at this moment?
1013  if (UNLIKELY(!page_status.has_next_page() && !next_page->volatile_pointer_.is_null())) {
1014  LOG(INFO) << "Interesting. concurrent next-page installation just happend to the page";
1016  continue; // just retry to make it sure. this is rare.
1017  }
1018 
1019  if (next_page->volatile_pointer_.is_null()) {
1020  // no next page.
1021  if (create_if_notfound) {
1022  // this is the tail page, so let's insert it here.
1023  // we do that as a system transaction.
1024  ASSERT_ND(for_write);
1025  DataPageSlotIndex new_location;
1027  context,
1028  key,
1029  key_length,
1030  combo,
1031  create_payload_length,
1032  &page,
1033  record_count,
1034  &new_location));
1035  ASSERT_ND(new_location != kSlotNotFound); // contract of the above method
1036  // The returned location is not logically protected... yet.
1037  ASSERT_ND(page->compare_slot_key(new_location, combo.hash_, key, key_length));
1038  if (physical_only) {
1039  // we don't care. the caller is responsible to do logical operation
1040  result->populate_physical(page, new_location);
1041  return kErrorCodeOk;
1042  } else {
1043  CHECK_ERROR_CODE(result->populate_logical(cur_xct, page, new_location, for_write));
1044  if (UNLIKELY(result->observed_.is_moved())) {
1045  LOG(INFO) << "Interesting. The record has been just moved after creation!";
1046  continue;
1047  }
1048  return kErrorCodeOk;
1049  }
1050  } else {
1051  // "NotFound" result. To finalize it,
1052  // we have to take version set because someone might
1053  // insert a new record/next-page later.
1054  result->clear();
1055  if (physical_only) {
1056  // we don't care. the caller is responsible to do logical operation
1057  return kErrorCodeOk;
1058  } else {
1059  // [Logical check]: Remember the page_status we observed as of checking record count
1060  // and verify it at commit time.
1061  CHECK_ERROR_CODE(cur_xct->add_to_page_version_set(
1062  &page->header().page_version_,
1063  page_status));
1064  return kErrorCodeOk;
1065  }
1066  }
1067  } else {
1068  page = context->resolve_cast<HashDataPage>(next_page->volatile_pointer_);
1069  ASSERT_ND(!page->header().snapshot_);
1070  }
1071  }
1072 }
const DataPageSlotIndex kSlotNotFound
Definition: hash_id.hpp:197
ErrorCode locate_record_reserve_physical(thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, uint16_t payload_length, HashDataPage **page_in_out, uint16_t examined_records, DataPageSlotIndex *new_location)
Subroutine of locate_record() to create/migrate a physical record of the given key in the page or its...
0 means no-error.
Definition: error_code.hpp:87
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
void memory_fence_acquire()
Equivalent to std::atomic_thread_fence(std::memory_order_acquire).
#define UNLIKELY(x)
Hints that x is highly likely false.
Definition: compiler.hpp:104
#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
ErrorCode locate_record_in_snapshot(thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
Simpler version of locate_record for when we are in snapshot world.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::locate_record_in_snapshot ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
HashDataPage bin_head,
RecordLocation result 
)

Simpler version of locate_record for when we are in snapshot world.

Definition at line 889 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashCombo::bin_, CHECK_ERROR_CODE, foedus::storage::hash::RecordLocation::clear(), foedus::storage::hash::HashDataPage::compare_slot_key(), foedus::thread::Thread::find_or_read_a_snapshot_page(), foedus::storage::hash::HashCombo::fingerprint_, foedus::storage::hash::HashDataPage::get_bin(), foedus::storage::Page::get_header(), foedus::storage::hash::HashDataPage::get_record_count(), foedus::storage::hash::HashCombo::hash_, foedus::storage::hash::HashDataPage::header(), foedus::xct::XctId::is_moved(), foedus::storage::VolatilePagePointer::is_null(), foedus::kErrorCodeOk, foedus::storage::hash::kSlotNotFound, foedus::storage::hash::HashDataPage::next_page_address(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::hash::RecordLocation::populate_physical(), foedus::storage::hash::HashDataPage::search_key_physical(), foedus::storage::PageHeader::snapshot_, foedus::storage::DualPagePointer::snapshot_pointer_, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by locate_record().

895  {
896  ASSERT_ND(bin_head);
897  ASSERT_ND(bin_head->get_bin() == combo.bin_);
898  ASSERT_ND(bin_head->header().snapshot_);
899  result->clear();
900  // Snapshot version doesn't need any of the concerns above. Easy!
901  // Just physically search and follow to next page.
902  HashDataPage* page = bin_head;
903  while (true) {
904  const uint16_t record_count = page->get_record_count();
905  const DataPageSlotIndex index = page->search_key_physical(
906  combo.hash_,
907  combo.fingerprint_,
908  key,
909  key_length,
910  record_count);
911  if (index != kSlotNotFound) {
912  // found! this is final in snapshot page, so physical-only suffices (no protection needed).
913  ASSERT_ND(page->compare_slot_key(index, combo.hash_, key, key_length));
914  result->populate_physical(page, index);
915  ASSERT_ND(!result->observed_.is_moved());
916  return kErrorCodeOk;
917  }
918 
919  // Definitely not in this page, now on to next page.
920  DualPagePointer* next_page = page->next_page_address();
921  // then we are in snapshot world. no race.
922  ASSERT_ND(next_page->volatile_pointer_.is_null());
923  SnapshotPagePointer pointer = next_page->snapshot_pointer_;
924  if (pointer) {
925  Page* next;
926  CHECK_ERROR_CODE(context->find_or_read_a_snapshot_page(pointer, &next));
927  ASSERT_ND(next->get_header().snapshot_);
928  page = reinterpret_cast<HashDataPage*>(next);
929  } else {
930  // it's snapshot world. the result is final, we are done.
931  return kErrorCodeOk;
932  }
933  }
934 }
const DataPageSlotIndex kSlotNotFound
Definition: hash_id.hpp:197
0 means no-error.
Definition: error_code.hpp:87
uint64_t SnapshotPagePointer
Page ID of a snapshot page.
Definition: storage_id.hpp:79
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
#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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::locate_record_logical ( thread::Thread context,
bool  for_write,
bool  create_if_notfound,
uint16_t  create_payload_length,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
HashDataPage bin_head,
RecordLocation result 
)
inline

locate_record()'s logical+physical version.

Invoke this rather than locate_record directly

Definition at line 400 of file hash_storage_pimpl.hpp.

References locate_record().

Referenced by delete_record(), get_record(), get_record_part(), increment_record(), insert_record(), overwrite_record(), and upsert_record().

409  {
410  return locate_record(
411  context,
412  for_write,
413  false,
414  create_if_notfound,
415  create_payload_length,
416  key,
417  key_length,
418  combo,
419  bin_head,
420  result);
421  }
ErrorCode locate_record(thread::Thread *context, bool for_write, bool physical_only, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
Usually follows locate_bin to locate the exact physical record for the key, or create a new one if no...

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::locate_record_physical_only ( thread::Thread context,
bool  for_write,
bool  create_if_notfound,
uint16_t  create_payload_length,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
HashDataPage bin_head,
RecordLocation result 
)
inline

locate_record()'s physical_only version.

Invoke this rather than locate_record directly

Definition at line 377 of file hash_storage_pimpl.hpp.

References locate_record().

386  {
387  return locate_record(
388  context,
389  for_write,
390  true,
391  create_if_notfound,
392  create_payload_length,
393  key,
394  key_length,
395  combo,
396  bin_head,
397  result);
398  }
ErrorCode locate_record(thread::Thread *context, bool for_write, bool physical_only, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
Usually follows locate_bin to locate the exact physical record for the key, or create a new one if no...

Here is the call graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::locate_record_reserve_physical ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
uint16_t  payload_length,
HashDataPage **  page_in_out,
uint16_t  examined_records,
DataPageSlotIndex new_location 
)

Subroutine of locate_record() to create/migrate a physical record of the given key in the page or its next pages.

This method has the following possible outcomes:

  • Created a new physical record of the key in the given page or its next pages.
  • Did nothing because we found an existing record of the key in the given page or its next pages.

In either case, new_location returns the index of the record, thus it's never a kSlotNotFound.

This method is physical-only. It doesn't add any read-set or take logical record locks. Thus, even seemingly right after calling this method, you might find the new_location points to a moved record. It might happen. The caller is responsible to do a logical lock/readset etc and retries if necessary. But, this method does guarantee that the new_location points to a record of the given key that was at least at some point valid.

Definition at line 1074 of file hash_storage_pimpl.cpp.

References ASSERT_ND, CHECK_ERROR_CODE, foedus::kErrorCodeOk, foedus::storage::hash::ReserveRecords::out_page_, foedus::storage::hash::ReserveRecords::out_slot_, and foedus::thread::Thread::run_nested_sysxct().

Referenced by locate_record().

1082  {
1083  ASSERT_ND(new_location);
1084  ReserveRecords functor(
1085  context,
1086  *page_in_out,
1087  key,
1088  key_length,
1089  combo,
1090  payload_length,
1091  payload_length,
1092  examined_records);
1093  CHECK_ERROR_CODE(context->run_nested_sysxct(&functor, 5U));
1094  *page_in_out = functor.out_page_;
1095  *new_location = functor.out_slot_;
1096  return kErrorCodeOk;
1097 }
0 means no-error.
Definition: error_code.hpp:87
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
#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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::overwrite_record ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
const void *  payload,
uint16_t  payload_offset,
uint16_t  payload_count 
)
See also
foedus::storage::hash::HashStorage::overwrite_record()

Definition at line 502 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashCommonLogType::calculate_log_length(), CHECK_ERROR_CODE, foedus::storage::hash::RecordLocation::cur_payload_length_, get_bin_bits(), get_id(), foedus::thread::Thread::get_thread_log_buffer(), foedus::storage::hash::HashCombo::hash_, foedus::xct::XctId::is_deleted(), foedus::storage::hash::RecordLocation::is_found(), foedus::kErrorCodeStrKeyNotFound, foedus::kErrorCodeStrTooShortPayload, locate_bin(), locate_record_logical(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::hash::HashOverwriteLogType::populate(), register_record_write_log(), and foedus::log::ThreadLogBuffer::reserve_new_log().

Referenced by foedus::storage::hash::HashStorage::overwrite_record(), and overwrite_record_primitive().

509  {
510  HashDataPage* bin_head;
511  CHECK_ERROR_CODE(locate_bin(context, true, combo, &bin_head));
512  ASSERT_ND(bin_head);
513  RecordLocation location;
515  context,
516  true,
517  false,
518  0,
519  key,
520  key_length,
521  combo,
522  bin_head,
523  &location));
524 
525  if (!location.is_found()) {
526  return kErrorCodeStrKeyNotFound; // protected by page version set, so we are done
527  } else if (location.observed_.is_deleted()) {
528  return kErrorCodeStrKeyNotFound; // protected by the read set
529  } else if (location.cur_payload_length_ < payload_offset + payload_count) {
530  LOG(WARNING) << "short record " << combo; // probably this is a rare error. so warn.
531  return kErrorCodeStrTooShortPayload; // protected by the read set
532  }
533 
534  uint16_t log_length = HashOverwriteLogType::calculate_log_length(key_length, payload_count);
535  HashOverwriteLogType* log_entry = reinterpret_cast<HashOverwriteLogType*>(
536  context->get_thread_log_buffer().reserve_new_log(log_length));
537  log_entry->populate(
538  get_id(),
539  key,
540  key_length,
541  get_bin_bits(),
542  combo.hash_,
543  payload,
544  payload_offset,
545  payload_count);
546 
547  // overwrite_record is apparently a blind-write, but actually it's not.
548  // we depend on the fact that the record was not deleted/moved! so,
549  // this still has a related/dependent read-set
550  return register_record_write_log(context, location, log_entry);
551 }
0x080A : "STORAGE: The record's payload is smaller than requested" .
Definition: error_code.hpp:176
0x080C : "STORAGE: This key is not found in this storage" .
Definition: error_code.hpp:178
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
ErrorCode register_record_write_log(thread::Thread *context, const RecordLocation &location, log::RecordLogType *log_entry)
Used in the following methods.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
static uint16_t calculate_log_length(uint16_t key_length, uint16_t payload_count) __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

Here is the call graph for this function:

Here is the caller graph for this function:

template<typename PAYLOAD >
ErrorCode foedus::storage::hash::HashStoragePimpl::overwrite_record_primitive ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
PAYLOAD  payload,
uint16_t  payload_offset 
)
inline
See also
foedus::storage::hash::HashStorage::overwrite_record_primitive()

Definition at line 259 of file hash_storage_pimpl.hpp.

References overwrite_record().

Referenced by foedus::storage::hash::HashStorage::overwrite_record_primitive().

265  {
266  // same above. still handy as an API, though.
267  return overwrite_record(
268  context,
269  key,
270  key_length,
271  combo,
272  &payload,
273  payload_offset,
274  sizeof(payload));
275  }
ErrorCode overwrite_record(thread::Thread *context, const void *key, uint16_t key_length, const HashCombo &combo, const void *payload, uint16_t payload_offset, uint16_t payload_count)

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::register_record_write_log ( thread::Thread context,
const RecordLocation location,
log::RecordLogType log_entry 
)

Used in the following methods.

Definition at line 260 of file hash_storage_pimpl.cpp.

References foedus::xct::Xct::add_related_write_set(), foedus::xct::Xct::add_to_write_set(), ASSERT_ND, foedus::thread::Thread::get_current_xct(), get_id(), foedus::storage::hash::HashDataPage::get_slot_address(), foedus::storage::hash::RecordLocation::index_, foedus::storage::hash::RecordLocation::is_found(), foedus::storage::hash::RecordLocation::page_, foedus::storage::hash::RecordLocation::readset_, and foedus::storage::hash::RecordLocation::record_.

Referenced by delete_record(), increment_record(), insert_record(), overwrite_record(), and upsert_record().

263  {
264  // If we have taken readset in locate_record, add as a related write set
265  ASSERT_ND(location.is_found());
266  auto* slot = location.page_->get_slot_address(location.index_);
267  char* record = location.record_;
268  xct::Xct* cur_xct = &context->get_current_xct();
269  if (location.readset_) {
270  return cur_xct->add_related_write_set(location.readset_, &slot->tid_, record, log_entry);
271  } else {
272  return cur_xct->add_to_write_set(get_id(), &slot->tid_, record, log_entry);
273  }
274 }
#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

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::storage::hash::HashStoragePimpl::release_pages_recursive_data ( memory::PageReleaseBatch batch,
HashDataPage page,
VolatilePagePointer  volatile_page_id 
)
void foedus::storage::hash::HashStoragePimpl::release_pages_recursive_intermediate ( memory::PageReleaseBatch batch,
HashIntermediatePage page,
VolatilePagePointer  volatile_page_id 
)
void foedus::storage::hash::HashStoragePimpl::release_pages_recursive_root ( memory::PageReleaseBatch batch,
HashIntermediatePage page,
VolatilePagePointer  volatile_page_id 
)

Used only from uninitialize()

xct::TrackMovedRecordResult foedus::storage::hash::HashStoragePimpl::track_moved_record ( xct::RwLockableXctId old_address,
xct::WriteXctAccess write_set 
)

Definition at line 1099 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::storage::hash::HashCommonLogType::assert_record_and_log_keys(), foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::xct::RwLockableXctId::is_moved(), foedus::storage::kHashDataPageType, foedus::xct::WriteXctAccess::log_entry_, foedus::xct::WriteXctAccess::payload_address_, foedus::xct::RecordXctAccess::storage_id_, foedus::storage::to_page(), and track_moved_record_search().

Referenced by foedus::storage::hash::HashStorage::track_moved_record().

1101  {
1102  ASSERT_ND(old_address);
1103  ASSERT_ND(old_address->is_moved());
1104  // We use moved bit only for volatile data pages
1105  HashDataPage* page = reinterpret_cast<HashDataPage*>(to_page(old_address));
1106  ASSERT_ND(!page->header().snapshot_);
1107  ASSERT_ND(page->header().get_page_type() == kHashDataPageType);
1108 
1109  // TID is the first member in slot, so this ugly cast works.
1110  HashDataPage::Slot* old_slot = reinterpret_cast<HashDataPage::Slot*>(old_address);
1111  ASSERT_ND(&old_slot->tid_ == old_address);
1112 
1113  // for tracking, we need the full key and hash. let's extract them.
1114  const char* key = page->record_from_offset(old_slot->offset_);
1115  uint16_t key_length = old_slot->key_length_;
1116  HashCombo combo(key, key_length, control_block_->meta_);
1117 
1118  // we need write_set only for sanity check. It's easier in hash storage!
1119  if (write_set) {
1120 #ifndef NDEBUG
1121  ASSERT_ND(write_set->storage_id_ == page->header().storage_id_);
1122  ASSERT_ND(write_set->payload_address_ == page->record_from_offset(old_slot->offset_));
1123  HashCommonLogType* the_log = reinterpret_cast<HashCommonLogType*>(write_set->log_entry_);
1124  the_log->assert_record_and_log_keys(old_address, page->record_from_offset(old_slot->offset_));
1125 #endif // NDEBUG
1126  }
1127  HashDataPage::Slot* slot_origin = reinterpret_cast<HashDataPage::Slot*>(page + 1);
1128  ASSERT_ND(slot_origin > old_slot); // because origin corresponds to "-1".
1129  DataPageSlotIndex old_index = slot_origin - old_slot - 1;
1130  ASSERT_ND(page->get_slot_address(old_index) == old_slot);
1131 
1132  return track_moved_record_search(page, key, key_length, combo);
1133 }
Page * to_page(const void *address)
super-dirty way to obtain Page the address belongs to.
Definition: page.hpp:395
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
#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
xct::TrackMovedRecordResult track_moved_record_search(HashDataPage *page, const void *key, uint16_t key_length, const HashCombo &combo)

Here is the call graph for this function:

Here is the caller graph for this function:

xct::TrackMovedRecordResult foedus::storage::hash::HashStoragePimpl::track_moved_record_search ( HashDataPage page,
const void *  key,
uint16_t  key_length,
const HashCombo combo 
)

Definition at line 1135 of file hash_storage_pimpl.cpp.

References ASSERT_ND, foedus::Attachable< HashStorageControlBlock >::engine_, foedus::storage::hash::HashCombo::fingerprint_, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::Engine::get_memory_manager(), foedus::storage::hash::HashDataPage::get_record_count(), foedus::storage::hash::HashDataPage::get_slot_address(), foedus::storage::hash::HashCombo::hash_, foedus::storage::hash::HashDataPage::header(), foedus::storage::VolatilePagePointer::is_null(), foedus::storage::hash::kSlotNotFound, foedus::assorted::memory_fence_acquire(), foedus::assorted::memory_fence_consume(), foedus::storage::hash::HashDataPage::next_page_address(), foedus::storage::hash::HashDataPage::Slot::offset_, foedus::storage::hash::HashDataPage::record_from_offset(), foedus::memory::GlobalVolatilePageResolver::resolve_offset(), foedus::storage::hash::HashDataPage::search_key_physical(), foedus::storage::PageHeader::snapshot_, foedus::storage::DualPagePointer::snapshot_pointer_, foedus::storage::hash::HashDataPage::Slot::tid_, UNLIKELY, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by track_moved_record().

1139  {
1140  const memory::GlobalVolatilePageResolver& resolver
1142  RecordLocation result;
1143  while (true) {
1144  ASSERT_ND(!page->header().snapshot_);
1145  ASSERT_ND(page->next_page_address()->snapshot_pointer_ == 0);
1146  const uint16_t record_count = page->get_record_count();
1147 
1148  // Tracking happens in commit phase, so we don't need further logical readset/lock things.
1149  // This is just to locate the new address. So, physical_only search.
1150  // (which might miss a new record being inserted, but it's just a bit conservative abort)
1151  DataPageSlotIndex index = page->search_key_physical(
1152  combo.hash_,
1153  combo.fingerprint_,
1154  key,
1155  key_length,
1156  record_count);
1157  if (index != kSlotNotFound) {
1158  HashDataPage::Slot* slot = page->get_slot_address(index);
1159  char* payload = page->record_from_offset(slot->offset_);
1160  return xct::TrackMovedRecordResult(&slot->tid_, payload);
1161  }
1162 
1163  // we must meet the same invariant as usual case. a bit simpler, though
1165  DualPagePointer* next_page = page->next_page_address();
1167 
1168  uint16_t record_count_again = page->get_record_count();
1169  if (UNLIKELY(record_count != record_count_again)) {
1170  LOG(INFO) << "Interesting. concurrent insertion just happend to the page";
1172  continue;
1173  }
1174  if (next_page->volatile_pointer_.is_null()) {
1175  // This shouldn't happen as far as we flip moved bit after installing the new record
1176  LOG(WARNING) << "no next page?? but we didn't find the moved record in this page";
1178  if (next_page->volatile_pointer_.is_null()) {
1179  LOG(ERROR) << "Unexpected error, failed to track moved record in hash storage."
1180  << " This should not happen. hash combo=" << combo;
1181  return xct::TrackMovedRecordResult();
1182  }
1183  continue;
1184  }
1185  page = reinterpret_cast<HashDataPage*>(resolver.resolve_offset(next_page->volatile_pointer_));
1186  }
1187 }
const GlobalVolatilePageResolver & get_global_volatile_page_resolver() const
Returns the page resolver to convert volatile page ID to page pointer.
const DataPageSlotIndex kSlotNotFound
Definition: hash_id.hpp:197
Engine * engine_
Most attachable object stores an engine pointer (local engine), so we define it here.
Definition: attachable.hpp:107
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
void memory_fence_consume()
Equivalent to std::atomic_thread_fence(std::memory_order_consume).
void memory_fence_acquire()
Equivalent to std::atomic_thread_fence(std::memory_order_acquire).
#define UNLIKELY(x)
Hints that x is highly likely false.
Definition: compiler.hpp:104
#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
memory::EngineMemory * get_memory_manager() const
See Memory Manager.
Definition: engine.cpp:50

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::storage::hash::HashStoragePimpl::upsert_record ( thread::Thread context,
const void *  key,
uint16_t  key_length,
const HashCombo combo,
const void *  payload,
uint16_t  payload_count,
uint16_t  physical_payload_hint 
)
See also
foedus::storage::hash::HashStorage::upsert_record()

Definition at line 390 of file hash_storage_pimpl.cpp.

References foedus::storage::hash::adjust_payload_hint(), ASSERT_ND, foedus::storage::hash::HashDataPage::bloom_filter(), foedus::storage::hash::HashCommonLogType::calculate_log_length(), CHECK_ERROR_CODE, foedus::storage::hash::DataPageBloomFilter::contains(), foedus::storage::hash::RecordLocation::cur_payload_length_, foedus::storage::hash::HashCombo::fingerprint_, get_bin_bits(), get_id(), foedus::storage::hash::RecordLocation::get_max_payload(), foedus::thread::Thread::get_thread_log_buffer(), foedus::storage::hash::HashCombo::hash_, foedus::storage::hash::HashDataPage::header(), foedus::storage::hash::RecordLocation::index_, foedus::xct::XctId::is_deleted(), foedus::storage::hash::RecordLocation::is_found(), locate_bin(), locate_record_logical(), foedus::storage::hash::RecordLocation::observed_, foedus::storage::hash::RecordLocation::page_, foedus::storage::hash::HashInsertLogType::populate(), foedus::storage::hash::HashUpdateLogType::populate(), foedus::storage::hash::HashOverwriteLogType::populate(), foedus::storage::hash::RecordLocation::record_, register_record_write_log(), foedus::log::ThreadLogBuffer::reserve_new_log(), foedus::thread::Thread::run_nested_sysxct(), and foedus::storage::PageHeader::snapshot_.

Referenced by foedus::storage::hash::HashStorage::upsert_record().

397  {
398  physical_payload_hint = adjust_payload_hint(payload_count, physical_payload_hint);
399 
400  // Upsert is a combination of what insert does and what delete does.
401  // If there isn't an existing physical record, it's exactly same as insert.
402  // If there is, it's _basically_ a delete followed by an insert.
403  // There are a few complications, depending on the status of the record.
404 
405  HashDataPage* bin_head;
406  CHECK_ERROR_CODE(locate_bin(context, true, combo, &bin_head));
407  ASSERT_ND(bin_head);
408 
409  while (true) { // we might retry due to migrate_record. not that often, tho.
410  RecordLocation location;
412  context,
413  true,
414  true,
415  physical_payload_hint,
416  key,
417  key_length,
418  combo,
419  bin_head,
420  &location));
421 
422  // we create if not exists, these are surely non-null
423  ASSERT_ND(location.is_found());
424  ASSERT_ND(location.record_);
425 
426  // Whether currently deleted or not, migrate it to make sure the record is long enough.
427  if (payload_count > location.get_max_payload()) {
428  HashDataPage* cur_page = location.page_;
429  ASSERT_ND(!cur_page->header().snapshot_);
430  ASSERT_ND(cur_page->bloom_filter().contains(combo.fingerprint_));
431  DataPageSlotIndex cur_index = location.index_;
432  DVLOG(2) << "Record expansion triggered. payload_count=" << payload_count
433  << ", current max=" << location.get_max_payload()
434  << ", size hint=" << physical_payload_hint;
435 
436  ReserveRecords functor(
437  context,
438  cur_page,
439  key,
440  key_length,
441  combo,
442  payload_count,
443  physical_payload_hint,
444  cur_index);
445  CHECK_ERROR_CODE(context->run_nested_sysxct(&functor, 5U));
446  DVLOG(2) << "Expanded record!";
447  continue; // need to re-locate the record. retry.
448  }
449 
450  ASSERT_ND(payload_count <= location.get_max_payload());
451  HashCommonLogType* log_common;
452  if (location.observed_.is_deleted()) {
453  // If it's a deleted record, this turns to be a plain insert.
454  uint16_t log_length = HashInsertLogType::calculate_log_length(key_length, payload_count);
455  HashInsertLogType* log_entry = reinterpret_cast<HashInsertLogType*>(
456  context->get_thread_log_buffer().reserve_new_log(log_length));
457  log_entry->populate(
458  get_id(),
459  key,
460  key_length,
461  get_bin_bits(),
462  combo.hash_,
463  payload,
464  payload_count);
465  log_common = log_entry;
466  } else if (location.cur_payload_length_ == payload_count) {
467  // If it's not changing payload size of existing record, we can conver it to an overwrite,
468  // which is more efficient
469  uint16_t log_length = HashUpdateLogType::calculate_log_length(key_length, payload_count);
470  HashOverwriteLogType* log_entry = reinterpret_cast<HashOverwriteLogType*>(
471  context->get_thread_log_buffer().reserve_new_log(log_length));
472  log_entry->populate(
473  get_id(),
474  key,
475  key_length,
476  get_bin_bits(),
477  combo.hash_,
478  payload,
479  0,
480  payload_count);
481  log_common = log_entry;
482  } else {
483  // If not, this is an update operation.
484  uint16_t log_length = HashUpdateLogType::calculate_log_length(key_length, payload_count);
485  HashUpdateLogType* log_entry = reinterpret_cast<HashUpdateLogType*>(
486  context->get_thread_log_buffer().reserve_new_log(log_length));
487  log_entry->populate(
488  get_id(),
489  key,
490  key_length,
491  get_bin_bits(),
492  combo.hash_,
493  payload,
494  payload_count);
495  log_common = log_entry;
496  }
497 
498  return register_record_write_log(context, location, log_common);
499  }
500 }
uint16_t adjust_payload_hint(uint16_t payload_count, uint16_t physical_payload_hint)
ErrorCode locate_record_logical(thread::Thread *context, bool for_write, bool create_if_notfound, uint16_t create_payload_length, const void *key, uint16_t key_length, const HashCombo &combo, HashDataPage *bin_head, RecordLocation *result)
locate_record()'s logical+physical version.
ErrorCode locate_bin(thread::Thread *context, bool for_write, const HashCombo &combo, HashDataPage **bin_head)
Find a pointer to the bin that contains records for the hash.
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
ErrorCode register_record_write_log(thread::Thread *context, const RecordLocation &location, log::RecordLogType *log_entry)
Used in the following methods.
#define CHECK_ERROR_CODE(x)
This macro calls x and checks its returned error code.
Definition: error_code.hpp:155
static uint16_t calculate_log_length(uint16_t key_length, uint16_t payload_count) __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

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::verify_single_thread ( Engine engine)

These are defined in hash_storage_verify.cpp.

Definition at line 42 of file hash_storage_verify.cpp.

References CHECK_AND_ASSERT, CHECK_ERROR, foedus::Attachable< HashStorageControlBlock >::control_block_, foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::Engine::get_memory_manager(), foedus::storage::VolatilePagePointer::is_null(), foedus::kRetOk, foedus::memory::GlobalVolatilePageResolver::resolve_offset(), and verify_single_thread_intermediate().

Referenced by foedus::storage::hash::HashStorage::verify_single_thread(), and verify_single_thread().

42  {
43  VolatilePagePointer pointer = control_block_->root_page_pointer_.volatile_pointer_;
44  if (!pointer.is_null()) {
45  // TASK(Hideaki) probably two versions: always follow volatile vs snapshot
46  // so far check volatile only
47  HashIntermediatePage* root = reinterpret_cast<HashIntermediatePage*>(
48  engine->get_memory_manager()->get_global_volatile_page_resolver().resolve_offset(pointer));
49  CHECK_AND_ASSERT(root->get_level() + 1U == control_block_->levels_);
51  }
52  return kRetOk;
53 }
HashStorageControlBlock * control_block_
The shared data on shared memory that has been initialized in some SOC or master engine.
Definition: attachable.hpp:111
ErrorStack verify_single_thread_intermediate(Engine *engine, HashIntermediatePage *page)
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.
#define CHECK_AND_ASSERT(x)

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::verify_single_thread ( thread::Thread context)

Definition at line 39 of file hash_storage_verify.cpp.

References foedus::thread::Thread::get_engine(), and verify_single_thread().

39  {
40  return verify_single_thread(context->get_engine());
41 }
ErrorStack verify_single_thread(Engine *engine)
These are defined in hash_storage_verify.cpp.

Here is the call graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::verify_single_thread_data ( Engine engine,
HashDataPage head 
)

Definition at line 87 of file hash_storage_verify.cpp.

References CHECK_AND_ASSERT, foedus::storage::hash::HashDataPage::get_bin(), foedus::xct::XctId::get_epoch(), foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::Engine::get_memory_manager(), foedus::xct::XctId::is_being_written(), foedus::xct::RwLockableXctId::is_keylocked(), foedus::storage::VolatilePagePointer::is_null(), foedus::Epoch::is_valid(), foedus::storage::kHashDataPageType, foedus::kRetOk, foedus::storage::hash::HashDataPage::Slot::tid_, and foedus::xct::RwLockableXctId::xct_id_.

Referenced by verify_single_thread_intermediate().

89  {
90  const auto& resolver = engine->get_memory_manager()->get_global_volatile_page_resolver();
91  HashBin bin = head->get_bin();
92  for (HashDataPage* page = head; page;) {
93  CHECK_AND_ASSERT(page->header().get_page_type() == kHashDataPageType);
94  CHECK_AND_ASSERT(!page->header().page_version_.is_locked());
95  CHECK_AND_ASSERT(!page->header().page_version_.is_moved());
96  CHECK_AND_ASSERT(!page->header().page_version_.is_retired());
97  CHECK_AND_ASSERT(page->header().masstree_in_layer_level_ == 0);
98  CHECK_AND_ASSERT(page->get_bin() == bin);
99 
100  page->assert_entries_impl();
101 
102  uint16_t records = page->get_record_count();
103  for (DataPageSlotIndex i = 0; i < records; ++i) {
104  HashDataPage::Slot* slot = page->get_slot_address(i);
105  CHECK_AND_ASSERT(!slot->tid_.is_keylocked());
106  CHECK_AND_ASSERT(!slot->tid_.xct_id_.is_being_written());
107  CHECK_AND_ASSERT(slot->tid_.xct_id_.get_epoch().is_valid());
108  }
109 
110  VolatilePagePointer next = page->next_page().volatile_pointer_;
111  page = nullptr;
112  if (!next.is_null()) {
113  page = reinterpret_cast<HashDataPage*>(resolver.resolve_offset(next));
114  }
115  }
116 
117  return kRetOk;
118 }
uint16_t DataPageSlotIndex
Definition: hash_id.hpp:196
uint64_t HashBin
Represents a bin of a hash value.
Definition: hash_id.hpp:142
const ErrorStack kRetOk
Normal return value for no-error case.
#define CHECK_AND_ASSERT(x)

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::storage::hash::HashStoragePimpl::verify_single_thread_intermediate ( Engine engine,
HashIntermediatePage page 
)

Definition at line 55 of file hash_storage_verify.cpp.

References foedus::storage::hash::HashBinRange::begin_, CHECK_AND_ASSERT, CHECK_ERROR, foedus::storage::hash::HashBinRange::end_, foedus::storage::hash::HashDataPage::get_bin(), foedus::storage::hash::HashIntermediatePage::get_bin_range(), foedus::memory::EngineMemory::get_global_volatile_page_resolver(), foedus::storage::hash::HashIntermediatePage::get_level(), foedus::Engine::get_memory_manager(), foedus::storage::PageHeader::get_page_type(), foedus::storage::hash::HashIntermediatePage::get_pointer(), foedus::storage::hash::HashIntermediatePage::header(), foedus::storage::PageVersion::is_locked(), foedus::storage::PageVersion::is_moved(), foedus::storage::VolatilePagePointer::is_null(), foedus::storage::PageVersion::is_retired(), foedus::storage::hash::kHashIntermediatePageFanout, foedus::storage::kHashIntermediatePageType, foedus::storage::hash::kHashMaxBins, foedus::kRetOk, foedus::storage::PageHeader::page_version_, verify_single_thread_data(), and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by verify_single_thread().

57  {
58  CHECK_AND_ASSERT(page->header().get_page_type() == kHashIntermediatePageType);
59  CHECK_AND_ASSERT(!page->header().page_version_.is_locked());
60  CHECK_AND_ASSERT(!page->header().page_version_.is_moved());
61  CHECK_AND_ASSERT(!page->header().page_version_.is_retired());
62  uint8_t level = page->get_level();
63  HashBin begin = page->get_bin_range().begin_;
64  HashBin interval = kHashMaxBins[level];
65  CHECK_AND_ASSERT(page->get_bin_range().end_ == begin + interval * kHashIntermediatePageFanout);
66  const auto& resolver = engine->get_memory_manager()->get_global_volatile_page_resolver();
67  for (uint8_t i = 0; i < kHashIntermediatePageFanout; ++i) {
68  DualPagePointer pointer = page->get_pointer(i);
69  if (!pointer.volatile_pointer_.is_null()) {
70  if (level == 0) {
71  HashDataPage* child = reinterpret_cast<HashDataPage*>(
72  resolver.resolve_offset(pointer.volatile_pointer_));
73  CHECK_AND_ASSERT(child->get_bin() == begin + i);
74  CHECK_ERROR(verify_single_thread_data(engine, child));
75  } else {
76  HashIntermediatePage* child = reinterpret_cast<HashIntermediatePage*>(
77  resolver.resolve_offset(pointer.volatile_pointer_));
78  CHECK_AND_ASSERT(child->get_level() + 1U == level);
79  CHECK_AND_ASSERT(child->get_bin_range().begin_ == begin + i * interval);
81  }
82  }
83  }
84  return kRetOk;
85 }
ErrorStack verify_single_thread_data(Engine *engine, HashDataPage *head)
ErrorStack verify_single_thread_intermediate(Engine *engine, HashIntermediatePage *page)
uint64_t HashBin
Represents a bin of a hash value.
Definition: hash_id.hpp:142
#define CHECK_ERROR(x)
This macro calls x and checks its returned value.
const ErrorStack kRetOk
Normal return value for no-error case.
const uint8_t kHashIntermediatePageFanout
Number of pointers in an intermediate page of hash storage.
Definition: hash_id.hpp:49
const uint64_t kHashMaxBins[]
kHashTotalBins[n] gives the maximum number of hash bins n-level hash can hold.
Definition: hash_id.hpp:74
#define CHECK_AND_ASSERT(x)

Here is the call graph for this function:

Here is the caller graph for this function:


The documentation for this class was generated from the following files: