1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6
7
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9
10 PerconaFT is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License, version 2,
12 as published by the Free Software Foundation.
13
14 PerconaFT is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
21
22 ----------------------------------------
23
24 PerconaFT is free software: you can redistribute it and/or modify
25 it under the terms of the GNU Affero General Public License, version 3,
26 as published by the Free Software Foundation.
27
28 PerconaFT is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU Affero General Public License for more details.
32
33 You should have received a copy of the GNU Affero General Public License
34 along with PerconaFT. If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38
39 #include <string.h>
40 #include <memory.h>
41 #include <toku_assert.h>
42 #include "mempool.h"
43
44 /* Contract:
45 * Caller allocates mempool struct as convenient for caller, but memory used for data storage
46 * must be dynamically allocated via toku_malloc().
47 * Caller dynamically allocates memory for mempool and initializes mempool by calling toku_mempool_init().
48 * Once a buffer is assigned to a mempool (via toku_mempool_init()), the mempool owns it and
49 * is responsible for destroying it when the mempool is destroyed.
50 * Caller destroys mempool by calling toku_mempool_destroy().
51 *
52 * Note, toku_mempool_init() does not allocate the memory because sometimes the caller will already have
53 * the memory allocated and will assign the pre-allocated memory to the mempool.
54 */
55
56 /* This is a constructor to be used when the memory for the mempool struct has been
57 * allocated by the caller, but no memory has yet been allocatd for the data.
58 */
toku_mempool_zero(struct mempool * mp)59 void toku_mempool_zero(struct mempool *mp) {
60 // printf("mempool_zero %p\n", mp);
61 memset(mp, 0, sizeof(*mp));
62 }
63
64 // TODO 4050 this is dirty, try to replace all uses of this
toku_mempool_init(struct mempool * mp,void * base,size_t free_offset,size_t size)65 void toku_mempool_init(struct mempool *mp, void *base, size_t free_offset, size_t size) {
66 // printf("mempool_init %p %p %lu\n", mp, base, size);
67 paranoid_invariant(base != 0);
68 paranoid_invariant(size < (1U<<31)); // used to be assert(size >= 0), but changed to size_t so now let's make sure it's not more than 2GB...
69 paranoid_invariant(free_offset <= size);
70 mp->base = base;
71 mp->size = size;
72 mp->free_offset = free_offset; // address of first available memory
73 mp->frag_size = 0; // byte count of wasted space (formerly used, no longer used or available)
74 }
75
76 /* allocate memory and construct mempool
77 */
toku_mempool_construct(struct mempool * mp,size_t data_size)78 void toku_mempool_construct(struct mempool *mp, size_t data_size) {
79 if (data_size) {
80 // add 25% slack
81 size_t mp_size = data_size + (data_size / 4);
82 mp->base = toku_xmalloc_aligned(64, mp_size);
83 mp->size = mp_size;
84 mp->free_offset = 0;
85 mp->frag_size = 0;
86 }
87 else {
88 toku_mempool_zero(mp);
89 }
90 }
91
toku_mempool_reset(struct mempool * mp)92 void toku_mempool_reset(struct mempool *mp) {
93 mp->free_offset = 0;
94 mp->frag_size = 0;
95 }
96
toku_mempool_realloc_larger(struct mempool * mp,size_t data_size)97 void toku_mempool_realloc_larger(struct mempool *mp, size_t data_size) {
98 invariant(data_size >= mp->free_offset);
99
100 size_t mpsize = data_size + (data_size/4); // allow 1/4 room for expansion (would be wasted if read-only)
101 void* newmem = toku_xmalloc_aligned(64, mpsize); // allocate new buffer for mempool
102 memcpy(newmem, mp->base, mp->free_offset); // Copy old info
103 toku_free(mp->base);
104 mp->base = newmem;
105 mp->size = mpsize;
106 }
107
108
toku_mempool_destroy(struct mempool * mp)109 void toku_mempool_destroy(struct mempool *mp) {
110 // printf("mempool_destroy %p %p %lu %lu\n", mp, mp->base, mp->size, mp->frag_size);
111 if (mp->base)
112 toku_free(mp->base);
113 toku_mempool_zero(mp);
114 }
115
toku_mempool_get_base(const struct mempool * mp)116 void *toku_mempool_get_base(const struct mempool *mp) {
117 return mp->base;
118 }
119
toku_mempool_get_pointer_from_base_and_offset(const struct mempool * mp,size_t offset)120 void *toku_mempool_get_pointer_from_base_and_offset(const struct mempool *mp, size_t offset) {
121 return reinterpret_cast<void*>(reinterpret_cast<char*>(mp->base) + offset);
122 }
123
toku_mempool_get_offset_from_pointer_and_base(const struct mempool * mp,const void * p)124 size_t toku_mempool_get_offset_from_pointer_and_base(const struct mempool *mp, const void* p) {
125 paranoid_invariant(p >= mp->base);
126 return reinterpret_cast<const char*>(p) - reinterpret_cast<const char*>(mp->base);
127 }
128
toku_mempool_get_size(const struct mempool * mp)129 size_t toku_mempool_get_size(const struct mempool *mp) {
130 return mp->size;
131 }
132
toku_mempool_get_frag_size(const struct mempool * mp)133 size_t toku_mempool_get_frag_size(const struct mempool *mp) {
134 return mp->frag_size;
135 }
136
toku_mempool_get_used_size(const struct mempool * mp)137 size_t toku_mempool_get_used_size(const struct mempool *mp) {
138 return mp->free_offset - mp->frag_size;
139 }
140
toku_mempool_get_next_free_ptr(const struct mempool * mp)141 void* toku_mempool_get_next_free_ptr(const struct mempool *mp) {
142 return toku_mempool_get_pointer_from_base_and_offset(mp, mp->free_offset);
143 }
144
toku_mempool_get_offset_limit(const struct mempool * mp)145 size_t toku_mempool_get_offset_limit(const struct mempool *mp) {
146 return mp->free_offset;
147 }
148
toku_mempool_get_free_size(const struct mempool * mp)149 size_t toku_mempool_get_free_size(const struct mempool *mp) {
150 return mp->size - mp->free_offset;
151 }
152
toku_mempool_get_allocated_size(const struct mempool * mp)153 size_t toku_mempool_get_allocated_size(const struct mempool *mp) {
154 return mp->free_offset;
155 }
156
toku_mempool_malloc(struct mempool * mp,size_t size)157 void *toku_mempool_malloc(struct mempool *mp, size_t size) {
158 paranoid_invariant(size < (1U<<31));
159 paranoid_invariant(mp->size < (1U<<31));
160 paranoid_invariant(mp->free_offset < (1U<<31));
161 paranoid_invariant(mp->free_offset <= mp->size);
162 void *vp;
163 if (mp->free_offset + size > mp->size) {
164 vp = nullptr;
165 } else {
166 vp = reinterpret_cast<char *>(mp->base) + mp->free_offset;
167 mp->free_offset += size;
168 }
169 paranoid_invariant(mp->free_offset <= mp->size);
170 paranoid_invariant(vp == 0 || toku_mempool_inrange(mp, vp, size));
171 return vp;
172 }
173
174 // if vp is null then we are freeing something, but not specifying what. The data won't be freed until compression is done.
toku_mempool_mfree(struct mempool * mp,void * vp,size_t size)175 void toku_mempool_mfree(struct mempool *mp, void *vp, size_t size) {
176 if (vp) { paranoid_invariant(toku_mempool_inrange(mp, vp, size)); }
177 mp->frag_size += size;
178 invariant(mp->frag_size <= mp->free_offset);
179 invariant(mp->frag_size <= mp->size);
180 }
181
182
183 /* get memory footprint */
toku_mempool_footprint(struct mempool * mp)184 size_t toku_mempool_footprint(struct mempool *mp) {
185 void * base = mp->base;
186 size_t touched = mp->free_offset;
187 size_t rval = toku_memory_footprint(base, touched);
188 return rval;
189 }
190
toku_mempool_clone(const struct mempool * orig_mp,struct mempool * new_mp)191 void toku_mempool_clone(const struct mempool* orig_mp, struct mempool* new_mp) {
192 new_mp->frag_size = orig_mp->frag_size;
193 new_mp->free_offset = orig_mp->free_offset;
194 new_mp->size = orig_mp->free_offset; // only make the cloned mempool store what is needed
195 new_mp->base = toku_xmalloc_aligned(64, new_mp->size);
196 memcpy(new_mp->base, orig_mp->base, new_mp->size);
197 }
198