libfoedus-core
FOEDUS Core Library
foedus::memory::PagePoolPimpl Class Referencefinal

Pimpl object of PagePool. More...

Detailed Description

Pimpl object of PagePool.

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

Definition at line 74 of file page_pool_pimpl.hpp.

#include <page_pool_pimpl.hpp>

Inheritance diagram for foedus::memory::PagePoolPimpl:
Collaboration diagram for foedus::memory::PagePoolPimpl:

Public Member Functions

 PagePoolPimpl ()
 
void attach (PagePoolControlBlock *control_block, void *memory, uint64_t memory_size, bool owns, bool rigorous_page_boundary_check)
 
ErrorStack initialize_once () override
 
ErrorStack uninitialize_once () override
 
ErrorCode grab (uint32_t desired_grab_count, PagePoolOffsetChunk *chunk)
 
template<typename CHUNK >
void release_impl (uint32_t desired_release_count, CHUNK *chunk)
 
void release (uint32_t desired_release_count, PagePoolOffsetChunk *chunk)
 
void release (uint32_t desired_release_count, PagePoolOffsetDynamicChunk *chunk)
 
void release (uint32_t desired_release_count, PagePoolOffsetAndEpochChunk *chunk)
 
ErrorCode grab_one (PagePoolOffset *offset)
 
void release_one (PagePoolOffset offset)
 
const LocalPageResolverget_resolver () const
 
PagePool::Stat get_stat () const
 
uint64_t & free_pool_head ()
 
uint64_t free_pool_head () const
 
uint64_t get_free_pool_capacity () const
 
uint64_t get_free_pool_count () const
 
void increase_free_pool_count (uint64_t op)
 
void decrease_free_pool_count (uint64_t op)
 
void assert_free_pool () const
 Not thread safe. More...
 
std::string get_debug_pool_name () const
 
void set_debug_pool_name (const std::string &name)
 
- Public Member Functions inherited from foedus::DefaultInitializable
 DefaultInitializable ()
 
virtual ~DefaultInitializable ()
 
 DefaultInitializable (const DefaultInitializable &)=delete
 
DefaultInitializableoperator= (const DefaultInitializable &)=delete
 
ErrorStack initialize () override final
 Typical implementation of Initializable::initialize() that provides initialize-once semantics. More...
 
ErrorStack uninitialize () override final
 Typical implementation of Initializable::uninitialize() that provides uninitialize-once semantics. More...
 
bool is_initialized () const override final
 Returns whether the object has been already initialized or not. More...
 
- Public Member Functions inherited from foedus::Initializable
virtual ~Initializable ()
 

Public Attributes

PagePoolControlBlockcontrol_block_
 
void * memory_
 The whole memory region of the pool. More...
 
uint64_t memory_size_
 Byte size of this page pool. More...
 
bool owns_
 Whether this engine owns this page pool. More...
 
bool rigorous_page_boundary_check_
 Whether to use mprotect() for page boundaries to detect bogus memory accesses. More...
 
LocalPageResolver resolver_
 An object to resolve an offset in this page pool (thus local) to an actual pointer and vice versa. More...
 
storage::Pagepool_base_
 Just an auxiliary variable to the beginning of the pool. More...
 
uint64_t pool_size_
 Just an auxiliary variable of the size of pool. More...
 
uint64_t pages_for_free_pool_
 This many first pages are used for free page maintainance. More...
 
PagePoolOffsetfree_pool_
 We maintain free pages as a simple circular queue. More...
 
uint64_t free_pool_capacity_
 Size of free_pool_. More...
 

Friends

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

Constructor & Destructor Documentation

foedus::memory::PagePoolPimpl::PagePoolPimpl ( )

Definition at line 40 of file page_pool_pimpl.cpp.

41  : control_block_(nullptr),
42  memory_(nullptr),
43  memory_size_(0),
44  owns_(false),
bool rigorous_page_boundary_check_
Whether to use mprotect() for page boundaries to detect bogus memory accesses.
void * memory_
The whole memory region of the pool.
PagePoolControlBlock * control_block_
bool owns_
Whether this engine owns this page pool.
uint64_t memory_size_
Byte size of this page pool.

Member Function Documentation

void foedus::memory::PagePoolPimpl::assert_free_pool ( ) const
inline

Not thread safe.

Use it after taking a lock.

Definition at line 108 of file page_pool_pimpl.hpp.

References ASSERT_ND, free_pool_, free_pool_capacity_, free_pool_head(), get_free_pool_count(), pages_for_free_pool_, and pool_size_.

Referenced by grab(), initialize_once(), release_impl(), and uninitialize_once().

108  {
109 #ifndef NDEBUG
110  const uint64_t free_count = get_free_pool_count();
111  const uint64_t free_head = free_pool_head();
112  for (uint64_t i = 0; i < free_count; ++i) {
113  uint64_t index = free_head + i;
114  while (index >= free_pool_capacity_) {
115  index -= free_pool_capacity_;
116  }
117  PagePoolOffset* address = free_pool_ + index;
118  ASSERT_ND(*address >= pages_for_free_pool_);
119  ASSERT_ND(*address < pool_size_);
120  }
121 #endif // NDEBUG
122  }
uint64_t get_free_pool_count() const
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
uint64_t free_pool_capacity_
Size of free_pool_.
uint64_t pool_size_
Just an auxiliary variable of the size of pool.
uint64_t pages_for_free_pool_
This many first pages are used for free page maintainance.
#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
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::memory::PagePoolPimpl::attach ( PagePoolControlBlock control_block,
void *  memory,
uint64_t  memory_size,
bool  owns,
bool  rigorous_page_boundary_check 
)

Definition at line 47 of file page_pool_pimpl.cpp.

References foedus::assorted::FixedString< MAXLEN, CHAR >::clear(), control_block_, foedus::memory::PagePoolControlBlock::debug_pool_name_, free_pool_, free_pool_capacity_, foedus::assorted::int_div_ceil(), foedus::storage::kPageSize, memory_, memory_size_, owns_, pages_for_free_pool_, pool_base_, pool_size_, resolver_, and rigorous_page_boundary_check_.

Referenced by foedus::memory::PagePool::attach().

52  {
53  control_block_ = control_block;
54  if (owns) {
56  }
57  memory_ = memory;
58  memory_size_ = memory_size;
59  owns_ = owns;
60  rigorous_page_boundary_check_ = rigorous_page_boundary_check;
61  pool_base_ = reinterpret_cast<storage::Page*>(memory_);
63 
64  uint64_t pointers_total_size = pool_size_ * sizeof(PagePoolOffset);
66 
67  free_pool_ = reinterpret_cast<PagePoolOffset*>(memory_);
69  if (rigorous_page_boundary_check) {
71  }
72  resolver_ = LocalPageResolver(pool_base_, pages_for_free_pool_, pool_size_);
73 }
bool rigorous_page_boundary_check_
Whether to use mprotect() for page boundaries to detect bogus memory accesses.
void * memory_
The whole memory region of the pool.
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
storage::Page * pool_base_
Just an auxiliary variable to the beginning of the pool.
uint64_t free_pool_capacity_
Size of free_pool_.
PagePoolControlBlock * control_block_
uint64_t pool_size_
Just an auxiliary variable of the size of pool.
bool owns_
Whether this engine owns this page pool.
LocalPageResolver resolver_
An object to resolve an offset in this page pool (thus local) to an actual pointer and vice versa...
assorted::FixedString< 60 > debug_pool_name_
just for debugging/logging.
uint64_t pages_for_free_pool_
This many first pages are used for free page maintainance.
int64_t int_div_ceil(int64_t dividee, int64_t dividor)
Efficient ceil(dividee/dividor) for integer.
void clear() noexcept
Clear string.
const uint16_t kPageSize
A constant defining the page size (in bytes) of both snapshot pages and volatile pages.
Definition: storage_id.hpp:45
uint64_t memory_size_
Byte size of this page pool.
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::memory::PagePoolPimpl::decrease_free_pool_count ( uint64_t  op)
inline

Definition at line 103 of file page_pool_pimpl.hpp.

References ASSERT_ND, control_block_, and foedus::memory::PagePoolControlBlock::free_pool_count_.

Referenced by grab(), and grab_one().

103  {
106  }
PagePoolControlBlock * control_block_
uint64_t free_pool_count_
Number of free pages.
#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 caller graph for this function:

uint64_t& foedus::memory::PagePoolPimpl::free_pool_head ( )
inline

Definition at line 98 of file page_pool_pimpl.hpp.

References control_block_, and foedus::memory::PagePoolControlBlock::free_pool_head_.

Referenced by assert_free_pool(), grab(), grab_one(), foedus::memory::operator<<(), release_impl(), and release_one().

PagePoolControlBlock * control_block_
uint64_t free_pool_head_
Inclusive head of the circular queue.

Here is the caller graph for this function:

uint64_t foedus::memory::PagePoolPimpl::free_pool_head ( ) const
inline

Definition at line 99 of file page_pool_pimpl.hpp.

References control_block_, and foedus::memory::PagePoolControlBlock::free_pool_head_.

PagePoolControlBlock * control_block_
uint64_t free_pool_head_
Inclusive head of the circular queue.
std::string foedus::memory::PagePoolPimpl::get_debug_pool_name ( ) const
inline

Definition at line 124 of file page_pool_pimpl.hpp.

References control_block_, foedus::memory::PagePoolControlBlock::debug_pool_name_, foedus::assorted::FixedString< MAXLEN, CHAR >::empty(), and foedus::assorted::FixedString< MAXLEN, CHAR >::str().

Referenced by foedus::memory::PagePool::get_debug_pool_name(), grab(), grab_one(), initialize_once(), foedus::memory::operator<<(), release_impl(), release_one(), and uninitialize_once().

124  {
125  if (control_block_) {
128  } else {
129  return "Unnamed";
130  }
131  } else {
132  return "Not-attached";
133  }
134  }
PagePoolControlBlock * control_block_
bool empty() const noexcept
Test if string is empty.
std::basic_string< CHAR > str() const
Convert to a std::string object.
assorted::FixedString< 60 > debug_pool_name_
just for debugging/logging.

Here is the call graph for this function:

Here is the caller graph for this function:

uint64_t foedus::memory::PagePoolPimpl::get_free_pool_capacity ( ) const
inline

Definition at line 100 of file page_pool_pimpl.hpp.

References free_pool_capacity_.

Referenced by foedus::memory::PagePool::get_free_pool_capacity().

100 { return free_pool_capacity_; }
uint64_t free_pool_capacity_
Size of free_pool_.

Here is the caller graph for this function:

uint64_t foedus::memory::PagePoolPimpl::get_free_pool_count ( ) const
inline

Definition at line 101 of file page_pool_pimpl.hpp.

References control_block_, and foedus::memory::PagePoolControlBlock::free_pool_count_.

Referenced by assert_free_pool(), get_stat(), grab(), grab_one(), foedus::memory::operator<<(), release_impl(), release_one(), and uninitialize_once().

PagePoolControlBlock * control_block_
uint64_t free_pool_count_
Number of free pages.

Here is the caller graph for this function:

const LocalPageResolver& foedus::memory::PagePoolPimpl::get_resolver ( ) const
inline

Definition at line 96 of file page_pool_pimpl.hpp.

References resolver_.

Referenced by foedus::memory::PagePool::get_resolver().

96 { return resolver_; }
LocalPageResolver resolver_
An object to resolve an offset in this page pool (thus local) to an actual pointer and vice versa...

Here is the caller graph for this function:

PagePool::Stat foedus::memory::PagePoolPimpl::get_stat ( ) const

Definition at line 359 of file page_pool_pimpl.cpp.

References foedus::memory::PagePool::Stat::allocated_pages_, get_free_pool_count(), pages_for_free_pool_, pool_size_, and foedus::memory::PagePool::Stat::total_pages_.

Referenced by foedus::memory::PagePool::get_stat().

359  {
360  PagePool::Stat ret;
361  ret.total_pages_ = pool_size_ - pages_for_free_pool_;
362  ret.allocated_pages_ = ret.total_pages_ - get_free_pool_count();
363  return ret;
364 }
uint64_t get_free_pool_count() const
uint64_t pool_size_
Just an auxiliary variable of the size of pool.
uint64_t pages_for_free_pool_
This many first pages are used for free page maintainance.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::memory::PagePoolPimpl::grab ( uint32_t  desired_grab_count,
PagePoolOffsetChunk chunk 
)

Definition at line 191 of file page_pool_pimpl.cpp.

References assert_free_pool(), ASSERT_ND, foedus::memory::PagePoolOffsetChunk::capacity(), control_block_, decrease_free_pool_count(), free_pool_, free_pool_capacity_, free_pool_head(), get_debug_pool_name(), get_free_pool_count(), foedus::kErrorCodeMemoryNoFreePages, foedus::kErrorCodeOk, foedus::memory::PagePoolControlBlock::lock_, foedus::memory::PagePoolOffsetChunk::push_back(), foedus::memory::PagePoolOffsetChunk::size(), and UNLIKELY.

Referenced by foedus::memory::PagePool::grab().

191  {
192  ASSERT_ND(chunk->size() + desired_grab_count <= chunk->capacity());
193  VLOG(0) << get_debug_pool_name() << " - Grabbing " << desired_grab_count << " pages."
194  << " free_pool_count_=" << get_free_pool_count()
195  << "->"
196  << (get_free_pool_count() >= desired_grab_count
197  ? get_free_pool_count() - desired_grab_count
198  : 0);
199  soc::SharedMutexScope guard(&control_block_->lock_);
200  uint64_t free_count = get_free_pool_count();
201  if (UNLIKELY(free_count == 0)) {
202  LOG(WARNING) << get_debug_pool_name() << " - No more free pages left in the pool";
204  }
205 
206  // grab from the head
208  uint64_t grab_count = std::min<uint64_t>(desired_grab_count, free_count);
210  if (free_pool_head() + grab_count > free_pool_capacity_) {
211  // wrap around
212  uint64_t wrap_count = free_pool_capacity_ - free_pool_head();
213  chunk->push_back(head, head + wrap_count);
214  free_pool_head() = 0;
215  decrease_free_pool_count(wrap_count);
216  grab_count -= wrap_count;
217  head = free_pool_;
218  }
219 
220  // no wrap around (or no more wrap around)
222  ASSERT_ND(free_pool_head() + grab_count <= free_pool_capacity_);
223  chunk->push_back(head, head + grab_count);
224  free_pool_head() += grab_count;
225  decrease_free_pool_count(grab_count);
227  return kErrorCodeOk;
228 }
std::string get_debug_pool_name() const
uint64_t get_free_pool_count() const
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
uint64_t free_pool_capacity_
Size of free_pool_.
soc::SharedMutex lock_
grab()/release() are protected with this lock.
PagePoolControlBlock * control_block_
0 means no-error.
Definition: error_code.hpp:87
void decrease_free_pool_count(uint64_t op)
void assert_free_pool() const
Not thread safe.
0x0301 : "MEMORY : Not enough free volatile pages. Check the config of MemoryOptions" ...
Definition: error_code.hpp:142
#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
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorCode foedus::memory::PagePoolPimpl::grab_one ( PagePoolOffset offset)

Definition at line 230 of file page_pool_pimpl.cpp.

References ASSERT_ND, control_block_, decrease_free_pool_count(), free_pool_, free_pool_capacity_, free_pool_head(), get_debug_pool_name(), get_free_pool_count(), foedus::kErrorCodeMemoryNoFreePages, foedus::kErrorCodeOk, foedus::memory::PagePoolControlBlock::lock_, and UNLIKELY.

Referenced by foedus::memory::PagePool::grab_one().

230  {
231  VLOG(1) << get_debug_pool_name()
232  << " - Grabbing just one page. free_pool_count_=" << get_free_pool_count() << "->"
233  << (get_free_pool_count() - 1);
234  *offset = 0;
235  soc::SharedMutexScope guard(&control_block_->lock_);
236  uint64_t free_count = get_free_pool_count();
237  if (UNLIKELY(free_count == 0)) {
238  LOG(WARNING) << get_debug_pool_name() << " - No more free pages left in the pool";
240  }
241 
242  // grab from the head
245  // wrap around
246  free_pool_head() = 0;
247  head = free_pool_;
248  }
249 
250  // no wrap around (or no more wrap around)
252  *offset = *head;
253  ++free_pool_head();
255  return kErrorCodeOk;
256 }
std::string get_debug_pool_name() const
uint64_t get_free_pool_count() const
uint32_t PagePoolOffset
Offset in PagePool that compactly represents the page address (unlike 8 bytes pointer).
Definition: memory_id.hpp:44
uint64_t free_pool_capacity_
Size of free_pool_.
soc::SharedMutex lock_
grab()/release() are protected with this lock.
PagePoolControlBlock * control_block_
0 means no-error.
Definition: error_code.hpp:87
void decrease_free_pool_count(uint64_t op)
0x0301 : "MEMORY : Not enough free volatile pages. Check the config of MemoryOptions" ...
Definition: error_code.hpp:142
#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
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::memory::PagePoolPimpl::increase_free_pool_count ( uint64_t  op)
inline

Definition at line 102 of file page_pool_pimpl.hpp.

References control_block_, and foedus::memory::PagePoolControlBlock::free_pool_count_.

Referenced by release_impl(), and release_one().

PagePoolControlBlock * control_block_
uint64_t free_pool_count_
Number of free pages.

Here is the caller graph for this function:

ErrorStack foedus::memory::PagePoolPimpl::initialize_once ( )
overridevirtual

Implements foedus::DefaultInitializable.

Definition at line 75 of file page_pool_pimpl.cpp.

References foedus::assorted::ProtectedBoundary::acquire_protect(), assert_free_pool(), ASSERT_ND, control_block_, foedus::debugging::StopWatch::elapsed_ms(), free_pool_, free_pool_capacity_, foedus::memory::PagePoolControlBlock::free_pool_count_, foedus::memory::PagePoolControlBlock::free_pool_head_, get_debug_pool_name(), foedus::memory::PagePoolControlBlock::initialize(), foedus::kErrorCodeOk, foedus::kRetOk, foedus::assorted::os_error(), owns_, pages_for_free_pool_, pool_base_, pool_size_, foedus::assorted::ProtectedBoundary::reset(), rigorous_page_boundary_check_, and foedus::debugging::StopWatch::stop().

75  {
76  if (owns_) {
77  LOG(INFO) << get_debug_pool_name()
78  << " - total_pages=" << pool_size_ << ", pages_for_free_pool_=" << pages_for_free_pool_
79  << ", boundary_check=" << rigorous_page_boundary_check_;
81  LOG(INFO) << get_debug_pool_name() << " - Constructing circular free pool...";
82  // all pages after pages_for_free_pool_-th page is in the free pool at first
83  if (!rigorous_page_boundary_check_) {
85  for (uint64_t i = 0; i < free_pool_capacity_; ++i) {
87  }
88  } else {
89  // Use even-numbered pages only
91  for (uint64_t i = 0; i < free_pool_capacity_; ++i) {
92  free_pool_[i] = pages_for_free_pool_ + i * 2U;
93  }
94 
95  LOG(INFO) << get_debug_pool_name() << " - mprotect()-ing odd-numbered pages...";
96  debugging::StopWatch watch;
97  bool error_reported = false;
98  for (uint64_t i = 0; i < free_pool_capacity_; ++i) {
99  uint64_t index = pages_for_free_pool_ + i * 2U + 1U;
100  static_assert(sizeof(assorted::ProtectedBoundary) == sizeof(storage::Page), "Hoosh!");
101  assorted::ProtectedBoundary* boundary = reinterpret_cast<assorted::ProtectedBoundary*>(
102  pool_base_ + index);
103  boundary->reset(std::to_string(index));
104  ErrorCode mprotect_ret = boundary->acquire_protect();
105  if (mprotect_ret != kErrorCodeOk && !error_reported) {
106  LOG(ERROR) << get_debug_pool_name() << " - mprotect() failed: " << assorted::os_error();
107  error_reported = true;
108  }
109  }
110  watch.stop();
111  LOG(INFO) << get_debug_pool_name() << " - mprotect()-ed " << free_pool_capacity_
112  << " pages in " << watch.elapsed_ms() << "ms";
113  }
114 
115  /* to enable this, we need a version for rigorous_page_boundary_check_
116  // [experimental] randomize the free pool pointers so that we can evenly utilize all
117  // memory banks
118  if (false) { // disabled for now
119  // this should be an option...
120  LOG(INFO) << get_debug_pool_name() << " - Randomizing free pool...";
121  struct Randomizer {
122  PagePoolOffset offset_;
123  uint32_t rank_;
124  static bool compare(const Randomizer& left, const Randomizer& right) {
125  return left.rank_ < right.rank_;
126  }
127  };
128  Randomizer* randomizers = new Randomizer[free_pool_capacity_];
129  assorted::UniformRandom rnd(123456L);
130  for (uint64_t i = 0; i < free_pool_capacity_; ++i) {
131  randomizers[i].offset_ = pages_for_free_pool_ + i;
132  randomizers[i].rank_ = rnd.next_uint32();
133  }
134  std::sort(randomizers, randomizers + free_pool_capacity_, Randomizer::compare);
135  for (uint64_t i = 0; i < free_pool_capacity_; ++i) {
136  free_pool_[i] = randomizers[i].offset_;
137  }
138  delete[] randomizers;
139  LOG(INFO) << get_debug_pool_name() << " - Randomized free pool.";
140  }
141  */
142 
145  LOG(INFO) << get_debug_pool_name() << " - Constructed circular free pool.";
147  }
148 
149  return kRetOk;
150 }
std::string get_debug_pool_name() const
bool rigorous_page_boundary_check_
Whether to use mprotect() for page boundaries to detect bogus memory accesses.
storage::Page * pool_base_
Just an auxiliary variable to the beginning of the pool.
uint64_t free_pool_capacity_
Size of free_pool_.
PagePoolControlBlock * control_block_
uint64_t pool_size_
Just an auxiliary variable of the size of pool.
0 means no-error.
Definition: error_code.hpp:87
void assert_free_pool() const
Not thread safe.
uint64_t free_pool_head_
Inclusive head of the circular queue.
bool owns_
Whether this engine owns this page pool.
uint64_t free_pool_count_
Number of free pages.
std::string os_error()
Thread-safe strerror(errno).
uint64_t pages_for_free_pool_
This many first pages are used for free page maintainance.
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
ErrorCode
Enum of error codes defined in error_code.xmacro.
Definition: error_code.hpp:85
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

void foedus::memory::PagePoolPimpl::release ( uint32_t  desired_release_count,
PagePoolOffsetChunk chunk 
)

Definition at line 302 of file page_pool_pimpl.cpp.

Referenced by foedus::memory::PagePool::release().

302  {
303  release_impl<PagePoolOffsetChunk>(desired_release_count, chunk);
304 }

Here is the caller graph for this function:

void foedus::memory::PagePoolPimpl::release ( uint32_t  desired_release_count,
PagePoolOffsetDynamicChunk chunk 
)

Definition at line 305 of file page_pool_pimpl.cpp.

305  {
306  release_impl<PagePoolOffsetDynamicChunk>(desired_release_count, chunk);
307 }
void foedus::memory::PagePoolPimpl::release ( uint32_t  desired_release_count,
PagePoolOffsetAndEpochChunk chunk 
)

Definition at line 308 of file page_pool_pimpl.cpp.

308  {
309  release_impl<PagePoolOffsetAndEpochChunk>(desired_release_count, chunk);
310 }
template<typename CHUNK >
void foedus::memory::PagePoolPimpl::release_impl ( uint32_t  desired_release_count,
CHUNK *  chunk 
)

Definition at line 259 of file page_pool_pimpl.cpp.

References assert_free_pool(), ASSERT_ND, control_block_, free_pool_, free_pool_capacity_, free_pool_head(), get_debug_pool_name(), get_free_pool_count(), increase_free_pool_count(), and foedus::memory::PagePoolControlBlock::lock_.

259  {
260  ASSERT_ND(chunk->size() >= desired_release_count);
261  VLOG(0) << get_debug_pool_name() << " - Releasing " << desired_release_count << " pages."
262  << " free_pool_count_=" << get_free_pool_count() << "->"
263  << (get_free_pool_count() + desired_release_count);
264  soc::SharedMutexScope guard(&control_block_->lock_);
265  uint64_t free_count = get_free_pool_count();
266  if (free_count + desired_release_count > free_pool_capacity_) {
267  // this can't happen unless something is wrong! This is a critical issue from which
268  // we can't recover because page pool is inconsistent!
269  LOG(ERROR) << get_debug_pool_name()
270  << " - PagePoolPimpl::release() More than full free-pool. inconsistent state!"
271  << " free_count/capacity/release_count=" << free_count << "/" << free_pool_capacity_
272  << "/" << desired_release_count;
273  // TASK(Hideaki) Do a duplicate-check here to identify the problemetic pages.
274  // crash here only in debug mode. otherwise just log the error
275  // ASSERT_ND(free_count + desired_release_count <= free_pool_capacity_);
276  // TASK(Hideaki) need to figure out why we hit this.
277  return;
278  }
279 
280  // append to the tail
282  uint64_t release_count = std::min<uint64_t>(desired_release_count, chunk->size());
283  uint64_t tail = free_pool_head() + free_count;
284  if (tail >= free_pool_capacity_) {
285  tail -= free_pool_capacity_;
286  }
287  if (tail + release_count > free_pool_capacity_) {
288  // wrap around
289  uint32_t wrap_count = free_pool_capacity_ - tail;
290  chunk->move_to(free_pool_ + tail, wrap_count);
291  increase_free_pool_count(wrap_count);
292  release_count -= wrap_count;
293  tail = 0;
294  }
295 
296  // no wrap around (or no more wrap around)
297  ASSERT_ND(tail + release_count <= free_pool_capacity_);
298  chunk->move_to(free_pool_ + tail, release_count);
299  increase_free_pool_count(release_count);
301 }
void increase_free_pool_count(uint64_t op)
std::string get_debug_pool_name() const
uint64_t get_free_pool_count() const
uint64_t free_pool_capacity_
Size of free_pool_.
soc::SharedMutex lock_
grab()/release() are protected with this lock.
PagePoolControlBlock * control_block_
void assert_free_pool() const
Not thread safe.
#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
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

void foedus::memory::PagePoolPimpl::release_one ( PagePoolOffset  offset)

Definition at line 312 of file page_pool_pimpl.cpp.

References ASSERT_ND, COERCE_ERROR, control_block_, ERROR_STACK, free_pool_, free_pool_capacity_, free_pool_head(), get_debug_pool_name(), get_free_pool_count(), increase_free_pool_count(), foedus::DefaultInitializable::is_initialized(), foedus::kErrorCodeMemoryDuplicatePage, foedus::memory::PagePoolControlBlock::lock_, and owns_.

Referenced by foedus::memory::PagePool::release_one().

312  {
314  VLOG(1) << get_debug_pool_name() << " - Releasing just one page. free_pool_count_="
315  << get_free_pool_count() << "->" << (get_free_pool_count() + 1);
316  soc::SharedMutexScope guard(&control_block_->lock_);
317  uint64_t free_count = get_free_pool_count();
318  if (free_count >= free_pool_capacity_) {
319  // this can't happen unless something is wrong! This is a critical issue from which
320  // we can't recover because page pool is inconsistent!
321  LOG(ERROR) << get_debug_pool_name()
322  << " - PagePoolPimpl::release_one() More than full free-pool. inconsistent state!";
324  }
325 
326  // append to the tail
327  uint64_t tail = free_pool_head() + free_count;
328  if (tail >= free_pool_capacity_) {
329  tail -= free_pool_capacity_;
330  }
331  if (tail == free_pool_capacity_) {
332  // wrap around
333  tail = 0;
334  }
335 
336  // no wrap around (or no more wrap around)
337  ASSERT_ND(tail + 1 <= free_pool_capacity_);
338  free_pool_[tail] = offset;
340 }
void increase_free_pool_count(uint64_t op)
#define ERROR_STACK(e)
Instantiates ErrorStack with the given foedus::error_code, creating an error stack with the current f...
std::string get_debug_pool_name() const
uint64_t get_free_pool_count() const
uint64_t free_pool_capacity_
Size of free_pool_.
soc::SharedMutex lock_
grab()/release() are protected with this lock.
PagePoolControlBlock * control_block_
#define COERCE_ERROR(x)
This macro calls x and aborts if encounters an error.
0x0302 : "MEMORY : Duplicate entry in free-page pool." .
Definition: error_code.hpp:143
bool owns_
Whether this engine owns this page pool.
#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
bool is_initialized() const override final
Returns whether the object has been already initialized or not.
PagePoolOffset * free_pool_
We maintain free pages as a simple circular queue.

Here is the call graph for this function:

Here is the caller graph for this function:

void foedus::memory::PagePoolPimpl::set_debug_pool_name ( const std::string &  name)
inline

Definition at line 135 of file page_pool_pimpl.hpp.

References foedus::assorted::FixedString< MAXLEN, CHAR >::assign(), control_block_, and foedus::memory::PagePoolControlBlock::debug_pool_name_.

Referenced by foedus::memory::PagePool::set_debug_pool_name().

135  {
136  if (control_block_) {
138  }
139  }
PagePoolControlBlock * control_block_
void assign(const FixedString< MAXLEN2, CHAR > &other) noexcept
Assign operator for all FixedString objects.
assorted::FixedString< 60 > debug_pool_name_
just for debugging/logging.

Here is the call graph for this function:

Here is the caller graph for this function:

ErrorStack foedus::memory::PagePoolPimpl::uninitialize_once ( )
overridevirtual

Implements foedus::DefaultInitializable.

Definition at line 152 of file page_pool_pimpl.cpp.

References foedus::assorted::ProtectedBoundary::assert_boundary(), assert_free_pool(), ASSERT_ND, control_block_, foedus::debugging::StopWatch::elapsed_ms(), free_pool_capacity_, foedus::assorted::ProtectedBoundary::get_boundary_name(), get_debug_pool_name(), get_free_pool_count(), foedus::kErrorCodeOk, foedus::kRetOk, foedus::assorted::os_error(), owns_, pages_for_free_pool_, pool_base_, foedus::assorted::ProtectedBoundary::release_protect(), rigorous_page_boundary_check_, foedus::debugging::StopWatch::stop(), and foedus::memory::PagePoolControlBlock::uninitialize().

152  {
153  if (owns_) {
156  LOG(INFO) << get_debug_pool_name() << " - releasing mprotect() odd-numbered pages...";
157  debugging::StopWatch watch;
158  bool error_reported = false;
159  for (uint64_t i = 0; i < free_pool_capacity_; ++i) {
160  uint64_t index = pages_for_free_pool_ + i * 2U + 1U;
161  assorted::ProtectedBoundary* boundary = reinterpret_cast<assorted::ProtectedBoundary*>(
162  pool_base_ + index);
163  ErrorCode mprotect_ret = boundary->release_protect();
164  if (mprotect_ret != kErrorCodeOk && !error_reported) {
165  LOG(ERROR) << get_debug_pool_name() << " - mprotect() failed: " << assorted::os_error();
166  error_reported = true;
167  }
168  boundary->assert_boundary();
169  ASSERT_ND(boundary->get_boundary_name() == std::to_string(index));
170  }
171  watch.stop();
172  LOG(INFO) << get_debug_pool_name() << " - released mprotect() " << free_pool_capacity_
173  << " pages in " << watch.elapsed_ms() << "ms";
174  }
175 
176  uint64_t free_count = get_free_pool_count();
177  if (free_count != free_pool_capacity_) {
178  // This is not a memory leak as we anyway releases everything, but it's a smell of bug.
179  LOG(WARNING) << get_debug_pool_name()
180  << " - Page Pool has not received back all free pages by its uninitialization!!"
181  << " count=" << free_count << ", capacity=" << free_pool_capacity_;
182  } else {
183  LOG(INFO) << get_debug_pool_name()
184  << " - Page Pool has received back all free pages. No suspicious behavior.";
185  }
187  }
188  return kRetOk;
189 }
std::string get_debug_pool_name() const
bool rigorous_page_boundary_check_
Whether to use mprotect() for page boundaries to detect bogus memory accesses.
uint64_t get_free_pool_count() const
storage::Page * pool_base_
Just an auxiliary variable to the beginning of the pool.
uint64_t free_pool_capacity_
Size of free_pool_.
PagePoolControlBlock * control_block_
0 means no-error.
Definition: error_code.hpp:87
void assert_free_pool() const
Not thread safe.
bool owns_
Whether this engine owns this page pool.
std::string os_error()
Thread-safe strerror(errno).
uint64_t pages_for_free_pool_
This many first pages are used for free page maintainance.
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
ErrorCode
Enum of error codes defined in error_code.xmacro.
Definition: error_code.hpp:85

Here is the call graph for this function:

Friends And Related Function Documentation

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

Definition at line 343 of file page_pool_pimpl.cpp.

343  {
344  o << "<PagePool>"
345  << "<name_>" << v.get_debug_pool_name() << "</name_>"
346  << "<memory_>" << v.memory_ << "</memory_>"
347  << "<memory_size>" << v.memory_size_ << "</memory_size>"
348  << "<owns_>" << v.owns_ << "</owns_>"
349  << "<rigorous_page_boundary_check_>"
350  << v.rigorous_page_boundary_check_ << "</rigorous_page_boundary_check_>"
351  << "<pages_for_free_pool_>" << v.pages_for_free_pool_ << "</pages_for_free_pool_>"
352  << "<free_pool_capacity_>" << v.free_pool_capacity_ << "</free_pool_capacity_>"
353  << "<free_pool_head_>" << v.free_pool_head() << "</free_pool_head_>"
354  << "<free_pool_count_>" << v.get_free_pool_count() << "</free_pool_count_>"
355  << "</PagePool>";
356  return o;
357 }

Member Data Documentation

PagePoolOffset* foedus::memory::PagePoolPimpl::free_pool_

We maintain free pages as a simple circular queue.

We append new/released pages to tail while we eat from head.

Definition at line 181 of file page_pool_pimpl.hpp.

Referenced by assert_free_pool(), attach(), grab(), grab_one(), initialize_once(), release_impl(), and release_one().

uint64_t foedus::memory::PagePoolPimpl::free_pool_capacity_
void* foedus::memory::PagePoolPimpl::memory_

The whole memory region of the pool.

Definition at line 146 of file page_pool_pimpl.hpp.

Referenced by attach(), and foedus::memory::operator<<().

uint64_t foedus::memory::PagePoolPimpl::memory_size_

Byte size of this page pool.

Definition at line 149 of file page_pool_pimpl.hpp.

Referenced by attach(), foedus::memory::PagePool::get_memory_size(), and foedus::memory::operator<<().

bool foedus::memory::PagePoolPimpl::owns_

Whether this engine owns this page pool.

If not, initialize just attaches

Definition at line 152 of file page_pool_pimpl.hpp.

Referenced by attach(), initialize_once(), foedus::memory::operator<<(), release_one(), and uninitialize_once().

uint64_t foedus::memory::PagePoolPimpl::pages_for_free_pool_

This many first pages are used for free page maintainance.

This also means that "Page-0" never appears in our engine, thus we can use offset=0 as null. In other words, all offsets grabbed/released should be equal or larger than this value. Immutable once initialized.

Definition at line 175 of file page_pool_pimpl.hpp.

Referenced by assert_free_pool(), attach(), get_stat(), initialize_once(), foedus::memory::operator<<(), and uninitialize_once().

storage::Page* foedus::memory::PagePoolPimpl::pool_base_

Just an auxiliary variable to the beginning of the pool.

Same as memory_.get_block().

Definition at line 164 of file page_pool_pimpl.hpp.

Referenced by attach(), foedus::memory::PagePool::get_base(), initialize_once(), and uninitialize_once().

uint64_t foedus::memory::PagePoolPimpl::pool_size_

Just an auxiliary variable of the size of pool.

Same as memory_byte_size/kPageSize.

Definition at line 167 of file page_pool_pimpl.hpp.

Referenced by assert_free_pool(), attach(), get_stat(), and initialize_once().

LocalPageResolver foedus::memory::PagePoolPimpl::resolver_

An object to resolve an offset in this page pool (thus local) to an actual pointer and vice versa.

Definition at line 161 of file page_pool_pimpl.hpp.

Referenced by attach(), and get_resolver().

bool foedus::memory::PagePoolPimpl::rigorous_page_boundary_check_

Whether to use mprotect() for page boundaries to detect bogus memory accesses.

Similar to rigorous_memory_boundary_check_, but this one is about page pools. When true, we waste a half of volatile/snapshot page pool, putting mprotect in odd-numbered page indexes. The threads receive only the even-numbered indexes, so if any read/write overruns a page, a signal is fired. This makes the execution quite slower and wastes half of memory, so use it just for debugging. This flag also disables hugepages used for snapshot page pool for mprotect to work, so makes it really SLOW. Default is false.

Attention
To use this feature with large page pool sizes, you must increase max_map_count. sudo sysctl -w vm.max_map_count=2147483647 Otherwise you will get out-of-memory crashes. Linux's default value is only 65530.
Note
When FOEDUS is running on a valgrind process, you shouldn't turn this on because valgrind uses a hard-coded limit VG_N_SEGMENTS rather than vm.max_map_count. However, if you are sure the number of mprotect-ed pages are less than 64k, you can.
See also
foedus::assorted::ProtectedBoundary

Definition at line 155 of file page_pool_pimpl.hpp.

Referenced by attach(), initialize_once(), foedus::memory::operator<<(), and uninitialize_once().


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