1 #ifndef MMAP_ALLOCATOR_H 2 #define MMAP_ALLOCATOR_H 3 4 #include "macros.h" 5 #include <cstdio> 6 #include <sys/types.h> 7 8 #include <memory> 9 #include <limits> 10 #include <string> 11 #include <stdexcept> 12 13 /* This is inspired from https://github.com/johannesthoma/mmap_allocator 14 * License is LGPL. 15 * The version here has been trimmed down significantly, look for uptream 16 * version for more features */ 17 18 namespace mmap_allocator_details 19 { 20 typedef off_t offset_type; 21 typedef size_t size_type; 22 23 enum access_mode { 24 DEFAULT_STL_ALLOCATOR, /* Default STL allocator (malloc based). Reason is to have containers that do both and are compatible */ 25 READ_ONLY, /* Readonly modus. Segfaults when vector content is written to */ 26 READ_WRITE_PRIVATE, /* Read/write access, writes are not propagated to disk */ 27 READ_WRITE_SHARED /* Read/write access, writes are propagated to disk (file is modified) */ 28 }; 29 30 struct mmap_allocator_exception: public std::runtime_error { mmap_allocator_exceptionmmap_allocator_details::mmap_allocator_exception31 mmap_allocator_exception(const char *msg_param): 32 std::runtime_error(msg_param) { } 33 mmap_allocator_exceptionmmap_allocator_details::mmap_allocator_exception34 mmap_allocator_exception(std::string msg_param): 35 std::runtime_error(msg_param) { } 36 ~mmap_allocator_exceptionmmap_allocator_details::mmap_allocator_exception37 virtual ~mmap_allocator_exception(void) noexcept { } 38 }; 39 40 /* Only the mmapped_file is something we can use to grab mapping 41 * segments. Once the mmapped_file object is destroyed, the segments 42 * survive because of shared_ptr's. 43 */ 44 class mmapped_file { 45 public: 46 private: 47 class mapping { 48 int fd = -1; 49 void * area = NULL; 50 offset_type offset_mapped; /* page-aligned */ 51 size_type length_mapped; /* page-aligned */ 52 public: 53 mapping(const char * fname, enum access_mode access_mode, offset_type offset, size_type length); 54 ~mapping(); 55 void * get(offset_type, size_type); 56 void put(void *, offset_type, size_type); 57 }; 58 #if 0 59 /* use this to trace shared_ptr games. */ 60 class shared_mapping : private std::shared_ptr<mapping> { 61 public: 62 template<typename... Args> shared_mapping(Args... args) : 63 std::shared_ptr<mapping>(args...) { 64 fprintf(stderr, "Creating a shared_ptr [%p]\n", (void*) get()); 65 } 66 shared_mapping(std::shared_ptr<mapping> const & s) : std::shared_ptr<mapping>(s) { 67 fprintf(stderr, "Copying a shared_ptr [%p]\n", (void*) get()); 68 } 69 shared_mapping(shared_mapping const & s) : std::shared_ptr<mapping>(s) { 70 fprintf(stderr, "Copying a shared_ptr [%p]\n", (void*) get()); 71 } 72 ~shared_mapping() { 73 fprintf(stderr, "Destroying a shared_ptr [%p]\n", (void*) get()); 74 } 75 mapping * operator->() { return std::shared_ptr<mapping>::operator->(); } 76 mapping const * operator->() const { return std::shared_ptr<mapping>::operator->(); } 77 operator bool() const { return (std::shared_ptr<mapping> const&)(*this) != nullptr; } 78 }; 79 #endif 80 std::shared_ptr<mapping> m; 81 public: 82 class segment { 83 public: 84 std::shared_ptr<mapping> file; 85 offset_type offset; 86 size_type length; 87 /* with shared_mapping above that defines an operator 88 * bool, we just say "return file" */ operator bool() const89 operator bool() const { return file != nullptr; } get(size_type s)90 void * get(size_type s) { 91 if (s == 0) return NULL; 92 ASSERT_ALWAYS(s == length); 93 return file->get(offset, length); 94 } put(void * p,size_type s)95 void put(void * p, size_type s) { 96 if (s == 0) return; 97 ASSERT_ALWAYS(s == length); 98 file->put(p, offset, length); 99 } 100 }; 101 public: get_segment(offset_type offset,size_type length)102 segment get_segment(offset_type offset, size_type length) { 103 return segment { m, offset, length }; 104 } mmapped_file(const char * fname,access_mode mode=READ_ONLY,offset_type offset=0,size_type length=std::numeric_limits<size_type>::max ())105 mmapped_file(const char * fname, access_mode mode = READ_ONLY, offset_type offset = 0, size_type length = std::numeric_limits<size_type>::max()) : m(std::make_shared<mapping>(fname, mode, offset, length)) {} 106 }; 107 108 template <typename T> class mmap_allocator: public std::allocator<T> 109 { 110 public: 111 using typename std::allocator<T>::size_type; 112 using typename std::allocator<T>::pointer; 113 using typename std::allocator<T>::const_pointer; 114 typedef mmap_allocator_details::offset_type offset_type; 115 private: 116 mmapped_file::segment s; 117 public: has_defined_mapping() const118 bool has_defined_mapping() const { return s; } 119 template<typename _Tp1> 120 struct rebind { typedef mmap_allocator<_Tp1> other; }; 121 allocate(size_type n,const void * hint=0)122 pointer allocate(size_type n, const void *hint=0) 123 { 124 if (!s) 125 return std::allocator<T>::allocate(n, hint); 126 127 if (n == 0) return NULL; 128 129 return (pointer) s.get(n*sizeof(T)); 130 } 131 deallocate(pointer p,size_type n)132 void deallocate(pointer p, size_type n) 133 { 134 if (!s) { 135 std::allocator<T>::deallocate(p, n); 136 return; 137 } 138 139 if (n == 0) return; 140 141 s.put(p, n*sizeof(T)); 142 } 143 144 mmap_allocator() = default; mmap_allocator(const std::allocator<T> & a)145 mmap_allocator(const std::allocator<T> &a): std::allocator<T>(a) {} 146 mmap_allocator(const mmap_allocator &) = default; 147 ~mmap_allocator() = default; 148 149 /* These are the only ctors that enable a behaviour that 150 * differs from the stl container */ mmap_allocator(mmapped_file::segment const & s)151 mmap_allocator(mmapped_file::segment const & s) : s(s) {} mmap_allocator(mmapped_file m,offset_type offset,size_type length)152 mmap_allocator(mmapped_file m, offset_type offset, size_type length) : s(m.get_segment(offset, length * sizeof(T))) {} mmap_allocator(const char * f,access_mode mode,offset_type offset,size_type length)153 mmap_allocator(const char * f, access_mode mode, offset_type offset, size_type length) : mmap_allocator(mmapped_file(f, mode, offset, length*sizeof(T)), offset, length) {} 154 155 }; 156 } 157 158 #endif /* MMAP_ALLOCATOR_H */ 159