libfoedus-core
FOEDUS Core Library
foedus::storage::array::ArrayComposer Class Referencefinal

Composer for an array storage. More...

Detailed Description

Composer for an array storage.

Note
This is a private implementation-details of Array Storage, thus file name ends with _impl. Do not include this header from a client program. There is no case client program needs to access this internal class.

Definition at line 51 of file array_composer_impl.hpp.

#include <array_composer_impl.hpp>

Public Member Functions

 ArrayComposer (Composer *parent)
 ArrayComposer methods. More...
 
std::string to_string () const
 
ErrorStack compose (const Composer::ComposeArguments &args)
 
ErrorStack construct_root (const Composer::ConstructRootArguments &args)
 
Composer::DropResult drop_volatiles (const Composer::DropVolatilesArguments &args)
 drop_volatiles and related methods More...
 
void drop_root_volatile (const Composer::DropVolatilesArguments &args)
 

Constructor & Destructor Documentation

foedus::storage::array::ArrayComposer::ArrayComposer ( Composer parent)
explicit

ArrayComposer methods.

Definition at line 59 of file array_composer_impl.cpp.

References ASSERT_ND, and foedus::storage::Storage< CONTROL_BLOCK >::exists().

60  : engine_(parent->get_engine()),
61  storage_id_(parent->get_storage_id()),
62  storage_(engine_, storage_id_) {
63  ASSERT_ND(storage_.exists());
64 }
bool exists() const
Returns whether this storage is already created.
Definition: storage.hpp:169
#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:

Member Function Documentation

ErrorStack foedus::storage::array::ArrayComposer::compose ( const Composer::ComposeArguments args)

Definition at line 66 of file array_composer_impl.cpp.

References foedus::storage::Composer::ComposeArguments::base_epoch_, CHECK_ERROR, foedus::debugging::StopWatch::elapsed_ms(), foedus::DefaultInitializable::initialize(), foedus::storage::kArrayStorage, foedus::storage::array::kMaxLevels, foedus::kRetOk, foedus::storage::Composer::ComposeArguments::log_streams_, foedus::storage::Composer::ComposeArguments::log_streams_count_, foedus::storage::Composer::ComposeArguments::previous_snapshot_files_, foedus::storage::Composer::ComposeArguments::root_info_page_, foedus::storage::Composer::ComposeArguments::snapshot_writer_, foedus::debugging::StopWatch::stop(), to_string(), foedus::DefaultInitializable::uninitialize(), and foedus::storage::Composer::ComposeArguments::work_memory_.

Referenced by foedus::storage::Composer::compose().

66  {
67  VLOG(0) << to_string() << " composing with " << args.log_streams_count_ << " streams.";
68  debugging::StopWatch stop_watch;
69 
70  snapshot::MergeSort merge_sort(
71  storage_id_,
73  args.base_epoch_,
74  args.log_streams_,
75  args.log_streams_count_,
76  kMaxLevels,
77  args.work_memory_);
78  CHECK_ERROR(merge_sort.initialize());
79 
80  ArrayComposeContext context(
81  engine_,
82  &merge_sort,
83  args.snapshot_writer_,
84  args.previous_snapshot_files_,
85  args.root_info_page_);
86  CHECK_ERROR(context.execute());
87 
88  CHECK_ERROR(merge_sort.uninitialize()); // no need for scoped release. its destructor is safe.
89 
90  stop_watch.stop();
91  LOG(INFO) << to_string() << " done in " << stop_watch.elapsed_ms() << "ms.";
92  return kRetOk;
93 }
const uint8_t kMaxLevels
Code in array storage assumes this number as the maximum number of levels.
Definition: array_id.hpp:118
#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::array::ArrayComposer::construct_root ( const Composer::ConstructRootArguments args)

Definition at line 95 of file array_composer_impl.cpp.

References ASSERT_ND, foedus::snapshot::SnapshotWriter::dump_pages(), foedus::storage::extract_snapshot_id_from_snapshot_pointer(), foedus::storage::array::ArrayPage::get_array_range(), foedus::storage::array::ArrayStorage::get_array_size(), foedus::Attachable< CONTROL_BLOCK >::get_control_block(), foedus::savepoint::SavepointManager::get_initial_durable_epoch(), foedus::storage::array::ArrayPage::get_interior_record(), foedus::storage::array::ArrayStorage::get_levels(), foedus::storage::Storage< CONTROL_BLOCK >::get_metadata(), foedus::snapshot::SnapshotWriter::get_next_page_id(), foedus::snapshot::SnapshotWriter::get_page_base(), foedus::storage::array::ArrayStorage::get_payload_size(), foedus::storage::array::LookupRouteFinder::get_records_in_leaf(), foedus::Engine::get_savepoint_manager(), foedus::snapshot::SnapshotWriter::get_snapshot_id(), foedus::storage::array::ArrayPage::header(), foedus::storage::array::ArrayPage::initialize_snapshot_page(), foedus::assorted::int_div_ceil(), foedus::storage::array::kInteriorFanout, foedus::kRetOk, foedus::storage::Composer::ConstructRootArguments::new_root_page_pointer_, foedus::storage::PageHeader::page_id_, foedus::storage::array::ArrayRootInfoPage::pointers_, foedus::storage::Composer::ConstructRootArguments::previous_snapshot_files_, foedus::cache::SnapshotFileSet::read_page(), foedus::storage::Composer::ConstructRootArguments::root_info_pages_, foedus::storage::Composer::ConstructRootArguments::root_info_pages_count_, foedus::storage::Metadata::root_snapshot_page_id_, foedus::storage::DualPagePointer::snapshot_pointer_, foedus::storage::Composer::ConstructRootArguments::snapshot_writer_, foedus::storage::PageHeader::storage_id_, and WRAP_ERROR_CODE.

Referenced by foedus::storage::Composer::construct_root().

95  {
96  // compose() created root_info_pages that contain pointers to fill in the root page,
97  // so we just find non-zero entry and copy it to root page.
98  uint8_t levels = storage_.get_levels();
99  uint16_t payload_size = storage_.get_payload_size();
100  snapshot::SnapshotId new_snapshot_id = args.snapshot_writer_->get_snapshot_id();
101  Epoch system_initial_epoch = engine_->get_savepoint_manager()->get_initial_durable_epoch();
102  if (levels == 1U) {
103  // if it's single-page array, we have already created the root page in compose().
104  ASSERT_ND(args.root_info_pages_count_ == 1U);
105  const ArrayRootInfoPage* casted
106  = reinterpret_cast<const ArrayRootInfoPage*>(args.root_info_pages_[0]);
107  ASSERT_ND(casted->pointers_[0] != 0);
108  *args.new_root_page_pointer_ = casted->pointers_[0];
109 
110  // and we have already installed it, right?
111  ASSERT_ND(storage_.get_control_block()->meta_.root_snapshot_page_id_
112  == casted->pointers_[0]);
113  ASSERT_ND(storage_.get_control_block()->root_page_pointer_.snapshot_pointer_
114  == casted->pointers_[0]);
115  } else {
116  ArrayPage* root_page = reinterpret_cast<ArrayPage*>(args.snapshot_writer_->get_page_base());
118  SnapshotPagePointer new_page_id = args.snapshot_writer_->get_next_page_id();
119  *args.new_root_page_pointer_ = new_page_id;
120 
121  uint64_t root_interval = LookupRouteFinder(levels, payload_size).get_records_in_leaf();
122  for (uint8_t level = 1; level < levels; ++level) {
123  root_interval *= kInteriorFanout;
124  }
125  ArrayRange range(0, root_interval, storage_.get_array_size());
126  if (page_id != 0) {
127  WRAP_ERROR_CODE(args.previous_snapshot_files_->read_page(page_id, root_page));
128  ASSERT_ND(root_page->header().storage_id_ == storage_id_);
129  ASSERT_ND(root_page->header().page_id_ == page_id);
130  ASSERT_ND(root_page->get_array_range() == range);
131  root_page->header().page_id_ = new_page_id;
132  } else {
133  root_page->initialize_snapshot_page(
134  system_initial_epoch,
135  storage_id_,
136  new_page_id,
137  payload_size,
138  levels - 1,
139  range);
140  }
141 
142  uint64_t child_interval = root_interval / kInteriorFanout;
143  uint16_t root_children = assorted::int_div_ceil(storage_.get_array_size(), child_interval);
144 
145  // overwrite pointers with root_info_pages.
146  for (uint32_t i = 0; i < args.root_info_pages_count_; ++i) {
147  const ArrayRootInfoPage* casted
148  = reinterpret_cast<const ArrayRootInfoPage*>(args.root_info_pages_[i]);
149  for (uint16_t j = 0; j < root_children; ++j) {
150  SnapshotPagePointer pointer = casted->pointers_[j];
151  if (pointer != 0) {
152  ASSERT_ND(extract_snapshot_id_from_snapshot_pointer(pointer) == new_snapshot_id);
153  DualPagePointer& record = root_page->get_interior_record(j);
154  // partitioning has no overlap, so this must be the only overwriting pointer
155  ASSERT_ND(record.snapshot_pointer_ == 0 ||
156  extract_snapshot_id_from_snapshot_pointer(record.snapshot_pointer_)
157  != new_snapshot_id);
158  record.snapshot_pointer_ = pointer;
159  }
160  }
161  for (uint16_t j = root_children; j < kInteriorFanout; ++j) {
162  ASSERT_ND(casted->pointers_[j] == 0);
163  }
164  }
165 
166  // even in initial snapshot, all pointers must be set because we create empty pages
167  // even if some sub-tree receives no logs.
168  for (uint16_t j = 0; j < root_children; ++j) {
169  ASSERT_ND(root_page->get_interior_record(j).snapshot_pointer_ != 0);
170  }
171 
172  WRAP_ERROR_CODE(args.snapshot_writer_->dump_pages(0, 1));
173  ASSERT_ND(args.snapshot_writer_->get_next_page_id() == new_page_id + 1ULL);
174  // AFTER writing out the root page, install the pointer to new root page
175  storage_.get_control_block()->root_page_pointer_.snapshot_pointer_ = new_page_id;
176  storage_.get_control_block()->meta_.root_snapshot_page_id_ = new_page_id;
177  }
178  return kRetOk;
179 }
uint16_t get_payload_size() const
Returns byte size of one record in this array storage without internal overheads. ...
const Metadata * get_metadata() const
Returns the metadata of this storage.
Definition: storage.hpp:162
ArrayOffset get_array_size() const
Returns the size of this array.
savepoint::SavepointManager * get_savepoint_manager() const
See Savepoint Manager.
Definition: engine.cpp:53
uint64_t SnapshotPagePointer
Page ID of a snapshot page.
Definition: storage_id.hpp:79
uint16_t extract_snapshot_id_from_snapshot_pointer(SnapshotPagePointer pointer)
Definition: storage_id.hpp:98
uint16_t SnapshotId
Unique ID of Snapshot.
Definition: snapshot_id.hpp:43
uint8_t get_levels() const
Returns the number of levels.
const ErrorStack kRetOk
Normal return value for no-error case.
int64_t int_div_ceil(int64_t dividee, int64_t dividor)
Efficient ceil(dividee/dividor) for integer.
const uint16_t kInteriorFanout
Max number of entries in an interior page of array storage.
Definition: array_id.hpp:110
#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.
CONTROL_BLOCK * get_control_block() const
Definition: attachable.hpp:97
SnapshotPagePointer root_snapshot_page_id_
Pointer to a snapshotted page this storage is rooted at.
Definition: metadata.hpp:112

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::storage::array::ArrayComposer::drop_root_volatile ( const Composer::DropVolatilesArguments args)

Definition at line 971 of file array_composer_impl.cpp.

References ASSERT_ND, foedus::storage::array::ArrayStorage::get_array_metadata(), foedus::storage::array::ArrayStorage::get_array_size(), foedus::Attachable< CONTROL_BLOCK >::get_control_block(), foedus::xct::XctId::get_epoch(), foedus::storage::array::ArrayPage::get_leaf_record(), foedus::storage::array::ArrayStorage::get_levels(), foedus::storage::Storage< CONTROL_BLOCK >::get_name(), foedus::storage::array::ArrayStorage::get_payload_size(), foedus::storage::array::ArrayPage::is_leaf(), foedus::Epoch::is_valid(), foedus::storage::Metadata::keeps_all_volatile_pages(), foedus::storage::Record::owner_id_, foedus::storage::Composer::DropVolatilesArguments::snapshot_, foedus::snapshot::Snapshot::valid_until_epoch_, foedus::storage::DualPagePointer::volatile_pointer_, and foedus::xct::RwLockableXctId::xct_id_.

Referenced by foedus::storage::Composer::drop_root_volatile().

971  {
972  if (storage_.get_array_metadata()->keeps_all_volatile_pages()) {
973  LOG(INFO) << "Oh, but keep-all-volatile is on. Storage-" << storage_.get_name()
974  << " is configured to keep all volatile pages.";
975  return;
976  }
977  if (is_to_keep_volatile(storage_.get_levels() - 1U)) {
978  LOG(INFO) << "Oh, but Storage-" << storage_.get_name() << " is configured to keep"
979  << " the root page.";
980  return;
981  }
982  DualPagePointer* root_pointer = &storage_.get_control_block()->root_page_pointer_;
983  ArrayPage* volatile_page = resolve_volatile(root_pointer->volatile_pointer_);
984  if (volatile_page == nullptr) {
985  LOG(INFO) << "Oh, but root volatile page already null";
986  return;
987  }
988 
989  if (volatile_page->is_leaf()) {
990  // if this is a single-level array. we now have to check epochs of records in the root page.
991  uint16_t records = storage_.get_array_size();
992  for (uint16_t i = 0; i < records; ++i) {
993  Record* record = volatile_page->get_leaf_record(i, storage_.get_payload_size());
994  Epoch epoch = record->owner_id_.xct_id_.get_epoch();
995  ASSERT_ND(epoch.is_valid());
996  if (epoch > args.snapshot_.valid_until_epoch_) {
997  LOG(INFO) << "Oh, but the root volatile page in single-level array contains a new rec";
998  return;
999  }
1000  }
1001  } else {
1002  // otherwise, all verifications already done. go drop everything!
1003  }
1004  LOG(INFO) << "Okay, drop em all!!";
1005  drop_all_recurse(args, root_pointer);
1006 }
const ArrayMetadata * get_array_metadata() const
bool keeps_all_volatile_pages() const
Definition: metadata.hpp:98
uint16_t get_payload_size() const
Returns byte size of one record in this array storage without internal overheads. ...
ArrayOffset get_array_size() const
Returns the size of this array.
const StorageName & get_name() const
Returns the unique name of this storage.
Definition: storage.hpp:155
uint8_t get_levels() const
Returns the number of levels.
#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
CONTROL_BLOCK * get_control_block() const
Definition: attachable.hpp:97

Here is the call graph for this function:

Here is the caller graph for this function:

Composer::DropResult foedus::storage::array::ArrayComposer::drop_volatiles ( const Composer::DropVolatilesArguments args)

drop_volatiles and related methods

Definition at line 929 of file array_composer_impl.cpp.

References ASSERT_ND, foedus::storage::Composer::DropResult::combine(), foedus::storage::Composer::DropResult::dropped_all_, foedus::storage::extract_numa_node_from_snapshot_pointer(), foedus::storage::array::ArrayStorage::get_array_metadata(), foedus::Attachable< CONTROL_BLOCK >::get_control_block(), foedus::storage::array::ArrayPage::get_interior_record(), foedus::storage::Storage< CONTROL_BLOCK >::get_name(), foedus::storage::array::ArrayPage::is_leaf(), foedus::storage::VolatilePagePointer::is_null(), foedus::storage::Metadata::keeps_all_volatile_pages(), foedus::storage::array::kInteriorFanout, foedus::storage::Composer::DropVolatilesArguments::my_partition_, foedus::storage::Composer::DropVolatilesArguments::partitioned_drop_, foedus::storage::DualPagePointer::snapshot_pointer_, and foedus::storage::DualPagePointer::volatile_pointer_.

Referenced by foedus::storage::Composer::drop_volatiles().

929  {
930  Composer::DropResult result(args);
931  if (storage_.get_array_metadata()->keeps_all_volatile_pages()) {
932  LOG(INFO) << "Keep-all-volatile: Storage-" << storage_.get_name()
933  << " is configured to keep all volatile pages.";
934  result.dropped_all_ = false;
935  return result;
936  }
937 
938  DualPagePointer* root_pointer = &storage_.get_control_block()->root_page_pointer_;
939  ArrayPage* volatile_page = resolve_volatile(root_pointer->volatile_pointer_);
940  if (volatile_page == nullptr) {
941  LOG(INFO) << "No volatile root page. Probably while restart";
942  return result;
943  }
944 
945  // single-page array has only the root page. nothing to do here.
946  // we might drop the root page later, just like non-single-page cases.
947  if (volatile_page->is_leaf()) {
948  LOG(INFO) << "Single-page array skipped by .";
949  return result;
950  }
951 
952  // We iterate through all existing volatile pages to drop volatile pages of
953  // level-3 or deeper (if the storage has only 2 levels, keeps all).
954  // this "level-3 or deeper" is a configuration per storage.
955  // Even if the volatile page is deeper than that, we keep them if it contains newer modification,
956  // including descendants (so, probably we will keep higher levels anyways).
957  for (uint16_t i = 0; i < kInteriorFanout; ++i) {
958  DualPagePointer& child_pointer = volatile_page->get_interior_record(i);
959  if (!child_pointer.volatile_pointer_.is_null()) {
960  ASSERT_ND(child_pointer.snapshot_pointer_ != 0);
961  uint16_t partition = extract_numa_node_from_snapshot_pointer(child_pointer.snapshot_pointer_);
962  if (!args.partitioned_drop_ || partition == args.my_partition_) {
963  result.combine(drop_volatiles_recurse(args, &child_pointer));
964  }
965  }
966  }
967  // root page is kept at this point in this case. we need to check with other threads
968  return result;
969 }
const ArrayMetadata * get_array_metadata() const
bool keeps_all_volatile_pages() const
Definition: metadata.hpp:98
const StorageName & get_name() const
Returns the unique name of this storage.
Definition: storage.hpp:155
uint8_t extract_numa_node_from_snapshot_pointer(SnapshotPagePointer pointer)
Definition: storage_id.hpp:95
const uint16_t kInteriorFanout
Max number of entries in an interior page of array storage.
Definition: array_id.hpp:110
#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
CONTROL_BLOCK * get_control_block() const
Definition: attachable.hpp:97

Here is the call graph for this function:

Here is the caller graph for this function:

std::string foedus::storage::array::ArrayComposer::to_string ( ) const

Definition at line 182 of file array_composer_impl.cpp.

Referenced by compose().

182  {
183  return std::string("ArrayComposer-") + std::to_string(storage_id_);
184 }

Here is the caller graph for this function:


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