From 9c6bd1afc973c02b7fe65a2da53748a31042480b Mon Sep 17 00:00:00 2001 From: Haoran Xu Date: Thu, 9 Jul 2020 10:21:48 -0700 Subject: [PATCH] Make sure we have at least kHeaderSize immutable pages in log (#284) It seems that when there is less than kHeaderSize immutable pages in log, we will not be able to dump the in-memory log into disk when the in-memory log is full. Added a check to enforce this requirement. A complication is compaction logic. In compaction logic, the logic makes sure that nothing will be dumped to disk, so it provides no backing storage path (the root_directory is "") and the requirement does not apply. So we will only throw error if root_directory is not "". --- cc/src/core/faster.h | 2 +- cc/src/core/persistent_memory_malloc.h | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/cc/src/core/faster.h b/cc/src/core/faster.h index 39a4d84d3..3ebec1e11 100644 --- a/cc/src/core/faster.h +++ b/cc/src/core/faster.h @@ -101,7 +101,7 @@ class FasterKv { double log_mutable_fraction = 0.9, bool pre_allocate_log = false) : min_table_size_{ table_size } , disk{ filename, epoch_ } - , hlog{ log_size, epoch_, disk, disk.log(), log_mutable_fraction, pre_allocate_log } + , hlog{ filename.empty() /*hasNoBackingStorage*/, log_size, epoch_, disk, disk.log(), log_mutable_fraction, pre_allocate_log } , system_state_{ Action::None, Phase::REST, 1 } , num_pending_ios{ 0 } { if(!Utility::IsPowerOfTwo(table_size)) { diff --git a/cc/src/core/persistent_memory_malloc.h b/cc/src/core/persistent_memory_malloc.h index 8026821e0..fdf60fcea 100644 --- a/cc/src/core/persistent_memory_malloc.h +++ b/cc/src/core/persistent_memory_malloc.h @@ -243,7 +243,7 @@ class PersistentMemoryMalloc { /// The first 4 HLOG pages should be below the head (i.e., being flushed to disk). static constexpr uint32_t kNumHeadPages = 4; - PersistentMemoryMalloc(uint64_t log_size, LightEpoch& epoch, disk_t& disk_, log_file_t& file_, + PersistentMemoryMalloc(bool has_no_backing_storage, uint64_t log_size, LightEpoch& epoch, disk_t& disk_, log_file_t& file_, Address start_address, double log_mutable_fraction, bool pre_allocate_log) : sector_size{ static_cast(file_.alignment()) } , epoch_{ &epoch } @@ -282,6 +282,13 @@ class PersistentMemoryMalloc { // mutable page is full. throw std::invalid_argument{ "Must have at least 2 mutable pages" }; } + // Make sure we have at least 'kNumHeadPages' immutable pages. + // Otherwise, we will not be able to dump log to disk when our in-memory log is full. + // If the user is certain that we will never need to dump anything to disk + // (this is the case in compaction), skip this check. + if(!has_no_backing_storage && buffer_size_ - num_mutable_pages_ < kNumHeadPages) { + throw std::invalid_argument{ "Must have at least 'kNumHeadPages' immutable pages" }; + } page_status_ = new FullPageStatus[buffer_size_]; @@ -302,9 +309,9 @@ class PersistentMemoryMalloc { AllocatePage(tail_page_offset.page() + 1); } - PersistentMemoryMalloc(uint64_t log_size, LightEpoch& epoch, disk_t& disk_, log_file_t& file_, + PersistentMemoryMalloc(bool has_no_backing_storage, uint64_t log_size, LightEpoch& epoch, disk_t& disk_, log_file_t& file_, double log_mutable_fraction, bool pre_allocate_log) - : PersistentMemoryMalloc(log_size, epoch, disk_, file_, Address{ 0 }, log_mutable_fraction, pre_allocate_log) { + : PersistentMemoryMalloc(has_no_backing_storage, log_size, epoch, disk_, file_, Address{ 0 }, log_mutable_fraction, pre_allocate_log) { /// Allocate the invalid page. Supports allocations aligned up to kCacheLineBytes. uint32_t discard; Allocate(Constants::kCacheLineBytes, discard);