]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
Initial revision
[bacula/bacula] / bacula / src / lib / mem_pool.c
1 /*
2  *  Bacula memory pool routines. 
3  *
4  *  The idea behind these routines is that there will be
5  *  pools of memory that are pre-allocated for quick
6  *  access. The pools will have a fixed memory size on allocation
7  *  but if need be, the size can be increased. This is 
8  *  particularly useful for filename
9  *  buffers where 256 bytes should be sufficient in 99.99%
10  *  of the cases, but when it isn't we want to be able to
11  *  increase the size.
12  *
13  *  A major advantage of the pool memory aside from the speed
14  *  is that the buffer carrys around its size, so to ensure that
15  *  there is enough memory, simply call the check_pool_memory_size()
16  *  with the desired size and it will adjust only if necessary.
17  *
18  *           Kern E. Sibbald
19  */
20
21 /*
22    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
23
24    This program is free software; you can redistribute it and/or
25    modify it under the terms of the GNU General Public License as
26    published by the Free Software Foundation; either version 2 of
27    the License, or (at your option) any later version.
28
29    This program is distributed in the hope that it will be useful,
30    but WITHOUT ANY WARRANTY; without even the implied warranty of
31    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
32    General Public License for more details.
33
34    You should have received a copy of the GNU General Public
35    License along with this program; if not, write to the Free
36    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
37    MA 02111-1307, USA.
38
39  */
40
41 #include "bacula.h"
42
43 struct s_pool_ctl {
44    size_t size;                       /* default size */
45    size_t max_size;                   /* max allocated */
46    size_t max_used;                   /* max buffers used */
47    size_t in_use;                     /* number in use */
48    struct abufhead *free_buf;         /* pointer to free buffers */
49 };
50
51 static struct s_pool_ctl pool_ctl[] = {
52    {  256,  256, 0, 0, NULL },        /* PM_NOPOOL no pooling */
53    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
54    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
55    { 1024, 1024, 0, 0, NULL }         /* PM_EMSG error message buffer */
56 };
57
58 /*  Memory allocation control structures and storage.  */
59 struct abufhead {
60    size_t ablen;                      /* Buffer length in bytes */
61    int32_t pool;                      /* pool */
62    struct abufhead *next;             /* pointer to next free buffer */
63 };
64
65 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
66
67
68 #ifdef SMARTALLOC
69
70 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
71
72 extern void *sm_malloc(char *fname, int lineno, int nbytes);
73
74 void *sm_get_pool_memory(char *fname, int lineno, int pool)
75 {
76    struct abufhead *buf;
77
78    sm_check(fname, lineno, True);
79    if (pool > PM_MAX) {
80       Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
81    }
82    P(mutex);
83    if (pool_ctl[pool].free_buf) {
84       buf = pool_ctl[pool].free_buf;
85       pool_ctl[pool].free_buf = buf->next;
86       pool_ctl[pool].in_use++;
87       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
88          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
89       }
90       V(mutex);
91       Dmsg3(150, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
92       sm_new_owner(fname, lineno, (char *)buf);
93       return (void *)((char *)buf+HEAD_SIZE);
94    }
95       
96    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
97       V(mutex);
98       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
99    }
100    buf->ablen = pool_ctl[pool].size;
101    buf->pool = pool;
102    pool_ctl[pool].in_use++;
103    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
104       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
105    }
106    V(mutex);
107    Dmsg3(150, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
108    return (void *)((char *)buf+HEAD_SIZE);
109 }
110
111 /* Get nonpool memory of size requested */
112 void *sm_get_memory(char *fname, int lineno, size_t size)
113 {
114    struct abufhead *buf;
115    int pool = 0;
116
117    sm_check(fname, lineno, True);
118    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
119       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
120    }
121    buf->ablen = size;
122    buf->pool = pool;
123    buf->next = NULL;
124    pool_ctl[pool].in_use++;
125    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
126       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
127    return (void *)(((char *)buf)+HEAD_SIZE);
128 }
129
130 #else
131
132 void *get_pool_memory(int pool)
133 {
134    struct abufhead *buf;
135
136    P(mutex);
137    if (pool_ctl[pool].free_buf) {
138       buf = pool_ctl[pool].free_buf;
139       pool_ctl[pool].free_buf = buf->next;
140       V(mutex);
141       return (void *)((char *)buf+HEAD_SIZE);
142    }
143       
144    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
145       V(mutex);
146       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
147    }
148    buf->ablen = pool_ctl[pool].size;
149    buf->pool = pool;
150    buf->next = NULL;
151    pool_ctl[pool].in_use++;
152    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
153       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
154    }
155    V(mutex);
156    return (void *)(((char *)buf)+HEAD_SIZE);
157 }
158
159 /* Get nonpool memory of size requested */
160 void *get_memory(size_t size)
161 {
162    struct abufhead *buf;
163    int pool = 0;
164
165    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
166       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
167    }
168    buf->ablen = size;
169    buf->pool = pool;
170    buf->next = NULL;
171    pool_ctl[pool].in_use++;
172    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
173       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
174    }
175    return (void *)(((char *)buf)+HEAD_SIZE);
176 }
177 #endif /* SMARTALLOC */
178
179
180
181 /* Free a memory buffer */
182 void free_pool_memory(void *obuf)
183 {
184    struct abufhead *buf;
185    int pool;
186
187    sm_check(__FILE__, __LINE__, False);
188    ASSERT(obuf);
189    P(mutex);
190    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
191    pool = buf->pool;
192    pool_ctl[pool].in_use--;
193    if (pool == 0) {
194       free((char *)buf);              /* free nonpooled memory */
195    } else {                           /* otherwise link it to the free pool chain */
196       buf->next = pool_ctl[pool].free_buf;
197       pool_ctl[pool].free_buf = buf;
198    }
199    Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
200    V(mutex);
201 }
202
203
204 /* Return the size of a memory buffer */
205 size_t sizeof_pool_memory(void *obuf)
206 {
207    char *cp = (char *)obuf;
208
209    sm_check(__FILE__, __LINE__, False);
210    ASSERT(obuf);
211    cp -= HEAD_SIZE;
212    return ((struct abufhead *)cp)->ablen;
213 }
214
215 /* Realloc pool memory buffer */
216 void *realloc_pool_memory(void *obuf, size_t size)
217 {
218    char *cp = (char *)obuf;
219    void *buf;
220    int pool;
221
222    sm_check(__FILE__, __LINE__, False);
223    ASSERT(obuf);
224    P(mutex);
225    cp -= HEAD_SIZE;
226    buf = realloc(cp, size+HEAD_SIZE);
227    if (buf == NULL) {
228       V(mutex);
229       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
230    }
231    ((struct abufhead *)buf)->ablen = size;
232    pool = ((struct abufhead *)buf)->pool;
233    if (size > pool_ctl[pool].max_size) {
234       pool_ctl[pool].max_size = size;
235    }
236    V(mutex);
237    sm_check(__FILE__, __LINE__, False);
238    return (void *)(((char *)buf)+HEAD_SIZE);
239 }
240
241 void *check_pool_memory_size(void *obuf, size_t size)
242 {
243    sm_check(__FILE__, __LINE__, False);
244    ASSERT(obuf);
245    if (size <= sizeof_pool_memory(obuf)) {
246       return obuf;
247    }
248    return realloc_pool_memory(obuf, size);
249 }
250
251 /* Release all pooled memory */
252 void close_memory_pool()
253 {
254    struct abufhead *buf, *next;
255    int i;
256
257    sm_check(__FILE__, __LINE__, False);
258    P(mutex);
259    for (i=1; i<=PM_MAX; i++) {
260       buf = pool_ctl[i].free_buf;
261       while (buf) {
262          next = buf->next;
263          free((char *)buf);
264          buf = next;
265       }
266    }
267    V(mutex);
268 }
269
270 #ifdef DEBUG
271
272 static char *pool_name(int pool)
273 {
274    static char *name[] = {"NoPool", "FNAME ", "MSG   ", "EMSG  "};
275    static char buf[30];
276
277    if (pool >= 0 && pool <= PM_MAX) {
278       return name[pool];
279    }
280    sprintf(buf, "%-6d", pool);
281    return buf;
282 }
283    
284 /* Print staticstics on memory pool usage   
285  */ 
286 void print_memory_pool_stats()
287 {
288    int i;
289
290    Dmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
291    for (i=0; i<=PM_MAX; i++)
292       Dmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_size,
293          pool_ctl[i].max_used, pool_ctl[i].in_use);
294
295    Dmsg0(-1, "\n");
296 }
297
298 #else
299 void print_memory_pool_stats() {} 
300 #endif /* DEBUG */