MiniOB 1
MiniOB is one mini database, helping developers to learn how database works.
载入中...
搜索中...
未找到
mem_pool.h
1/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
2miniob is licensed under Mulan PSL v2.
3You can use this software according to the terms and conditions of the Mulan PSL v2.
4You may obtain a copy of Mulan PSL v2 at:
5 http://license.coscl.org.cn/MulanPSL2
6THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
7EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
8MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
9See the Mulan PSL v2 for more details. */
10
11//
12// Created by Longda on 2010
13//
14
15#pragma once
16
17#include <sstream>
18
19#include "common/lang/mutex.h"
20#include "common/lang/string.h"
21#include "common/lang/set.h"
22#include "common/lang/list.h"
23#include "common/lang/memory.h"
24#include "common/lang/sstream.h"
25#include "common/log/log.h"
26#include "common/os/os.h"
27
28#include <sanitizer/asan_interface.h>
29
30namespace common {
31
32#define DEFAULT_ITEM_NUM_PER_POOL 128
33#define DEFAULT_POOL_NUM 1
34
35typedef bool (*match)(void *item, void *input_arg);
36
37template <class T>
39{
40public:
41 MemPool(const char *tag) : name(tag)
42 {
43 this->size = 0;
44
45 pthread_mutexattr_t mutexatr;
46 pthread_mutexattr_init(&mutexatr);
47 pthread_mutexattr_settype(&mutexatr, PTHREAD_MUTEX_RECURSIVE);
48
49 MUTEX_INIT(&mutex, &mutexatr);
50 }
51
52 virtual ~MemPool() { MUTEX_DESTROY(&mutex); }
53
60 virtual int init(
61 bool dynamic = true, int pool_num = DEFAULT_POOL_NUM, int item_num_per_pool = DEFAULT_ITEM_NUM_PER_POOL) = 0;
62
66 virtual void cleanup() = 0;
67
71 virtual int extend() = 0;
72
77 virtual T *alloc() = 0;
78
83 virtual void free(T *item) = 0;
84
89 virtual string to_string() = 0;
90
91 const string get_name() const { return name; }
92 bool is_dynamic() const { return dynamic; }
93 int get_size() const { return size; }
94
95protected:
96 pthread_mutex_t mutex;
97 int size;
98 bool dynamic;
99 string name;
100};
101
107template <class T>
108class MemPoolSimple : public MemPool<T>
109{
110public:
111 MemPoolSimple(const char *tag) : MemPool<T>(tag) {}
112
113 virtual ~MemPoolSimple() { cleanup(); }
114
121 int init(bool dynamic = true, int pool_num = DEFAULT_POOL_NUM, int item_num_per_pool = DEFAULT_ITEM_NUM_PER_POOL);
122
126 void cleanup();
127
131 int extend();
132
137 T *alloc();
138
143 void free(T *item);
144
149 string to_string();
150
151 int get_item_num_per_pool() const { return item_num_per_pool; }
152
153 int get_used_num()
154 {
155 MUTEX_LOCK(&this->mutex);
156 auto num = used.size();
157 MUTEX_UNLOCK(&this->mutex);
158 return num;
159 }
160
161protected:
162 list<T *> pools;
163 set<T *> used;
164 list<T *> frees;
165 int item_num_per_pool;
166
167private:
168 inline void asan_poison(void *addr, size_t size) { ASAN_POISON_MEMORY_REGION(addr, size); }
169 inline void asan_unpoison(void *addr, size_t size) { ASAN_UNPOISON_MEMORY_REGION(addr, size); }
170};
171
172template <class T>
173int MemPoolSimple<T>::init(bool dynamic, int pool_num, int item_num_per_pool)
174{
175 if (pools.empty() == false) {
176 LOG_WARN("Memory pool has been initialized, but still begin to be initialized, this->name:%s.", this->name.c_str());
177 return 0;
178 }
179
180 if (pool_num <= 0 || item_num_per_pool <= 0) {
181 LOG_ERROR("Invalid arguments, pool_num:%d, item_num_per_pool:%d, this->name:%s.",
182 pool_num, item_num_per_pool, this->name.c_str());
183 return -1;
184 }
185
186 this->item_num_per_pool = item_num_per_pool;
187 // in order to init memory pool, enable dynamic here
188 this->dynamic = true;
189 for (int i = 0; i < pool_num; i++) {
190 if (extend() < 0) {
191 cleanup();
192 return -1;
193 }
194 }
195 this->dynamic = dynamic;
196
197 LOG_INFO("Extend one pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
198 this->size, item_num_per_pool, this->name.c_str());
199 return 0;
200}
201
202template <class T>
204{
205 if (pools.empty() == true) {
206 LOG_WARN("Begin to do cleanup, but there is no memory pool, this->name:%s!", this->name.c_str());
207 return;
208 }
209 MUTEX_LOCK(&this->mutex);
210 for (auto &&i : frees) {
211 asan_unpoison(i, sizeof(T));
212 }
213 used.clear();
214 frees.clear();
215 this->size = 0;
216
217 for (typename list<T *>::iterator iter = pools.begin(); iter != pools.end(); iter++) {
218 T *pool = *iter;
219 delete[] pool;
220 }
221 pools.clear();
222 MUTEX_UNLOCK(&this->mutex);
223 LOG_INFO("Successfully do cleanup, this->name:%s.", this->name.c_str());
224}
225
226template <class T>
228{
229 if (this->dynamic == false) {
230 LOG_ERROR("Disable dynamic extend memory pool, but begin to extend, this->name:%s", this->name.c_str());
231 return -1;
232 }
233
234 MUTEX_LOCK(&this->mutex);
235 T *pool = new T[item_num_per_pool];
236 if (pool == nullptr) {
237 MUTEX_UNLOCK(&this->mutex);
238 LOG_ERROR("Failed to extend memory pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
239 this->size, item_num_per_pool, this->name.c_str());
240 return -1;
241 }
242
243 pools.push_back(pool);
244 this->size += item_num_per_pool;
245 for (int i = 0; i < item_num_per_pool; i++) {
246 frees.push_back(pool + i);
247 asan_poison(pool + i, sizeof(T));
248 }
249 MUTEX_UNLOCK(&this->mutex);
250
251 LOG_INFO("Extend one pool, this->size:%d, item_num_per_pool:%d, this->name:%s.",
252 this->size, item_num_per_pool, this->name.c_str());
253 return 0;
254}
255
256template <class T>
258{
259 MUTEX_LOCK(&this->mutex);
260 if (frees.empty() == true) {
261 if (this->dynamic == false) {
262 MUTEX_UNLOCK(&this->mutex);
263 return nullptr;
264 }
265
266 if (extend() < 0) {
267 MUTEX_UNLOCK(&this->mutex);
268 return nullptr;
269 }
270 }
271 T *buffer = frees.front();
272 asan_unpoison(buffer, sizeof(T));
273 frees.pop_front();
274
275 used.insert(buffer);
276
277 MUTEX_UNLOCK(&this->mutex);
278 buffer->reinit();
279 return buffer;
280}
281
282template <class T>
284{
285 buf->reset();
286
287 MUTEX_LOCK(&this->mutex);
288
289 size_t num = used.erase(buf);
290 if (num == 0) {
291 MUTEX_UNLOCK(&this->mutex);
292 LOG_WARN("No entry of %p in %s.", buf, this->name.c_str());
293 print_stacktrace();
294 return;
295 }
296 asan_poison(buf, sizeof(T));
297 frees.push_back(buf);
298
299 MUTEX_UNLOCK(&this->mutex);
300 return; // TODO for test
301}
302
303template <class T>
305{
306 stringstream ss;
307
308 ss << "name:" << this->name << ","
309 << "dyanmic:" << this->dynamic << ","
310 << "size:" << this->size << ","
311 << "pool_size:" << this->pools.size() << ","
312 << "used_size:" << this->used.size() << ","
313 << "free_size:" << this->frees.size();
314 return ss.str();
315}
316
318{
319public:
320 using item_unique_ptr = unique_ptr<void, function<void(void *const)>>;
321
322public:
323 MemPoolItem(const char *tag) : name(tag)
324 {
325 this->size = 0;
326
327 pthread_mutexattr_t mutexatr;
328 pthread_mutexattr_init(&mutexatr);
329 pthread_mutexattr_settype(&mutexatr, PTHREAD_MUTEX_RECURSIVE);
330
331 MUTEX_INIT(&mutex, &mutexatr);
332 }
333
334 virtual ~MemPoolItem()
335 {
336 cleanup();
337 MUTEX_DESTROY(&mutex);
338 }
339
346 int init(int item_size, bool dynamic = true, int pool_num = DEFAULT_POOL_NUM,
347 int item_num_per_pool = DEFAULT_ITEM_NUM_PER_POOL);
348
352 void cleanup();
353
357 int extend();
358
363 void *alloc();
364 item_unique_ptr alloc_unique_ptr();
365
370 void free(void *item);
371
377 bool is_used(void *item)
378 {
379 MUTEX_LOCK(&mutex);
380 auto it = used.find(item);
381 MUTEX_UNLOCK(&mutex);
382 return it != used.end();
383 }
384
385 string to_string()
386 {
387
388 stringstream ss;
389
390 ss << "name:" << this->name << ","
391 << "dyanmic:" << this->dynamic << ","
392 << "size:" << this->size << ","
393 << "pool_size:" << this->pools.size() << ","
394 << "used_size:" << this->used.size() << ","
395 << "free_size:" << this->frees.size();
396 return ss.str();
397 }
398
399 const string get_name() const { return name; }
400 bool is_dynamic() const { return dynamic; }
401 int get_size() const { return size; }
402 int get_item_size() const { return item_size; }
403 int get_item_num_per_pool() const { return item_num_per_pool; }
404
405 int get_used_num()
406 {
407 MUTEX_LOCK(&mutex);
408 auto num = used.size();
409 MUTEX_UNLOCK(&mutex);
410 return num;
411 }
412
413protected:
414 pthread_mutex_t mutex;
415 string name;
416 bool dynamic;
417 int size;
418 int item_size;
419 int item_num_per_pool;
420
421 list<void *> pools;
422 set<void *> used;
423 list<void *> frees;
424};
425
426} // namespace common
Definition: mem_pool.h:318
void cleanup()
Definition: mem_pool.cpp:47
void * alloc()
Definition: mem_pool.cpp:104
int init(int item_size, bool dynamic=true, int pool_num=DEFAULT_POOL_NUM, int item_num_per_pool=DEFAULT_ITEM_NUM_PER_POOL)
Definition: mem_pool.cpp:17
int extend()
Definition: mem_pool.cpp:70
bool is_used(void *item)
Definition: mem_pool.h:377
void free(void *item)
Definition: mem_pool.cpp:136
Definition: mem_pool.h:109
void cleanup()
Definition: mem_pool.h:203
int extend()
Definition: mem_pool.h:227
string to_string()
Definition: mem_pool.h:304
void free(T *item)
Definition: mem_pool.h:283
int init(bool dynamic=true, int pool_num=DEFAULT_POOL_NUM, int item_num_per_pool=DEFAULT_ITEM_NUM_PER_POOL)
Definition: mem_pool.h:173
T * alloc()
Definition: mem_pool.h:257
Definition: mem_pool.h:39
virtual void cleanup()=0
virtual void free(T *item)=0
virtual T * alloc()=0
virtual string to_string()=0
virtual int init(bool dynamic=true, int pool_num=DEFAULT_POOL_NUM, int item_num_per_pool=DEFAULT_ITEM_NUM_PER_POOL)=0
virtual int extend()=0