GCS  0.2.3
gu_alloc.hpp
1 /* Copyright (C) 2013 Codership Oy <info@codership.com> */
8 #ifndef _GU_ALLOC_HPP_
9 #define _GU_ALLOC_HPP_
10 
11 #include "gu_string.hpp"
12 #include "gu_fdesc.hpp"
13 #include "gu_mmap.hpp"
14 #include "gu_buf.hpp"
15 #include "gu_vector.hpp"
16 
17 #include "gu_macros.h" // gu_likely()
18 #include "gu_limits.h" // GU_PAGE_SIZE
19 
20 #include <cstdlib> // realloc(), free()
21 #include <string>
22 #include <iostream>
23 
24 namespace gu
25 {
26 
27 class Allocator
28 {
29 public:
30 
31  class BaseName
32  {
33  public:
34  virtual void print(std::ostream& os) const = 0;
35  virtual ~BaseName() {}
36  };
37 
38  // this questionable optimization reduces Allocator size by 8
39  // probably not worth the loss of generality.
40  typedef unsigned int page_size_type; // max page size
41  typedef page_size_type heap_size_type; // max heap store size
42 
43  explicit
44  Allocator (const BaseName& base_name = BASE_NAME_DEFAULT,
45  byte_t* reserved = NULL,
46  page_size_type reserved_size = 0,
47  heap_size_type max_heap = (1U << 22), /* 4M */
48  page_size_type disk_page_size = (1U << 26)); /* 64M */
49 
50  ~Allocator ();
51 
53  byte_t* alloc (page_size_type const size, bool& new_page);
54 
55  /* Total allocated size */
56  size_t size () const { return size_; }
57 
58  /* Total count of pages */
59  size_t count() const { return pages_->size(); }
60 
61 #ifdef GU_ALLOCATOR_DEBUG
62  /* appends own vector of Buf structures to the passed one,
63  * should be called only after all allocations have been made.
64  * returns sum of all appended buffers' sizes (same as size()) */
65  size_t gather (std::vector<Buf>& out) const;
66 #endif /* GU_ALLOCATOR_DEBUG */
67 
68  /* After we allocated 3 heap pages, spilling vector into heap should not
69  * be an issue. */
70  static size_t const INITIAL_VECTOR_SIZE = 4;
71 
72 private:
73 
74  class Page /* base class for memory and file pages */
75  {
76  public:
77 
78  Page (byte_t* ptr, size_t size)
79  : base_ptr_(ptr),
80  ptr_ (base_ptr_),
81  left_ (size)
82  {}
83 
84  virtual ~Page() {};
85 
86  byte_t* alloc (size_t size)
87  {
88  byte_t* ret = NULL;
89 
90  if (gu_likely(size <= left_))
91  {
92  ret = ptr_;
93  ptr_ += size;
94  left_ -= size;
95  }
96 
97  return ret;
98  }
99 
100  const byte_t* base() const { return base_ptr_; }
101  ssize_t size() const { return ptr_ - base_ptr_; }
102 
103  protected:
104 
105  byte_t* base_ptr_;
106  byte_t* ptr_;
107  page_size_type left_;
108 
109  Page& operator=(const Page&);
110  Page (const Page&);
111  };
112 
113  class HeapPage : public Page
114  {
115  public:
116 
117  HeapPage (page_size_type max_size);
118 
119  ~HeapPage () { free (base_ptr_); }
120  };
121 
122  class FilePage : public Page
123  {
124  public:
125 
126  FilePage (const std::string& name, page_size_type size);
127 
128  ~FilePage () { fd_.unlink(); }
129 
130  private:
131 
132  FileDescriptor fd_;
133  MMap mmap_;
134  };
135 
136  class PageStore
137  {
138  public:
139 
140  Page* new_page (page_size_type size) { return my_new_page(size); }
141 
142  protected:
143 
144  virtual ~PageStore() {}
145 
146  private:
147 
148  virtual Page* my_new_page (page_size_type size) = 0;
149  };
150 
151  class HeapStore : public PageStore
152  {
153  public:
154 
155  HeapStore (heap_size_type max) : PageStore(), left_(max) {}
156 
157  ~HeapStore () {}
158 
159  private:
160 
161  /* to avoid too frequent allocation, make it 64K */
162  static page_size_type const PAGE_SIZE = GU_PAGE_SIZE * 16;
163 
164  heap_size_type left_;
165 
166  Page* my_new_page (page_size_type const size);
167  };
168 
169  class FileStore : public PageStore
170  {
171  public:
172 
173  FileStore (const BaseName& base_name,
174  page_size_type page_size)
175  :
176  PageStore(),
177  base_name_(base_name),
178  page_size_(page_size),
179  n_ (0)
180  {}
181 
182  ~FileStore() {}
183 
184  const BaseName& base_name() const { return base_name_; }
185  int size() const { return n_; }
186 
187  private:
188 
189  const BaseName& base_name_;
190  page_size_type const page_size_;
191  int n_;
192 
193  Page* my_new_page (page_size_type const size);
194 
195  FileStore (const FileStore&);
196  FileStore& operator= (const FileStore&);
197  };
198 
199  Page first_page_;
200  Page* current_page_;
201 
202  HeapStore heap_store_;
203  FileStore file_store_;
204  PageStore* current_store_;
205 
207 
208 #ifdef GU_ALLOCATOR_DEBUG
210  void add_current_to_bufs();
211 #endif /* GU_ALLOCATOR_DEBUG */
212 
213  size_t size_;
214 
215  Allocator(const gu::Allocator&);
216  const Allocator& operator=(const gu::Allocator&);
217 
218  class BaseNameDefault : public BaseName
219  {
220  public:
221  BaseNameDefault() {} // this is seemingly required by the standard
222  void print(std::ostream& os) const { os << "alloc"; }
223  };
224 
225  static BaseNameDefault const BASE_NAME_DEFAULT;
226 
227 }; /* class Allocator */
228 
229 inline
230 std::ostream& operator<< (std::ostream& os, const Allocator::BaseName& bn)
231 {
232  bn.print(os); return os;
233 }
234 
235 } /* namespace gu */
236 
237 #endif /* _GU_ALLOC_HPP_ */
byte_t * alloc(page_size_type const size, bool &new_page)
Definition: gu_alloc.hpp:27
Definition: gu_alloc.hpp:31