]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[2831] supported shrinkToFit().
authorJINMEI Tatuya <jinmei@isc.org>
Mon, 11 Mar 2013 21:02:32 +0000 (14:02 -0700)
committerJINMEI Tatuya <jinmei@isc.org>
Mon, 11 Mar 2013 21:02:32 +0000 (14:02 -0700)
src/lib/util/memory_segment.h
src/lib/util/memory_segment_local.h
src/lib/util/memory_segment_mapped.cc
src/lib/util/memory_segment_mapped.h
src/lib/util/tests/memory_segment_mapped_unittest.cc

index b00c87f05cfa39e22596d82e8e1fedae3e1a4c58..c3e91291445507e4b8568057b1c00e8dcd169c72 100644 (file)
@@ -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
index c6917e031a05fb1c0665ff9dfd4c600b25f6903e..78a425b76df9f3d11c7f493f236b3a2fc5eaffdc 100644 (file)
@@ -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
index 1b5c8427eda7a7233659956a51a4bd58b2a993a0..30db5777f0a7be51d8fa7ea2d1be4c0f34155f36 100644 (file)
@@ -170,6 +170,29 @@ MemorySegmentMapped::clearNamedAddress(const char* name) {
     return (impl_->base_sgmt_->destroy<offset_ptr<void> >(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());
index 46242a2c1ccf02de7bdf2cae37d5352bebe1474a..e45ea5715d10ce9fe11a187d3d0683d58fde965b 100644 (file)
@@ -72,6 +72,8 @@ public:
 
     virtual bool clearNamedAddress(const char* name);
 
+    virtual void shrinkToFit();
+
     size_t getSize() const;
 
 private:
index 4713c34cc2da87fd34ed48eea35a56a3a3dd6901..804adc47c613aa421d7a4c739a5de463e9742083 100644 (file)
@@ -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));
+}
+
 }