ztsdb
allocator.hpp
1 // (C) 2016 Leonardo Silvestri
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 
7 
8 #ifndef ALLOCATOR_HPP
9 #define ALLOCATOR_HPP
10 
11 
12 #include <string>
13 #include <exception>
14 #include <iostream>
15 #include <system_error>
16 #include <sys/mman.h>
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <sys/stat.h>
20 #include <boost/filesystem.hpp>
21 #include "misc.hpp"
22 
23 
24 // #define DEBUG
25 namespace fsys = boost::filesystem;
26 using namespace std::literals;
27 
28 
29 namespace arr {
30 
31  struct baseallocator {
32  virtual void* allocate(size_t sz) = 0;
33  virtual void deallocate(void* t, size_t n) = 0;
34  virtual void* reallocate(void* t, size_t n) = 0;
35  virtual void* initialize() = 0;
36  virtual size_t size() const = 0;
37  inline virtual void msync(bool async) const {
38  throw std::range_error("msync not defined for allocator type");
39  }
40  virtual ~baseallocator() noexcept(false) { }
41  };
42 
43 
45  memallocator() : t(nullptr) { }
46  inline void* allocate(size_t n) {
47  t = malloc(n);
48  if (t == nullptr) {
49  throw std::system_error(std::error_code(errno, std::system_category()), "malloc");
50  }
51  return t;
52  }
53  inline void deallocate(void* address, size_t n) {
54  free(t);
55  t = nullptr;
56  }
57  inline void* reallocate(void* old_address, size_t n) {
58  if (old_address != t) {
59  throw std::out_of_range("memallocator can't reallocate at an offset");
60  }
61  void* new_t = realloc(old_address, n);
62  if (new_t == nullptr) {
63  throw std::system_error(std::error_code(errno, std::system_category()), "realloc");
64  }
65  t = new_t;
66  return t;
67  }
68  inline void* initialize() {
69  throw std::out_of_range("memallocator has nothing to initialize from");
70  }
71  inline size_t size() const {
72  throw std::out_of_range("memallocator does not provide size");
73  }
74  ~memallocator() { if (t) free(t); }
75  private:
76  void* t;
77  };
78 
79 
81  flexallocator() : offset(0), t(nullptr), n(0), pagesz(sysconf(_SC_PAGESIZE)) { }
82 
83  inline void* allocate(size_t n_p) {
84  size_t pages = n_p / pagesz;
85  if (n_p % pagesz) {
86  ++pages;
87  }
88  n = pages * pagesz;
89  t = mmap(NULL, n, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
90  if (t == (void *)-1) {
91  throw std::system_error(std::error_code(errno, std::system_category()), "mmap (PRIVATE|ANON)");
92  }
93  return t;
94  }
95 
96  inline virtual void deallocate(void* t_p, size_t n_p) {
97  if (munmap(t_p, n_p) == -1) {
98  throw std::system_error(std::error_code(errno, std::system_category()), "munmap");
99  }
100  };
101 
102  inline virtual void* reallocate(void* t_p, size_t n_p) {
103  if (t_p < t) {
104  // we can't grow in front without moving the whole area...
105  throw std::out_of_range("can't reallocate with an address before start of mapping");
106  }
107  else if (t_p == (char*)t + offset) { // the outside world is oblivious of the offset...
108  size_t pages = (n_p + offset) / pagesz;
109  if ((n_p + offset) % pagesz) {
110  ++pages;
111  }
112  n_p = pages * pagesz;
113  if (n != n_p) {
114  t = mremap(t, n, n_p, MREMAP_MAYMOVE);
115  if (t == (void *)-1) {
116  throw std::system_error(std::error_code(errno, std::system_category()), "mremap");
117  }
118  n = n_p;
119  }
120  return (char*)t + offset;
121  }
122  else {
123  if (t_p > (char*)t + n) {
124  throw std::out_of_range("can't reallocate with an address beyond end of mapping");
125  }
126 
127  size_t sz = (char*)t_p - ((char*)t + offset);
128  size_t pages = sz / pagesz;
129  offset = sz % pagesz;
130 
131  if (pages) {
132  if (munmap(t, pages * pagesz) == -1) {
133  throw std::system_error(std::error_code(errno, std::system_category()), "munmap");
134  }
135 
136  t = (char*)t + pages * pagesz;
137  n -= pages * pagesz;
138  }
139 
140  return reallocate((char*)t + offset, n_p + offset);
141  }
142 
143  };
144 
145  inline void* initialize() {
146  throw std::out_of_range("flexallocator has nothing to initialize from");
147  }
148  inline size_t size() const {
149  throw std::out_of_range("flexallocator does not provide size");
150  }
151 
152  ~flexallocator() { munmap(t, n); }
153 
154  private:
155  size_t offset;
156  void* t;
157  size_t n;
158  const size_t pagesz;
159  };
160 
161 
163  mmapallocator(const fsys::path& filename_p) : t(nullptr), n(0), fd(-1), filename(filename_p) { }
164 
165  inline void* initialize() {
166  int fd = open(filename.c_str(), O_RDWR);
167  if (fd == -1) {
168  throw std::system_error(std::error_code(errno, std::system_category()),
169  "cannot open "s + filename.c_str());
170  }
171  // if file exists, map it:
172  off_t sz = lseek(fd, 0L, SEEK_END);
173  if (sz == -1) {
174  close(fd);
175  throw std::system_error(std::error_code(errno, std::system_category()), "lseek");
176  }
177  t = static_cast<void*>(mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
178  if (t == MAP_FAILED) {
179  close(fd);
180  throw std::system_error(std::error_code(errno, std::system_category()), "mmap");
181  }
182  n = sz;
183  return t; // nullptr if the file didn't exist
184  }
185 
186  inline size_t size() const { return n; }
187 
188  inline void* allocate(size_t sz) {
189  fd = open(filename.c_str(), O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
190  if (fd == -1) {
191  throw std::system_error(std::error_code(errno, std::system_category()), "open");
192  }
193  if (posix_fallocate(fd, 0, sz) == -1) {
194  close(fd);
195  throw std::system_error(std::error_code(errno, std::system_category()), "posix_fallocate");
196  }
197  t = static_cast<void*>(mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
198  if (t == MAP_FAILED) {
199  close(fd);
200  throw std::system_error(std::error_code(errno, std::system_category()), "mmap");
201  }
202  // close(fd); // file descriptor can be closed now
203  n = sz;
204  return t;
205  }
206 
207  inline void deallocate(void* address, size_t n) {
208  if (t) {
209  // unmap and delete the file
210  if (munmap(address, n) == -1) {
211  throw std::system_error(std::error_code(errno, std::system_category()), "munmap");
212  }
213  t = nullptr;
214  n = 0;
215  if (remove(filename.c_str()) != 0) {
216  throw std::system_error(std::error_code(errno, std::system_category()),
217  "can't remove "s + filename.c_str());
218  }
219  }
220  }
221 
222  inline void* reallocate(void* old_address, size_t new_size) {
223  if (old_address != t) {
224  throw std::out_of_range("mmapallocator can't reallocate at an offset");
225  }
226  if (lseek(fd, new_size, SEEK_SET) == -1) {
227  throw std::system_error(std::error_code(errno, std::system_category()), "lseek");
228  }
229  if (write(fd, "", 1) != 1) {
230  close(fd);
231  throw std::system_error(std::error_code(errno, std::system_category()), "write");
232  }
233  void *new_t = mremap(t, n, new_size, MREMAP_MAYMOVE);
234  if (new_t == MAP_FAILED) {
235  throw std::system_error(std::error_code(errno, std::system_category()), "mremap");
236  }
237  n = new_size;
238  t = new_t;
239  return t;
240  }
241 
242  inline virtual void msync(bool async) const {
243  if (async) {
244  if (::msync(t, n, MS_SYNC) == -1) {
245  throw std::system_error(std::error_code(errno, std::system_category()), "msync");
246  }
247  }
248  else {
249  if (::msync(t, n, MS_ASYNC) == -1) {
250  throw std::system_error(std::error_code(errno, std::system_category()), "msync");
251  }
252  }
253  }
254 
255  virtual ~mmapallocator() {
256  if (fd != -1) {
257  close(fd); // we can close
258  }
259  if (t) {
260  // std::cout << filename << " msync" << std::endl;
261  if (::msync(t, n, MS_SYNC) == -1) {
262  munmap(t, n);
263  throw std::system_error(std::error_code(errno, std::system_category()), "msync");
264  }
265  // std::cout << filename << " munmap" << std::endl;
266  if (munmap(t, n) == -1) {
267  throw std::system_error(std::error_code(errno, std::system_category()), "munmap");
268  }
269  }
270  }
271 
272  private:
273  void* t;
274  size_t n;
275  int fd;
276  const fsys::path filename;
277  };
278 
279 
280 } // end namespace arr
281 
282 #endif
arr::flexallocator
Definition: allocator.hpp:80
arr::memallocator
Definition: allocator.hpp:44
arr
Contains the classes and functions that implement a multidimentional array type.
Definition: allocator.hpp:29
arr::baseallocator
Definition: allocator.hpp:31
arr::mmapallocator
Definition: allocator.hpp:162