libfoedus-core
FOEDUS Core Library
foedus::snapshot::SnapshotWriter Class Referencefinal

Writes out one snapshot file for all data pages in one reducer. More...

Detailed Description

Writes out one snapshot file for all data pages in one reducer.

In a nutshell, snapshot writer is a in-memory page pool that dumps out some or all of the pages to a snapshot file. It consists of 3 phases for each storage.

Compose Phase
This first phase is invoked by the composers, loading prior snapshot pages and modifying them. Here, snapshot writers behave just as a usual in-memory page pool. This part depends on composer, so the snapshot writer calls composer's method.
Fix Phase
Next phase is invoked at the end of composer for the storage, finalizing page ID in the snapshot file for each modified page and replacing volatile page pointers with snapshot pointers. This part also depends on composer (or page format of the storage), so this is done by composer.
Dump Phase
The last phase simply dumps out the pages to snapshot file. This is a sequential write because no two storages have overlapping pages. This is independent from storage type, thus done in snapshot writer.
Conquer already-divided
Snapshot writer might not have enough pages to hold all pages of the storage modified in this snapshot. This can happen for a large storage with lots of changes. No worry, we have already sorted log entries by keys for this reason. When the page pool becomes fully occupied, we go on to the fix/dump phase, only keeping the right-most pages in all levels. After dumping everything else, we repeat the compose phase just like moving on to another storage.
Note
This is a private implementation-details of Snapshot Manager, 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 76 of file snapshot_writer_impl.hpp.

#include <snapshot_writer_impl.hpp>

Public Member Functions

 SnapshotWriter (Engine *engine, uint16_t numa_node, SnapshotId snapshot_id, memory::AlignedMemory *pool_memory, memory::AlignedMemory *intermediate_memory, bool append=false)
 
 ~SnapshotWriter ()
 
ErrorStack open ()
 Open the file so that the writer can start writing. More...
 
bool is_opened () const
 
bool close ()
 Close the file and makes sure all writes become durable (including the directory entry). More...
 
 SnapshotWriter ()=delete
 
 SnapshotWriter (const SnapshotWriter &other)=delete
 
SnapshotWriteroperator= (const SnapshotWriter &other)=delete
 
uint16_t get_numa_node () const
 
storage::Pageget_page_base () __attribute__((always_inline))
 
memory::PagePoolOffset get_page_size () const __attribute__((always_inline))
 
storage::Pageget_intermediate_base () __attribute__((always_inline))
 
memory::PagePoolOffset get_intermediate_size () const __attribute__((always_inline))
 
storage::SnapshotPagePointer get_next_page_id () const
 
SnapshotId get_snapshot_id () const
 
storage::Pageresolve (memory::PagePoolOffset offset) __attribute__((always_inline))
 
memory::PagePoolOffset resolve (storage::Page *page) __attribute__((always_inline))
 
ErrorCode dump_pages (memory::PagePoolOffset from_page, uint32_t count)
 Write out pages that are contiguous in the main page pool. More...
 
ErrorCode dump_intermediates (memory::PagePoolOffset from_page, uint32_t count)
 Write out pages that are contiguous in the sub intermediate page pool. More...
 
std::string to_string () const
 
ErrorCode expand_pool_memory (uint32_t required_pages, bool retain_content)
 Expands pool_memory_ in case it is too small. More...
 
ErrorCode expand_intermediate_memory (uint32_t required_pages, bool retain_content)
 Expands intermediate_memory_ in case it is too small. More...
 

Friends

std::ostream & operator<< (std::ostream &o, const SnapshotWriter &v)
 

Constructor & Destructor Documentation

foedus::snapshot::SnapshotWriter::SnapshotWriter ( Engine engine,
uint16_t  numa_node,
SnapshotId  snapshot_id,
memory::AlignedMemory pool_memory,
memory::AlignedMemory intermediate_memory,
bool  append = false 
)

Definition at line 36 of file snapshot_writer_impl.cpp.

43  : engine_(engine),
44  numa_node_(numa_node),
45  append_(append),
46  snapshot_id_(snapshot_id),
47  pool_memory_(pool_memory),
48  intermediate_memory_(intermediate_memory),
49  snapshot_file_(nullptr),
50  next_page_id_(0) {
51 }
foedus::snapshot::SnapshotWriter::~SnapshotWriter ( )
inline

Definition at line 85 of file snapshot_writer_impl.hpp.

References close().

85 { close(); }
bool close()
Close the file and makes sure all writes become durable (including the directory entry).

Here is the call graph for this function:

foedus::snapshot::SnapshotWriter::SnapshotWriter ( )
delete
foedus::snapshot::SnapshotWriter::SnapshotWriter ( const SnapshotWriter other)
delete

Member Function Documentation

bool foedus::snapshot::SnapshotWriter::close ( )

Close the file and makes sure all writes become durable (including the directory entry).

Returns
whether successfully closed and synced.

Definition at line 53 of file snapshot_writer_impl.cpp.

References foedus::fs::DirectIoFile::close(), foedus::fs::fsync(), and foedus::fs::DirectIoFile::get_path().

Referenced by open(), and ~SnapshotWriter().

53  {
54  if (snapshot_file_) {
55  bool success = true;
56  fs::Path path = snapshot_file_->get_path();
57  bool closed = snapshot_file_->close();
58  if (!closed) {
59  LOG(ERROR) << "Failed to close a snapshot file: " << *this;
60  success = false;
61  }
62  // also fsync the file.
63  if (!fs::fsync(path, true)) {
64  LOG(ERROR) << "Failed to fsync a snapshot file: " << *this;
65  success = false;
66  }
67 
68  delete snapshot_file_;
69  snapshot_file_ = nullptr;
70  return success;
71  } else {
72  return true;
73  }
74 }
bool close()
Close the file if not yet closed.
bool fsync(const Path &path, bool sync_parent_directory=false)
Makes the content and metadata of the file durable all the way up to devices.
Definition: filesystem.cpp:203

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::snapshot::SnapshotWriter::dump_intermediates ( memory::PagePoolOffset  from_page,
uint32_t  count 
)
inline

Write out pages that are contiguous in the sub intermediate page pool.

Parameters
[in]from_pagebeginning of contiguous in-memory pages to fix
[in]countnumber of pages to write out

Definition at line 144 of file snapshot_writer_impl.hpp.

144  {
145  return dump_general(intermediate_memory_, from_page, count);
146  }
ErrorCode foedus::snapshot::SnapshotWriter::dump_pages ( memory::PagePoolOffset  from_page,
uint32_t  count 
)
inline

Write out pages that are contiguous in the main page pool.

Parameters
[in]from_pagebeginning of contiguous in-memory pages to fix
[in]countnumber of pages to write out

Definition at line 135 of file snapshot_writer_impl.hpp.

Referenced by foedus::storage::hash::ComposedBinsMergedStream::assure_writer_buffer(), foedus::storage::array::ArrayComposer::construct_root(), foedus::storage::hash::HashComposer::construct_root(), foedus::storage::masstree::MasstreeComposer::construct_root(), and foedus::storage::sequential::SequentialComposer::construct_root().

135  {
136  return dump_general(pool_memory_, from_page, count);
137  }

Here is the caller graph for this function:

ErrorCode foedus::snapshot::SnapshotWriter::expand_intermediate_memory ( uint32_t  required_pages,
bool  retain_content 
)

Expands intermediate_memory_ in case it is too small.

Parameters
[in]required_pagesnumber of pages that are guaranteed after expansion. The actual size will probably be larger than this value to avoid frequent expansion.
[in]retain_contentwhether to copy the content of old memory to new memory
Postcondition
get_intermediate_size() >= required_pages
Returns
only possible error is out of memory
Note
intermediate_base will be also changed, so do not forget to re-obtain it.

Does nothing if it's already enough large. We use this method to make sure intermediate pool (which some composer assumes sufficiently large) can contain all intermediate pages.

Definition at line 163 of file snapshot_writer_impl.cpp.

References ASSERT_ND, foedus::memory::AlignedMemory::assure_capacity(), CHECK_ERROR_CODE, get_intermediate_size(), and foedus::kErrorCodeOk.

Referenced by foedus::storage::hash::ComposedBinsMergedStream::assure_writer_buffer().

163  {
164  if (required_pages <= get_intermediate_size()) {
165  return kErrorCodeOk;
166  }
167 
168  uint64_t bytes = required_pages * sizeof(storage::Page);
169  CHECK_ERROR_CODE(intermediate_memory_->assure_capacity(bytes, 2.0, retain_content));
170  ASSERT_ND(get_intermediate_size() >= required_pages);
171  return kErrorCodeOk;
172 }
ErrorCode assure_capacity(uint64_t required_size, double expand_margin=2.0, bool retain_content=false) noexcept
If the current size is smaller than the given size, automatically expands.
0 means no-error.
Definition: error_code.hpp:87
memory::PagePoolOffset get_intermediate_size() const __attribute__((always_inline))
#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::snapshot::SnapshotWriter::expand_pool_memory ( uint32_t  required_pages,
bool  retain_content 
)

Expands pool_memory_ in case it is too small.

Parameters
[in]required_pagesnumber of pages that are guaranteed after expansion. The actual size will probably be larger than this value to avoid frequent expansion.
[in]retain_contentwhether to copy the content of old memory to new memory
Postcondition
get_page_size() >= required_pages
Returns
only possible error is out of memory
Note
page_base will be also changed, so do not forget to re-obtain it.

Does nothing if it's already enough large. Most likely we don't have to use this method as composers should be able to run even when the number of leaf (content) pages is large.

Definition at line 150 of file snapshot_writer_impl.cpp.

References ASSERT_ND, foedus::memory::AlignedMemory::assure_capacity(), CHECK_ERROR_CODE, get_page_size(), and foedus::kErrorCodeOk.

150  {
151  if (required_pages <= get_page_size()) {
152  return kErrorCodeOk;
153  }
154 
155  uint64_t bytes = required_pages * sizeof(storage::Page);
156  CHECK_ERROR_CODE(pool_memory_->assure_capacity(bytes, 2.0, retain_content));
157  ASSERT_ND(get_page_size() >= required_pages);
158  return kErrorCodeOk;
159 }
memory::PagePoolOffset get_page_size() const __attribute__((always_inline))
ErrorCode assure_capacity(uint64_t required_size, double expand_margin=2.0, bool retain_content=false) noexcept
If the current size is smaller than the given size, automatically expands.
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:

storage::Page* foedus::snapshot::SnapshotWriter::get_intermediate_base ( )
inline

Definition at line 108 of file snapshot_writer_impl.hpp.

References foedus::memory::AlignedMemory::get_block().

Referenced by foedus::storage::array::ArrayComposeContext::ArrayComposeContext(), foedus::storage::hash::HashComposeContext::HashComposeContext(), and foedus::storage::hash::ComposedBinsMergedStream::open_path().

108  {
109  return reinterpret_cast<storage::Page*>(intermediate_memory_->get_block());
110  }
void * get_block() const
Returns the memory block.

Here is the call graph for this function:

Here is the caller graph for this function:

memory::PagePoolOffset foedus::snapshot::SnapshotWriter::get_intermediate_size ( ) const
inline

Definition at line 111 of file snapshot_writer_impl.hpp.

References foedus::memory::AlignedMemory::get_size(), and foedus::storage::kPageSize.

Referenced by foedus::storage::array::ArrayComposeContext::ArrayComposeContext(), foedus::storage::hash::ComposedBinsMergedStream::assure_writer_buffer(), expand_intermediate_memory(), foedus::storage::hash::HashComposeContext::HashComposeContext(), and foedus::storage::hash::ComposedBinsMergedStream::open_path().

111  {
112  return intermediate_memory_->get_size() / storage::kPageSize;
113  }
uint64_t get_size() const
Returns the byte size of the memory block.
const uint16_t kPageSize
A constant defining the page size (in bytes) of both snapshot pages and volatile pages.
Definition: storage_id.hpp:45

Here is the call graph for this function:

Here is the caller graph for this function:

uint16_t foedus::snapshot::SnapshotWriter::get_numa_node ( ) const
inline
memory::PagePoolOffset foedus::snapshot::SnapshotWriter::get_page_size ( ) const
inline

Definition at line 105 of file snapshot_writer_impl.hpp.

References foedus::memory::AlignedMemory::get_size(), and foedus::storage::kPageSize.

Referenced by foedus::storage::array::ArrayComposeContext::ArrayComposeContext(), foedus::storage::hash::ComposedBinsMergedStream::assure_writer_buffer(), foedus::storage::sequential::SequentialComposer::compose(), expand_pool_memory(), foedus::storage::hash::HashComposeContext::HashComposeContext(), foedus::storage::hash::ComposedBinsMergedStream::open_path(), and resolve().

105  {
106  return pool_memory_->get_size() / storage::kPageSize;
107  }
uint64_t get_size() const
Returns the byte size of the memory block.
const uint16_t kPageSize
A constant defining the page size (in bytes) of both snapshot pages and volatile pages.
Definition: storage_id.hpp:45

Here is the call graph for this function:

Here is the caller graph for this function:

bool foedus::snapshot::SnapshotWriter::is_opened ( ) const
inline

Definition at line 89 of file snapshot_writer_impl.hpp.

89 { return snapshot_file_; }
ErrorStack foedus::snapshot::SnapshotWriter::open ( )

Open the file so that the writer can start writing.

Definition at line 82 of file snapshot_writer_impl.cpp.

References ASSERT_ND, foedus::storage::PageHeader::checksum_, close(), foedus::snapshot::SnapshotOptions::emulation_, foedus::fs::file_size(), foedus::memory::AlignedMemory::get_block(), foedus::fs::DirectIoFile::get_current_offset(), foedus::Engine::get_options(), foedus::kRetOk, foedus::fs::DirectIoFile::open(), foedus::storage::PageHeader::page_id_, foedus::EngineOptions::snapshot_, foedus::storage::PageHeader::storage_id_, foedus::storage::to_snapshot_page_pointer(), to_string(), WRAP_ERROR_CODE, and foedus::fs::DirectIoFile::write().

82  {
83  close();
84  fs::Path path(get_snapshot_file_path());
85  snapshot_file_ = new fs::DirectIoFile(path, engine_->get_options().snapshot_.emulation_);
86  bool create_new_file = append_ ? false : true;
87  WRAP_ERROR_CODE(snapshot_file_->open(true, true, true, create_new_file));
88  if (!append_) {
89  // write page-0. this is a dummy page which will never be read
90  char* first_page = reinterpret_cast<char*>(pool_memory_->get_block());
91  // first 8 bytes have some data, but we would use them just for sanity checks and debugging
92  storage::PageHeader* first_page_header = reinterpret_cast<storage::PageHeader*>(first_page);
93  first_page_header->page_id_ = storage::to_snapshot_page_pointer(snapshot_id_, numa_node_, 0);
94  first_page_header->storage_id_ = 0x1BF0ED05; // something unusual
95  first_page_header->checksum_ = 0x1BF0ED05; // something unusual
96  std::memset(
97  first_page + sizeof(storage::PageHeader),
98  0,
99  sizeof(storage::Page) - sizeof(storage::PageHeader));
100  std::string duh("This is the first 4kb page of a snapshot file in libfoedus."
101  " The first page is never used as data. It just has the common page header"
102  " and these useless sentences. Maybe we put our complaints on our cafeteria here.");
103  std::memcpy(first_page + sizeof(storage::PageHeader), duh.data(), duh.size());
104 
105  WRAP_ERROR_CODE(snapshot_file_->write(sizeof(storage::Page), *pool_memory_));
106  next_page_id_ = storage::to_snapshot_page_pointer(snapshot_id_, numa_node_, 1);
107  } else {
108  // if appending, nothing to do
109  uint64_t file_size = snapshot_file_->get_current_offset();
110  LOG(INFO) << to_string() << " Appending to " << file_size << "th bytes";
111  ASSERT_ND(file_size >= sizeof(storage::Page)); // have at least the dummy page
112  ASSERT_ND(file_size % sizeof(storage::Page) == 0); // must be aligned writes
113  uint64_t next_offset = file_size / sizeof(storage::Page);
114  next_page_id_ = storage::to_snapshot_page_pointer(snapshot_id_, numa_node_, next_offset);
115  }
116  return kRetOk;
117 }
bool close()
Close the file and makes sure all writes become durable (including the directory entry).
ErrorCode write(uint64_t desired_bytes, const foedus::memory::AlignedMemory &buffer)
Sequentially write the given amount of contents from the current position.
foedus::fs::DeviceEmulationOptions emulation_
Settings to emulate slower data device.
SnapshotPagePointer to_snapshot_page_pointer(uint16_t snapshot_id, uint8_t node, SnapshotLocalPageId local_page_id)
Definition: storage_id.hpp:106
ErrorCode open(bool read, bool write, bool append, bool create)
Tries to open the file for the specified volume.
uint64_t get_current_offset() const
const EngineOptions & get_options() const
Definition: engine.cpp:39
snapshot::SnapshotOptions snapshot_
void * get_block() const
Returns the memory block.
uint64_t file_size(const Path &p)
Returns size of the file.
Definition: filesystem.cpp:120
const ErrorStack kRetOk
Normal return value for no-error case.
#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.

Here is the call graph for this function:

SnapshotWriter& foedus::snapshot::SnapshotWriter::operator= ( const SnapshotWriter other)
delete
storage::Page* foedus::snapshot::SnapshotWriter::resolve ( memory::PagePoolOffset  offset)
inline

Definition at line 118 of file snapshot_writer_impl.hpp.

References ASSERT_ND, get_page_base(), and get_page_size().

118  {
119  ASSERT_ND(offset > 0);
120  ASSERT_ND(offset < get_page_size());
121  return get_page_base() + offset;
122  }
memory::PagePoolOffset get_page_size() const __attribute__((always_inline))
storage::Page * get_page_base() __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:

memory::PagePoolOffset foedus::snapshot::SnapshotWriter::resolve ( storage::Page page)
inline

Definition at line 123 of file snapshot_writer_impl.hpp.

References ASSERT_ND, get_page_base(), and get_page_size().

123  {
124  memory::PagePoolOffset offset = page - get_page_base();
125  ASSERT_ND(offset > 0);
126  ASSERT_ND(offset < get_page_size());
127  return offset;
128  }
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
memory::PagePoolOffset get_page_size() const __attribute__((always_inline))
storage::Page * get_page_base() __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:

std::string foedus::snapshot::SnapshotWriter::to_string ( ) const
inline

Definition at line 148 of file snapshot_writer_impl.hpp.

Referenced by open().

148  {
149  return "SnapshotWriter-" + std::to_string(numa_node_) + (append_ ? "(append)" : "");
150  }

Here is the caller graph for this function:

Friends And Related Function Documentation

std::ostream& operator<< ( std::ostream &  o,
const SnapshotWriter v 
)
friend

Definition at line 174 of file snapshot_writer_impl.cpp.

174  {
175  o << "<SnapshotWriter>"
176  << "<numa_node_>" << v.numa_node_ << "</numa_node_>"
177  << "<append_>" << v.append_ << "</append_>"
178  << "<snapshot_id_>" << v.snapshot_id_ << "</snapshot_id_>"
179  << "<pool_memory_>" << *v.pool_memory_ << "</pool_memory_>"
180  << "<intermediate_memory_>" << *v.intermediate_memory_ << "</intermediate_memory_>"
181  << "<next_page_id_>" << v.next_page_id_ << "</next_page_id_>"
182  << "</SnapshotWriter>";
183  return o;
184 }

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