1 /*
2  * This code is (c) 2012 Johannes Thoma
3  *
4  * modified 2018 by D. Mitch Bailey
5  *
6  * This file is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This file is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this file.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * You can download original source from https://github.com/johannesthoma/mmap_allocator.git
20  */
21 
22 #ifndef _MMAP_ALLOCATOR_H
23 #define _MMAP_ALLOCATOR_H
24 
25 #include <memory>
26 #include <string>
27 #include <stdio.h>
28 #include <vector>
29 #include "mmap_access_mode.h"
30 #include "mmap_exception.h"
31 #include "mmap_file_pool.h"
32 
33 namespace mmap_allocator_namespace
34 {
35 	template <typename T>
36 	class mmap_allocator;  // required forward declaration for following default
37 	template <typename T, typename A = mmap_allocator<T> >
38 	class mmappable_vector;
39 
40 	template <typename T>
41 	class mmap_allocator: public std::allocator<T>
42 	{
43 public:
44 		typedef size_t size_type;
45 		typedef off_t offset_type;
46 		typedef T* pointer;
47 		typedef const T* const_pointer;
48 
49 		template<typename _Tp1>
50 		struct rebind
51 		{
52 			typedef mmap_allocator<_Tp1> other;
53 		};
54 
55 		pointer allocate(size_type n, const void *hint=0)
56 		{
57 			void *the_pointer;
58 			if (get_verbosity() > 0) {
59 				fprintf(stderr, "Alloc %zd bytes.\n", n*sizeof(T));
60 			}
61 			if (access_mode == DEFAULT_STL_ALLOCATOR) {
62 				return std::allocator<T>::allocate(n, hint);
63 			} else {
64 				if (n == 0) {
65 					return NULL;
66 				}
67 				if (bypass_file_pool) {
68 					the_pointer = private_file.open_and_mmap_file(filename, access_mode, offset, n*sizeof(T), map_whole_file, allow_remap);
69 				} else {
70 					the_pointer = the_pool.mmap_file(filename, access_mode, offset, n*sizeof(T), map_whole_file, allow_remap);
71 				}
72 				if (the_pointer == NULL) {
73 					throw(mmap_allocator_exception("Couldn't mmap file, mmap_file returned NULL"));
74 				}
75 				if (get_verbosity() > 0) {
76 					fprintf(stderr, "pointer = %p\n", the_pointer);
77 				}
78 
79 				return (pointer)the_pointer;
80 			}
81 		}
82 
deallocate(pointer p,size_type n)83 		void deallocate(pointer p, size_type n)
84 		{
85 			if (get_verbosity() > 0) {
86 				fprintf(stderr, "Dealloc %zd bytes (%p).\n", n*sizeof(T), p);
87 			}
88 			if (access_mode == DEFAULT_STL_ALLOCATOR) {
89 				std::allocator<T>::deallocate(p, n);
90 			} else {
91 				if (n == 0) {
92 					return;
93 				}
94 				if (bypass_file_pool) {
95 					private_file.munmap_and_close_file();
96 				} else {
97 					if (!keep_forever) {
98 						the_pool.munmap_file(filename, access_mode, offset, n*sizeof(T));
99 					}
100 				}
101 			}
102 		}
103 
throw()104 		mmap_allocator() throw():
105 			std::allocator<T>(),
106 			filename(""),
107 			offset(0),
108 			access_mode(DEFAULT_STL_ALLOCATOR),
109 			map_whole_file(false),
110 			allow_remap(false),
111 			bypass_file_pool(false),
112 			private_file(),
113 			keep_forever(false)
114 		{ }
115 
throw()116 		mmap_allocator(const std::allocator<T> &a) throw():
117 			std::allocator<T>(a),
118 			filename(""),
119 			offset(0),
120 			access_mode(DEFAULT_STL_ALLOCATOR),
121 			map_whole_file(false),
122 			allow_remap(false),
123 			bypass_file_pool(false),
124 			private_file(),
125 			keep_forever(false)
126 		{ }
127 
throw()128 		mmap_allocator(const mmap_allocator &a) throw():
129 			std::allocator<T>(a),
130 			filename(a.filename),
131 			offset(a.offset),
132 			access_mode(a.access_mode),
133 			map_whole_file(a.map_whole_file),
134 			allow_remap(a.allow_remap),
135 			bypass_file_pool(a.bypass_file_pool),
136 			private_file(a.private_file),
137 			keep_forever(a.keep_forever)
138 		{ }
throw()139 		mmap_allocator(const std::string filename_param, enum access_mode access_mode_param = READ_ONLY, offset_type offset_param = 0, int flags = 0) throw():
140 			std::allocator<T>(),
141 			filename(filename_param),
142 			offset(offset_param),
143 			access_mode(access_mode_param),
144 			map_whole_file((flags & MAP_WHOLE_FILE) != 0),
145 			allow_remap((flags & ALLOW_REMAP) != 0),
146 			bypass_file_pool((flags & BYPASS_FILE_POOL) != 0),
147 			private_file(),
148 			keep_forever((flags & KEEP_FOREVER) != 0)
149 		{
150 		}
151 
throw()152 		~mmap_allocator() throw() { }
153 
154 private:
155 		friend class mmappable_vector<T, mmap_allocator<T> >;
156 
157 		std::string filename;
158 		offset_type offset;
159 		enum access_mode access_mode;
160 		bool map_whole_file;
161 		bool allow_remap;
162 		bool bypass_file_pool;
163 		mmapped_file private_file;  /* used if bypass is set */
164 		bool keep_forever;
165 	};
166 }
167 
168 #endif /* _MMAP_ALLOCATOR_H */
169