From: JINMEI Tatuya Date: Mon, 11 Mar 2013 21:02:32 +0000 (-0700) Subject: [2831] supported shrinkToFit(). X-Git-Tag: bind10-1.2.0beta1-release~457^2~117 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=111e2c83f6584bc452e5658f17779b30d2959c99;p=thirdparty%2Fkea.git [2831] supported shrinkToFit(). --- diff --git a/src/lib/util/memory_segment.h b/src/lib/util/memory_segment.h index b00c87f05c..c3e9129144 100644 --- a/src/lib/util/memory_segment.h +++ b/src/lib/util/memory_segment.h @@ -94,6 +94,8 @@ public: /// responsibility to meet the restriction. virtual void setNamedAddress(const char* name, void* addr) = 0; virtual bool clearNamedAddress(const char* name) = 0; + + virtual void shrinkToFit() = 0; }; } // namespace util diff --git a/src/lib/util/memory_segment_local.h b/src/lib/util/memory_segment_local.h index c6917e031a..78a425b76d 100644 --- a/src/lib/util/memory_segment_local.h +++ b/src/lib/util/memory_segment_local.h @@ -67,6 +67,9 @@ public: virtual void setNamedAddress(const char* name, void* addr); virtual bool clearNamedAddress(const char* name); + /// There's nothing this implementation can do for this. + virtual void shrinkToFit() {} + private: // allocated_size_ can underflow, wrap around to max size_t (which // is unsigned). But because we only do a check against 0 and not a diff --git a/src/lib/util/memory_segment_mapped.cc b/src/lib/util/memory_segment_mapped.cc index 1b5c8427ed..30db5777f0 100644 --- a/src/lib/util/memory_segment_mapped.cc +++ b/src/lib/util/memory_segment_mapped.cc @@ -170,6 +170,29 @@ MemorySegmentMapped::clearNamedAddress(const char* name) { return (impl_->base_sgmt_->destroy >(name)); } +void +MemorySegmentMapped::shrinkToFit() { + // It appears an assertion failure is triggered within Boost if the size + // is too small. To work this around we'll make it no-op if the size is + // already reasonably small. + if (getSize() < INITIAL_SIZE) { + return; + } + + impl_->base_sgmt_.reset(); + managed_mapped_file::shrink_to_fit(impl_->filename_.c_str()); + try { + // Remap the grown file; this should succeed, but it's not 100% + // guaranteed. If it fails we treat it as if we fail to create + // the new segment. + impl_->base_sgmt_.reset( + new managed_mapped_file(open_only, impl_->filename_.c_str())); + } catch (const boost::interprocess::interprocess_exception& ex) { + isc_throw(MemorySegmentError, + "remap after shrink failed; segment is now unusable"); + } +} + size_t MemorySegmentMapped::getSize() const { return (impl_->base_sgmt_->get_size()); diff --git a/src/lib/util/memory_segment_mapped.h b/src/lib/util/memory_segment_mapped.h index 46242a2c1c..e45ea5715d 100644 --- a/src/lib/util/memory_segment_mapped.h +++ b/src/lib/util/memory_segment_mapped.h @@ -72,6 +72,8 @@ public: virtual bool clearNamedAddress(const char* name); + virtual void shrinkToFit(); + size_t getSize() const; private: diff --git a/src/lib/util/tests/memory_segment_mapped_unittest.cc b/src/lib/util/tests/memory_segment_mapped_unittest.cc index 4713c34cc2..804adc47c6 100644 --- a/src/lib/util/tests/memory_segment_mapped_unittest.cc +++ b/src/lib/util/tests/memory_segment_mapped_unittest.cc @@ -40,7 +40,7 @@ protected: ~MemorySegmentMappedTest() { segment_.reset(); - boost::interprocess::file_mapping::remove(mapped_file); + //boost::interprocess::file_mapping::remove(mapped_file); } // For initialization and for tests after the segment possibly becomes @@ -262,4 +262,21 @@ TEST_F(MemorySegmentMappedTest, nullDeallocate) { EXPECT_TRUE(segment_->allMemoryDeallocated()); } +TEST_F(MemorySegmentMappedTest, shrink) { + segment_->shrinkToFit(); + // Normally we should be able to expect the resulting size is the smaller + // than the initial default size. It's not really guaranteed by the API, + // however, so we may have to disable this check. + const size_t shrinked_size = segment_->getSize(); + EXPECT_GT(DEFAULT_INITIAL_SIZE, shrinked_size); + + // Another shrink shouldn't cause disruption, and the size shouldn't change + segment_->shrinkToFit(); + EXPECT_EQ(shrinked_size, segment_->getSize()); + + // Check the segment is still usable after shrink. + void* p = segment_->allocate(sizeof(uint32_t)); + segment_->deallocate(p, sizeof(uint32_t)); +} + }