memory_segment_mapped.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef MEMORY_SEGMENT_MAPPED_H
  15. #define MEMORY_SEGMENT_MAPPED_H
  16. #include <util/memory_segment.h>
  17. #include <boost/noncopyable.hpp>
  18. #include <string>
  19. namespace isc {
  20. namespace util {
  21. /// \brief Mapped-file based Memory Segment class.
  22. ///
  23. /// This implementation of \c MemorySegment uses a concrete file to be mapped
  24. /// into memory. Multiple processes can share the same mapped memory image.
  25. ///
  26. /// This class provides two operation modes: read-only and read-write.
  27. /// A \c MemorySegmentMapped object in the read-only mode cannot modify the
  28. /// mapped memory image or other internal maintenance data of the object;
  29. /// In the read-write mode the object can allocate or deallocate memory
  30. /// from the mapped image, and the owner process can change the content.
  31. ///
  32. /// Multiple processes can open multiple segments for the same file in
  33. /// read-only mode at the same time. But there shouldn't be more than
  34. /// one process that opens segments for the same file in read-write mode
  35. /// at the same time. Likewise, if one process opens a segment for a
  36. /// file in read-write mode, there shouldn't be any other process that
  37. /// opens a segment for the file in read-only mode. If one or more
  38. /// processes open segments for a file in read-only mode, there
  39. /// shouldn't be any other process that opens a segment for the file in
  40. /// read-write mode. This class tries to detect any violation of this
  41. /// restriction, but this does not intend to provide 100% safety. It's
  42. /// generally the user's responsibility to ensure this condition.
  43. ///
  44. /// The same restriction applies within the single process, whether
  45. /// multi-threaded or not: a process shouldn't open read-only and read-write
  46. /// (or multiple read-write) segments for the same file. The violation
  47. /// detection mentioned above may or may not work in such cases due to
  48. /// limitation of the underlying API. It's completely user's responsibility
  49. /// to prevent this from happening. A single process may open multiple
  50. /// segments in read-only mode for the same file, but that shouldn't be
  51. /// necessary in practice; since it's read-only there wouldn't be a reason
  52. /// to have a redundant copy.
  53. class MemorySegmentMapped : boost::noncopyable, public MemorySegment {
  54. public:
  55. /// \brief The default value of the mapped file size when newly created.
  56. ///
  57. /// Its value, 32KB, is an arbitrary choice, but considered to be
  58. /// sufficiently but not too large.
  59. static const size_t INITIAL_SIZE = 32768;
  60. /// \brief Open modes of \c MemorySegmentMapped.
  61. ///
  62. /// These modes matter only for \c MemorySegmentMapped to be opened
  63. /// in read-write mode, and specify further details of open operation.
  64. enum OpenMode {
  65. OPEN_FOR_WRITE = 0, ///< Open only. File must exist.
  66. OPEN_OR_CREATE, ///< If file doesn't exist it's created.
  67. CREATE_ONLY ///< New file is created; existing one will be removed.
  68. };
  69. /// \brief Constructor in the read-only mode.
  70. ///
  71. /// This constructor will map the content of the given file into memory
  72. /// in read-only mode; the resulting memory segment object cannot
  73. /// be used with methods that would require the mapped memory (see method
  74. /// descriptions). Also, if the application tries to modify memory in
  75. /// the segment, it will make the application crash.
  76. ///
  77. /// The file must have been created by the other version of the
  78. /// constructor beforehand and must be readable for the process
  79. /// constructing this object. Otherwise \c MemorySegmentOpenError
  80. /// exception will be thrown.
  81. ///
  82. /// \throw MemorySegmentOpenError The given file does not exist, is not
  83. /// readable, or not valid mappable segment. Or there is another process
  84. /// that has already opened a segment for the file.
  85. /// \throw std::bad_alloc (rare case) internal resource allocation
  86. /// failure.
  87. ///
  88. /// \param filename The file name to be mapped to memory.
  89. MemorySegmentMapped(const std::string& filename);
  90. /// \brief Constructor in the read-write mode.
  91. ///
  92. /// This is similar to the read-only version of the constructor, but
  93. /// does not have the restrictions that the read-only version has.
  94. ///
  95. /// The \c mode parameter specifies further details of how the segment
  96. /// should be opened.
  97. /// - OPEN_FOR_WRITE: this is open-only mode. The file must exist,
  98. /// and it will be opened without any initial modification.
  99. /// - OPEN_OR_CREATE: similar to OPEN_FOR_WRITE, but if the file does not
  100. /// exist, a new one will be created. An existing file will be used
  101. /// any initial modification.
  102. /// - CREATE_ONLY: a new file (of the given file name) will be created;
  103. /// any existing file of the same name will be removed.
  104. ///
  105. /// If OPEN_FOR_WRITE is specified, the specified file must exist
  106. /// and be writable, and have been previously initialized by this
  107. /// version of constructor either with OPEN_OR_CREATE or CREATE_ONLY.
  108. /// If the mode is OPEN_OR_CREATE or CREATE_ONLY, and the file needs
  109. /// to be created, then this method tries to create a new file of the
  110. /// name and build internal data on it so that the file will be mappable
  111. /// by this class object. If any of these conditions is not met, or
  112. /// create or initialization fails, \c MemorySegmentOpenError exception
  113. /// will be thrown.
  114. ///
  115. /// This constructor also throws \c MemorySegmentOpenError when it
  116. /// detects violation of the restriction on the mixed open of read-only
  117. /// and read-write mode (see the class description).
  118. ///
  119. /// When initial_size is specified but is too small (including a value of
  120. /// 0), the underlying Boost library will reject it, and this constructor
  121. /// throws \c MemorySegmentOpenError exception. The Boost documentation
  122. /// does not specify how large it should be, but the default
  123. /// \c INITIAL_SIZE should be sufficiently large in practice.
  124. ///
  125. /// \throw MemorySegmentOpenError see the description.
  126. ///
  127. /// \param filename The file name to be mapped to memory.
  128. /// \param mode Open mode (see the description).
  129. /// \param initial_size Specifies the size of the newly created file;
  130. /// ignored if \c mode is OPEN_FOR_WRITE.
  131. MemorySegmentMapped(const std::string& filename, OpenMode mode,
  132. size_t initial_size = INITIAL_SIZE);
  133. /// \brief Destructor.
  134. ///
  135. /// If the object was constructed in the read-write mode and the underlying
  136. /// memory segment wasn't broken due to an exceptional event, the
  137. /// destructor ensures the content of the mapped memory is written back to
  138. /// the corresponding file.
  139. virtual ~MemorySegmentMapped();
  140. /// \brief Allocate/acquire a segment of memory.
  141. ///
  142. /// This version can throw \c MemorySegmentGrown.
  143. ///
  144. /// This method cannot be called if the segment object is created in the
  145. /// read-only mode; in that case MemorySegmentError will be thrown.
  146. virtual void* allocate(size_t size);
  147. /// \brief Deallocate/release a segment of memory.
  148. ///
  149. /// This implementation does not check the validity of \c size, because
  150. /// if this segment object was constructed for an existing file to map,
  151. /// the underlying segment may already contain allocated regions, so
  152. /// this object cannot reliably detect whether it's safe to deallocate
  153. /// the given size of memory from the underlying segment.
  154. ///
  155. /// Parameter \c ptr must point to an address that was returned by a
  156. /// prior call to \c allocate() of this segment object, and there should
  157. /// not be a \c MemorySegmentGrown exception thrown from \c allocate()
  158. /// since then; if it was thrown the corresponding address must have been
  159. /// adjusted some way; e.g., by re-fetching the latest mapped address
  160. /// via \c getNamedAddress().
  161. ///
  162. /// This method cannot be called if the segment object is created in the
  163. /// read-only mode; in that case MemorySegmentError will be thrown.
  164. virtual void deallocate(void* ptr, size_t size);
  165. virtual bool allMemoryDeallocated() const;
  166. /// \brief Mapped segment version of setNamedAddress.
  167. ///
  168. /// This implementation detects if \c addr is invalid (see the base class
  169. /// description) and throws \c MemorySegmentError in that case.
  170. ///
  171. /// This version of method should normally return false. However,
  172. /// it internally allocates memory in the segment for the name and
  173. /// address to be stored, which can require segment extension, just like
  174. /// allocate(). So it's possible to return true unlike
  175. /// \c MemorySegmentLocal version of the method.
  176. ///
  177. /// This method cannot be called if the segment object is created in the
  178. /// read-only mode; in that case MemorySegmentError will be thrown.
  179. virtual bool setNamedAddressImpl(const char* name, void* addr);
  180. /// \brief Mapped segment version of getNamedAddress.
  181. ///
  182. /// This version never throws.
  183. virtual void* getNamedAddressImpl(const char* name);
  184. /// \brief Mapped segment version of clearNamedAddress.
  185. ///
  186. /// This method cannot be called if the segment object is created in the
  187. /// read-only mode; in that case MemorySegmentError will be thrown.
  188. virtual bool clearNamedAddressImpl(const char* name);
  189. /// \brief Shrink the underlying mapped segment to actually used size.
  190. ///
  191. /// When a large amount of memory is allocated and then deallocated
  192. /// from the segment, this method can be used to keep the resulting
  193. /// segment at a reasonable size.
  194. ///
  195. /// This method works by a best-effort basis, and does not guarantee
  196. /// any specific result.
  197. ///
  198. /// This method is generally expected to be failure-free, but it's still
  199. /// possible to fail. For example, the underlying file may not be writable
  200. /// at the time of shrink attempt; it also tries to remap the shrunk
  201. /// segment internally, and there's a small chance it could fail.
  202. /// In such a case it throws \c MemorySegmentError. If it's thrown the
  203. /// segment is not usable anymore.
  204. ///
  205. /// This method cannot be called if the segment object is created in the
  206. /// read-only mode; in that case MemorySegmentError will be thrown.
  207. ///
  208. /// \throw MemorySegmentError see the description.
  209. void shrinkToFit();
  210. /// \brief Return the actual segment size.
  211. ///
  212. /// This is generally expected to be the file size to map. It's
  213. /// provided mainly for diagnosis and testing purposes; the application
  214. /// shouldn't rely on specific return values of this method.
  215. ///
  216. /// \throw None
  217. size_t getSize() const;
  218. /// \brief Calculate a checksum over the memory segment.
  219. ///
  220. /// This method goes over all pages of the underlying mapped memory
  221. /// segment, and returns the sum of the value of the first byte of each
  222. /// page (wrapping around upon overflow). It only proves weak integrity
  223. /// of the file contents, but can run fast enough and will ensure all
  224. /// pages are actually in memory. The latter property will be useful
  225. /// if the application cannot allow the initial page fault overhead.
  226. ///
  227. /// \throw None
  228. size_t getCheckSum() const;
  229. private:
  230. struct Impl;
  231. Impl* impl_;
  232. };
  233. } // namespace util
  234. } // namespace isc
  235. #endif // MEMORY_SEGMENT_MAPPED_H
  236. // Local Variables:
  237. // mode: c++
  238. // End: