123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #ifndef MEMORY_SEGMENT_MAPPED_H
- #define MEMORY_SEGMENT_MAPPED_H
- #include <util/memory_segment.h>
- #include <boost/noncopyable.hpp>
- #include <string>
- namespace isc {
- namespace util {
- /// \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.
- ///
- /// Multiple processes can open multiple segments for the same file in
- /// read-only mode at the same time. But there shouldn't be more than
- /// one process that opens segments for the same file in read-write mode
- /// at the same time. Likewise, if one process opens a segment for a
- /// file in read-write mode, there shouldn't be any other process that
- /// opens a segment for the file in read-only mode. If one or more
- /// processes open segments for a file in read-only mode, there
- /// shouldn't be any other process that opens a segment for the file in
- /// read-write mode. This class tries to detect any violation of this
- /// restriction, but this does not intend to provide 100% safety. It's
- /// generally the user's responsibility to ensure this condition.
- ///
- /// The same restriction applies within the single process, whether
- /// multi-threaded or not: a process shouldn't open read-only and read-write
- /// (or multiple read-write) segments for the same file. The violation
- /// detection mentioned above may or may not work in such cases due to
- /// limitation of the underlying API. It's completely user's responsibility
- /// to prevent this from happening. A single process may open multiple
- /// segments in read-only mode for the same file, but that shouldn't be
- /// necessary in practice; since it's read-only there wouldn't be a reason
- /// to have a redundant copy.
- class MemorySegmentMapped : boost::noncopyable, public MemorySegment {
- public:
- /// \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 Open modes of \c MemorySegmentMapped.
- ///
- /// These modes matter only for \c MemorySegmentMapped to be opened
- /// in read-write mode, and specify further details of open operation.
- enum OpenMode {
- OPEN_FOR_WRITE = 0, ///< Open only. File must exist.
- OPEN_OR_CREATE, ///< If file doesn't exist it's created.
- CREATE_ONLY ///< New file is created; existing one will be removed.
- };
- /// \brief Constructor in the read-only mode.
- ///
- /// This constructor will map the content of the given file into memory
- /// in read-only mode; the resulting memory segment object cannot
- /// be used with methods that would require 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. Or there is another process
- /// that has already opened a segment for the file.
- /// \throw std::bad_alloc (rare case) internal resource allocation
- /// failure.
- ///
- /// \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.
- ///
- /// The \c mode parameter specifies further details of how the segment
- /// should be opened.
- /// - OPEN_FOR_WRITE: this is open-only mode. The file must exist,
- /// and it will be opened without any initial modification.
- /// - OPEN_OR_CREATE: similar to OPEN_FOR_WRITE, but if the file does not
- /// exist, a new one will be created. An existing file will be used
- /// any initial modification.
- /// - CREATE_ONLY: a new file (of the given file name) will be created;
- /// any existing file of the same name will be removed.
- ///
- /// If OPEN_FOR_WRITE is specified, the specified file must exist
- /// and be writable, and have been previously initialized by this
- /// version of constructor either with OPEN_OR_CREATE or CREATE_ONLY.
- /// If the mode is OPEN_OR_CREATE or CREATE_ONLY, and the file needs
- /// to be created, then this method 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 any of these conditions is not met, or
- /// create or initialization fails, \c MemorySegmentOpenError exception
- /// will be thrown.
- ///
- /// This constructor also throws \c MemorySegmentOpenError when it
- /// detects violation of the restriction on the mixed open of read-only
- /// and read-write mode (see the class description).
- ///
- /// When initial_size is specified but is too small (including a value of
- /// 0), the underlying Boost library will reject it, and this constructor
- /// throws \c MemorySegmentOpenError exception. The Boost documentation
- /// does not specify how large it should be, but the default
- /// \c INITIAL_SIZE should be sufficiently large in practice.
- ///
- /// \throw MemorySegmentOpenError see the description.
- ///
- /// \param filename The file name to be mapped to memory.
- /// \param mode Open mode (see the description).
- /// \param initial_size Specifies the size of the newly created file;
- /// ignored if \c mode is OPEN_FOR_WRITE.
- MemorySegmentMapped(const std::string& filename, OpenMode mode,
- size_t initial_size = INITIAL_SIZE);
- /// \brief Destructor.
- ///
- /// If the object was constructed in the read-write mode and the underlying
- /// memory segment wasn't broken due to an exceptional event, the
- /// destructor ensures the content of the mapped memory is written back to
- /// the corresponding file.
- virtual ~MemorySegmentMapped();
- /// \brief Allocate/acquire a segment of memory.
- ///
- /// This version can throw \c MemorySegmentGrown.
- ///
- /// This method cannot be called if the segment object is created in the
- /// read-only mode; in that case MemorySegmentError will be thrown.
- virtual void* allocate(size_t size);
- /// \brief Deallocate/release a segment of memory.
- ///
- /// This implementation does not check the validity of \c size, because
- /// if this segment object was constructed for an existing file to map,
- /// the underlying segment may already contain allocated regions, so
- /// this object cannot reliably detect whether it's safe to deallocate
- /// the given size of memory from the underlying segment.
- ///
- /// Parameter \c ptr must point to an address that was returned by a
- /// prior call to \c allocate() of this segment object, and there should
- /// not be a \c MemorySegmentGrown exception thrown from \c allocate()
- /// since then; if it was thrown the corresponding address must have been
- /// adjusted some way; e.g., by re-fetching the latest mapped address
- /// via \c getNamedAddress().
- ///
- /// This method cannot be called if the segment object is created in the
- /// read-only mode; in that case MemorySegmentError will be thrown.
- virtual void deallocate(void* ptr, size_t size);
- virtual bool allMemoryDeallocated() const;
- /// \brief Mapped segment version of setNamedAddress.
- ///
- /// This implementation detects if \c addr is invalid (see the base class
- /// description) and throws \c MemorySegmentError in that case.
- ///
- /// This version of method should normally return false. However,
- /// it internally allocates memory in the segment for the name and
- /// address to be stored, which can require segment extension, just like
- /// allocate(). So it's possible to return true unlike
- /// \c MemorySegmentLocal version of the method.
- ///
- /// This method cannot be called if the segment object is created in the
- /// read-only mode; in that case MemorySegmentError will be thrown.
- virtual bool setNamedAddressImpl(const char* name, void* addr);
- /// \brief Mapped segment version of getNamedAddress.
- ///
- /// This version never throws.
- virtual void* getNamedAddressImpl(const char* name);
- /// \brief Mapped segment version of clearNamedAddress.
- ///
- /// This method cannot be called if the segment object is created in the
- /// read-only mode; in that case MemorySegmentError will be thrown.
- virtual bool clearNamedAddressImpl(const char* name);
- /// \brief Shrink the underlying mapped segment to actually used size.
- ///
- /// When a large amount of memory is allocated and then deallocated
- /// from the segment, this method can be used to keep the resulting
- /// segment at a reasonable size.
- ///
- /// This method works by a best-effort basis, and does not guarantee
- /// any specific result.
- ///
- /// This method is generally expected to be failure-free, but it's still
- /// possible to fail. For example, the underlying file may not be writable
- /// at the time of shrink attempt; it also tries to remap the shrunk
- /// segment internally, and there's a small chance it could fail.
- /// In such a case it throws \c MemorySegmentError. If it's thrown the
- /// segment is not usable anymore.
- ///
- /// This method cannot be called if the segment object is created in the
- /// read-only mode; in that case MemorySegmentError will be thrown.
- ///
- /// \throw MemorySegmentError see the description.
- void shrinkToFit();
- /// \brief Return the actual segment size.
- ///
- /// This is generally expected to be the file size to map. It's
- /// provided mainly for diagnosis and testing purposes; the application
- /// shouldn't rely on specific return values of this method.
- ///
- /// \throw None
- size_t getSize() const;
- /// \brief Calculate a checksum over the memory segment.
- ///
- /// This method goes over all pages of the underlying mapped memory
- /// segment, and returns the sum of the value of the first byte of each
- /// page (wrapping around upon overflow). It only proves weak integrity
- /// of the file contents, but can run fast enough and will ensure all
- /// pages are actually in memory. The latter property will be useful
- /// if the application cannot allow the initial page fault overhead.
- ///
- /// \throw None
- size_t getCheckSum() const;
- private:
- struct Impl;
- Impl* impl_;
- };
- } // namespace util
- } // namespace isc
- #endif // MEMORY_SEGMENT_MAPPED_H
- // Local Variables:
- // mode: c++
- // End:
|