namespace isc {
namespace util {
+/// \brief Exception that can be thrown on constructing a MemorySegment
+/// object.
class MemorySegmentOpenError : public Exception {
public:
MemorySegmentOpenError(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
+/// \brief Exception that is thrown when allocating a space in a MemorySegment
+/// results in growing the underlying segment.
+///
+/// See MemorySegment::allocate() for details.
class MemorySegmentGrown : public Exception {
public:
MemorySegmentGrown(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
+/// \brief General error that can be thrown by a MemorySegment
+/// implementation.
class MemorySegmentError : public Exception {
public:
MemorySegmentError(const char* file, size_t line, const char* what) :
/// segments. This is an abstract class and a real
/// implementation such as MemorySegmentLocal should be used
/// in code.
+///
+/// It's intended to provide a unified interface whether the underlying
+/// memory is local to a specific process or is sharable by multiple
+/// processes.
class MemorySegment {
public:
/// \brief Destructor
/// \brief Check if all allocated memory was deallocated.
///
- /// \return Returns <code>true</code> if all allocated memory was
+ /// \return Returns <code>true</code> if all allocated memory (including
+ /// names associated by memory addresses by \c setNamedAddress()) was
/// deallocated, <code>false</code> otherwise.
virtual bool allMemoryDeallocated() const = 0;
/// deallocated, <code>false</code> otherwise.
virtual bool allMemoryDeallocated() const;
+ /// \brief Local segment version of getNamedAddress.
+ ///
+ /// There's a small chance this method could throw std::bad_alloc.
+ /// It should be considered a fatal error.
virtual void* getNamedAddress(const char* name);
+
+ /// \brief Local segment version of setNamedAddress.
+ ///
+ /// This version does not validate the given address to see whether it
+ /// belongs to this segment.
virtual bool setNamedAddress(const char* name, void* addr);
+
+ /// \brief Local segment version of clearNamedAddress.
+ ///
+ /// There's a small chance this method could throw std::bad_alloc.
+ /// It should be considered a fatal error.
virtual bool clearNamedAddress(const char* name);
private:
namespace isc {
namespace util {
-/// \brief TBD
+/// \brief Mapped-file based Memory Segment class.
+///
+/// This implementation of \c MemorySegment uses a concrete file to be mapped
+/// into memory. Multiple processes can share the same mapped memory image.
+///
+/// This class provides two operation modes: read-only and read-write.
+/// A \c MemorySegmentMapped object in the read-only mode cannot modify the
+/// mapped memory image or other internal maintenance data of the object;
+/// In the read-write mode the object can allocate or deallocate memory
+/// from the mapped image, and the owner process can change the content.
+///
+/// This class does not provide any synchronization mechanism between
+/// read-only and read-write objects that share the same mapped image;
+/// in fact, the expected usage is the application (or a system of related
+/// processes) ensures there's at most one read-write object and if there's
+/// such an object no read-only object shares the image. If an application
+/// uses this class beyond that expectation, it's the application's
+/// responsibility to provide necessary synchronization between the processes.
class MemorySegmentMapped : boost::noncopyable, public MemorySegment {
public:
- /// arbitrary choice.
+ /// \brief The default value of the mapped file size when newly created.
+ ///
+ /// Its value, 32KB, is an arbitrary choice, but considered to be
+ /// sufficiently but not too large.
static const size_t INITIAL_SIZE = 32768;
- /// \brief Constructor in the read-only mode
+ /// \brief Constructor in the read-only mode.
+ ///
+ /// This constructor will map the content of the given file into memory
+ /// in the "read only" mode; the resulting memory segment object cannot
+ /// be used with methods that would requite the mapped memory (see method
+ /// descriptions). Also, if the application tries to modify memory in
+ /// the segment, it will make the application crash.
+ ///
+ /// The file must have been created by the other version of the
+ /// constructor beforehand and must be readable for the process
+ /// constructing this object. Otherwise \c MemorySegmentOpenError
+ /// exception will be thrown.
+ ///
+ /// \throw MemorySegmentOpenError The given file does not exist, is not
+ /// readable, or not valid mappable segment.
+ /// \throw std::bad_alloc (rare case) internal resource allocation
+ /// failure.
///
- /// Creates a local memory segment object
+ /// \param filename The file name to be mapped to memory.
MemorySegmentMapped(const std::string& filename);
+ /// \brief Constructor in the read-write mode.
+ ///
+ /// This is similar to the read-only version of the constructor, but
+ /// does not have the restrictions that the read-only version has.
+ /// If \c create is true and the specified file does not exist, it tries
+ /// to create a new file of the name and build internal data on it so that
+ /// the file will be mappable by this class object. If \c create is
+ /// false, the specified file must exist and be writable, and have been
+ /// previously initialized by this version of constructor with \c create
+ /// being true. If any of these conditions is not met,
+ /// \c MemorySegmentOpenError exception will be thrown.
+ ///
+ /// \param filename The file name to be mapped to memory.
+ /// \param create If true and the file does not exist a new one is created.
+ /// \param initial_size Specifies the size of the newly created file;
+ /// ignored if \c create is false.
MemorySegmentMapped(const std::string& filename, bool create,
size_t initial_size = INITIAL_SIZE);
#include <cstring>
#include <limits>
#include <stdexcept>
+#include <fstream>
+#include <string>
using namespace isc::util;
using boost::scoped_ptr;
EXPECT_THROW(MemorySegmentMapped(TEST_DATA_BUILDDIR "/nosuchfile.mapped",
false),
MemorySegmentOpenError);
+
+ // Close the segment, break the file with bogus data, and try to reopen.
+ // It should fail with exception whether in the read-only or read-write,
+ // or "create if not exist" mode.
+ segment_.reset();
+ std::ofstream ofs(mapped_file, std::ios::trunc);
+ ofs << std::string(1024, 'x');
+ ofs.close();
+ EXPECT_THROW(MemorySegmentMapped sgmt(mapped_file), MemorySegmentOpenError);
+ EXPECT_THROW(MemorySegmentMapped sgmt(mapped_file, false),
+ MemorySegmentOpenError);
+ EXPECT_THROW(MemorySegmentMapped sgmt(mapped_file, true),
+ MemorySegmentOpenError);
}
TEST_F(MemorySegmentMappedTest, allocate) {