Browse Source

[2850] Add resetHeader() method

Mukund Sivaraman 12 years ago
parent
commit
3ebd4b039b

+ 3 - 0
src/lib/datasrc/memory/zone_table_segment.h

@@ -262,6 +262,9 @@ public:
     ///
     /// \throw none
     virtual void clear() = 0;
+
+    /// \brief Reset the table header address.
+    virtual void resetHeader() = 0;
 };
 
 } // namespace memory

+ 5 - 0
src/lib/datasrc/memory/zone_table_segment_local.cc

@@ -54,6 +54,11 @@ ZoneTableSegmentLocal::clear()
               "should not be used.");
 }
 
+void
+ZoneTableSegmentLocal::resetHeader() {
+    // This method does not have to do anything in this implementation.
+}
+
 // After more methods' definitions are added here, it would be a good
 // idea to move getHeader() and getMemorySegment() definitions to the
 // header file.

+ 3 - 0
src/lib/datasrc/memory/zone_table_segment_local.h

@@ -42,6 +42,9 @@ public:
     /// \brief Destructor
     virtual ~ZoneTableSegmentLocal();
 
+    /// \brief This method has an empty definition.
+    virtual void resetHeader();
+
     /// \brief Return the ZoneTableHeader for the local zone table
     /// segment implementation.
     virtual ZoneTableHeader& getHeader();

+ 26 - 6
src/lib/datasrc/memory/zone_table_segment_mapped.cc

@@ -36,7 +36,8 @@ const char* const ZONE_TABLE_HEADER_NAME = "zone_table_header";
 
 ZoneTableSegmentMapped::ZoneTableSegmentMapped(const RRClass& rrclass) :
     ZoneTableSegment(rrclass),
-    rrclass_(rrclass)
+    rrclass_(rrclass),
+    cached_header_(NULL)
 {
 }
 
@@ -283,6 +284,10 @@ ZoneTableSegmentMapped::reset(MemorySegmentOpenMode mode,
     current_filename_ = filename;
     current_mode_ = mode;
     mem_sgmt_.reset(segment.release());
+
+    // Given what we setup above, resetHeader() must not throw at this
+    // point. If it does, all bets are off.
+    resetHeader();
 }
 
 void
@@ -314,12 +319,15 @@ ZoneTableSegmentMapped::clear() {
     }
 }
 
-template<typename T>
-T*
-ZoneTableSegmentMapped::getHeaderHelper() const {
+void
+ZoneTableSegmentMapped::resetHeader() {
+    // We cannot perform resetHeader() lazily during getHeader() as
+    // getHeader() has to work on const objects too. So we do it here
+    // now.
+
     if (!mem_sgmt_) {
         isc_throw(isc::InvalidOperation,
-                  "getHeader() called without calling reset() first");
+                  "resetHeader() called without calling reset() first");
     }
 
     const MemorySegment::NamedAddressResult result =
@@ -330,7 +338,19 @@ ZoneTableSegmentMapped::getHeaderHelper() const {
                   "getHeader()");
     }
 
-    return (static_cast<T*>(result.second));
+    cached_header_ = static_cast<ZoneTableHeader*>(result.second);
+}
+
+template<typename T>
+T*
+ZoneTableSegmentMapped::getHeaderHelper() const {
+    if (!mem_sgmt_) {
+        isc_throw(isc::InvalidOperation,
+                  "getHeader() called without calling reset() first");
+    }
+
+    assert(cached_header_);
+    return (cached_header_);
 }
 
 ZoneTableHeader&

+ 5 - 0
src/lib/datasrc/memory/zone_table_segment_mapped.h

@@ -46,6 +46,10 @@ public:
     /// \brief Destructor
     virtual ~ZoneTableSegmentMapped();
 
+    /// \brief Reset the table header address from the named address in
+    /// the mapped file.
+    virtual void resetHeader();
+
     /// \brief Return the ZoneTableHeader for the mapped zone table
     /// segment implementation.
     ///
@@ -128,6 +132,7 @@ private:
     // Internally holds a MemorySegmentMapped. This is NULL on
     // construction, and is set by the \c reset() method.
     boost::scoped_ptr<isc::util::MemorySegmentMapped> mem_sgmt_;
+    ZoneTableHeader* cached_header_;
 };
 
 } // namespace memory

+ 4 - 0
src/lib/datasrc/memory/zone_writer.cc

@@ -59,6 +59,8 @@ ZoneWriter::load() {
         isc_throw(isc::InvalidOperation, "No data returned from load action");
     }
 
+    segment_.resetHeader();
+
     state_ = ZW_LOADED;
 }
 
@@ -78,6 +80,8 @@ ZoneWriter::install() {
 
     state_ = ZW_INSTALLED;
     zone_data_ = result.zone_data;
+
+    segment_.resetHeader();
 }
 
 void

+ 32 - 0
src/lib/datasrc/tests/memory/zone_table_segment_mapped_unittest.cc

@@ -454,4 +454,36 @@ TEST_F(ZoneTableSegmentMappedTest, resetFailedMissingHeader) {
     }, ResetFailed);
 }
 
+TEST_F(ZoneTableSegmentMappedTest, resetHeaderUninitialized) {
+    // This should throw as we haven't called reset() yet.
+    EXPECT_THROW(ztable_segment_->resetHeader(), isc::InvalidOperation);
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetHeader) {
+    // First, open an underlying mapped file in read+write mode (doesn't
+    // exist yet)
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    // Check if a valid ZoneTable is found.
+    {
+        const ZoneTableHeader& header = ztable_segment_->getHeader();
+        const ZoneTable* table = header.getTable();
+        EXPECT_EQ(0, table->getZoneCount());
+    }
+
+    // Grow the segment by allocating something large.
+    EXPECT_THROW(ztable_segment_->getMemorySegment().allocate(1<<16),
+                 MemorySegmentGrown);
+
+    // Reset the header address. This should not throw now.
+    EXPECT_NO_THROW(ztable_segment_->resetHeader());
+
+    // Check if a valid ZoneTable is found.
+    {
+        const ZoneTableHeader& header = ztable_segment_->getHeader();
+        const ZoneTable* table = header.getTable();
+        EXPECT_EQ(0, table->getZoneCount());
+    }
+}
+
 } // anonymous namespace

+ 5 - 0
src/lib/datasrc/tests/memory/zone_table_segment_test.h

@@ -49,6 +49,11 @@ public:
         isc_throw(isc::NotImplemented, "clear() is not implemented");
     }
 
+    virtual void resetHeader() {
+        // This method does not have to do anything in this
+        // implementation.
+    }
+
     virtual ZoneTableHeader& getHeader() {
         return (header_);
     }

+ 13 - 0
src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc

@@ -85,6 +85,19 @@ TEST_F(ZoneTableSegmentTest, getHeader) {
     // const version.
     testGetHeader<const ZoneTableSegment, const ZoneTableHeader,
                   const ZoneTable>(ztable_segment_);
+
+    // This is a nop for local segments.
+    ztable_segment_->resetHeader();
+
+    // The following still behave as before after resetHeader().
+
+    // non-const version.
+    testGetHeader<ZoneTableSegment, ZoneTableHeader, ZoneTable>
+        (ztable_segment_);
+
+    // const version.
+    testGetHeader<const ZoneTableSegment, const ZoneTableHeader,
+                  const ZoneTable>(ztable_segment_);
 }
 
 TEST_F(ZoneTableSegmentTest, getMemorySegment) {