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