]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
Misc -- see kes-1.30
[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  *   Version $Id$
21  */
22
23 /*
24    Copyright (C) 2000-2003 Kern Sibbald and John Walker
25
26    This program is free software; you can redistribute it and/or
27    modify it under the terms of the GNU General Public License as
28    published by the Free Software Foundation; either version 2 of
29    the License, or (at your option) any later version.
30
31    This program is distributed in the hope that it will be useful,
32    but WITHOUT ANY WARRANTY; without even the implied warranty of
33    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
34    General Public License for more details.
35
36    You should have received a copy of the GNU General Public
37    License along with this program; if not, write to the Free
38    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
39    MA 02111-1307, USA.
40
41  */
42
43 #include "bacula.h"
44
45 struct s_pool_ctl {
46    size_t size;                       /* default size */
47    size_t max_size;                   /* max allocated */
48    size_t max_used;                   /* max buffers used */
49    size_t in_use;                     /* number in use */
50    struct abufhead *free_buf;         /* pointer to free buffers */
51 };
52
53 /* #define STRESS_TEST_POOL */
54 #ifndef STRESS_TEST_POOL
55 /*
56  * Define default Pool buffer sizes
57  */
58 static struct s_pool_ctl pool_ctl[] = {
59    {  256,  256, 0, 0, NULL },        /* PM_NOPOOL no pooling */
60    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
61    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
62    { 1024, 1024, 0, 0, NULL }         /* PM_EMSG error message buffer */
63 };
64 #else
65
66 /* This is used ONLY when stress testing the code */
67 static struct s_pool_ctl pool_ctl[] = {
68    {   20,   20, 0, 0, NULL },        /* PM_NOPOOL no pooling */
69    {   20,   20, 0, 0, NULL },        /* PM_FNAME filename buffers */
70    {   20,   20, 0, 0, NULL },        /* PM_MESSAGE message buffer */
71    {   20,   20, 0, 0, NULL }         /* PM_EMSG error message buffer */
72 };
73 #endif
74
75
76 /*  Memory allocation control structures and storage.  */
77 struct abufhead {
78    size_t ablen;                      /* Buffer length in bytes */
79    int32_t pool;                      /* pool */
80    struct abufhead *next;             /* pointer to next free buffer */
81 };
82
83 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
84
85
86 #ifdef SMARTALLOC
87
88 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
89
90 POOLMEM *sm_get_pool_memory(char *fname, int lineno, int pool)
91 {
92    struct abufhead *buf;
93
94    if (pool > PM_MAX) {
95       Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
96    }
97    P(mutex);
98    if (pool_ctl[pool].free_buf) {
99       buf = pool_ctl[pool].free_buf;
100       pool_ctl[pool].free_buf = buf->next;
101       pool_ctl[pool].in_use++;
102       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
103          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
104       }
105       V(mutex);
106       Dmsg3(150, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
107       sm_new_owner(fname, lineno, (char *)buf);
108       return (POOLMEM *)((char *)buf+HEAD_SIZE);
109    }
110       
111    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
112       V(mutex);
113       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
114    }
115    buf->ablen = pool_ctl[pool].size;
116    buf->pool = pool;
117    pool_ctl[pool].in_use++;
118    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
119       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
120    }
121    V(mutex);
122    Dmsg3(150, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
123    return (POOLMEM *)((char *)buf+HEAD_SIZE);
124 }
125
126 /* Get nonpool memory of size requested */
127 POOLMEM *sm_get_memory(char *fname, int lineno, size_t size)
128 {
129    struct abufhead *buf;
130    int pool = 0;
131
132    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
133       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
134    }
135    buf->ablen = size;
136    buf->pool = pool;
137    buf->next = NULL;
138    pool_ctl[pool].in_use++;
139    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
140       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
141    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
142 }
143
144
145 /* Return the size of a memory buffer */
146 size_t sm_sizeof_pool_memory(char *fname, int lineno, POOLMEM *obuf)
147 {
148    char *cp = (char *)obuf;
149
150    ASSERT(obuf);
151    cp -= HEAD_SIZE;
152    return ((struct abufhead *)cp)->ablen;
153 }
154
155 /* Realloc pool memory buffer */
156 POOLMEM *sm_realloc_pool_memory(char *fname, int lineno, POOLMEM *obuf, size_t size)
157 {
158    char *cp = (char *)obuf;
159    void *buf;
160    int pool;
161
162    ASSERT(obuf);
163    P(mutex);
164    cp -= HEAD_SIZE;
165    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
166    if (buf == NULL) {
167       V(mutex);
168       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
169    }
170    ((struct abufhead *)buf)->ablen = size;
171    pool = ((struct abufhead *)buf)->pool;
172    if (size > pool_ctl[pool].max_size) {
173       pool_ctl[pool].max_size = size;
174    }
175    V(mutex);
176    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
177 }
178
179 POOLMEM *sm_check_pool_memory_size(char *fname, int lineno, POOLMEM *obuf, size_t size)
180 {
181    ASSERT(obuf);
182    if (size <= sizeof_pool_memory(obuf)) {
183       return obuf;
184    }
185    return realloc_pool_memory(obuf, size);
186 }
187
188 /* Free a memory buffer */
189 void sm_free_pool_memory(char *fname, int lineno, POOLMEM *obuf)
190 {
191    struct abufhead *buf;
192    int pool;
193
194    ASSERT(obuf);
195    P(mutex);
196    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
197    pool = buf->pool;
198    pool_ctl[pool].in_use--;
199    if (pool == 0) {
200       free((char *)buf);              /* free nonpooled memory */
201    } else {                           /* otherwise link it to the free pool chain */
202 #ifdef DEBUG
203       struct abufhead *next;
204       /* Don't let him free the same buffer twice */
205       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
206          ASSERT(next != buf);  /* attempt to free twice */
207       }
208 #endif
209       buf->next = pool_ctl[pool].free_buf;
210       pool_ctl[pool].free_buf = buf;
211    }
212    Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
213    V(mutex);
214 }
215
216
217 #else
218
219 /* ===================================================================  */
220
221 POOLMEM *get_pool_memory(int pool)
222 {
223    struct abufhead *buf;
224
225    P(mutex);
226    if (pool_ctl[pool].free_buf) {
227       buf = pool_ctl[pool].free_buf;
228       pool_ctl[pool].free_buf = buf->next;
229       V(mutex);
230       return (POOLMEM *)((char *)buf+HEAD_SIZE);
231    }
232       
233    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
234       V(mutex);
235       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
236    }
237    buf->ablen = pool_ctl[pool].size;
238    buf->pool = pool;
239    buf->next = NULL;
240    pool_ctl[pool].in_use++;
241    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
242       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
243    }
244    V(mutex);
245    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
246 }
247
248 /* Get nonpool memory of size requested */
249 POOLMEM *get_memory(size_t size)
250 {
251    struct abufhead *buf;
252    int pool = 0;
253
254    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
255       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
256    }
257    buf->ablen = size;
258    buf->pool = pool;
259    buf->next = NULL;
260    pool_ctl[pool].in_use++;
261    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
262       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
263    }
264    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
265 }
266
267
268 /* Return the size of a memory buffer */
269 size_t sizeof_pool_memory(POOLMEM *obuf)
270 {
271    char *cp = (char *)obuf;
272
273    ASSERT(obuf);
274    cp -= HEAD_SIZE;
275    return ((struct abufhead *)cp)->ablen;
276 }
277
278 /* Realloc pool memory buffer */
279 POOLMEM *realloc_pool_memory(POOLMEM *obuf, size_t size)
280 {
281    char *cp = (char *)obuf;
282    void *buf;
283    int pool;
284
285    ASSERT(obuf);
286    P(mutex);
287    cp -= HEAD_SIZE;
288    buf = realloc(cp, size+HEAD_SIZE);
289    if (buf == NULL) {
290       V(mutex);
291       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
292    }
293    ((struct abufhead *)buf)->ablen = size;
294    pool = ((struct abufhead *)buf)->pool;
295    if (size > pool_ctl[pool].max_size) {
296       pool_ctl[pool].max_size = size;
297    }
298    V(mutex);
299    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
300 }
301
302 POOLMEM *check_pool_memory_size(POOLMEM *obuf, size_t size)
303 {
304    ASSERT(obuf);
305    if (size <= sizeof_pool_memory(obuf)) {
306       return obuf;
307    }
308    return realloc_pool_memory(obuf, size);
309 }
310
311 /* Free a memory buffer */
312 void free_pool_memory(POOLMEM *obuf)
313 {
314    struct abufhead *buf;
315    int pool;
316
317    ASSERT(obuf);
318    P(mutex);
319    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
320    pool = buf->pool;
321    pool_ctl[pool].in_use--;
322    if (pool == 0) {
323       free((char *)buf);              /* free nonpooled memory */
324    } else {                           /* otherwise link it to the free pool chain */
325 #ifdef DEBUG
326       struct abufhead *next;
327       /* Don't let him free the same buffer twice */
328       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
329          ASSERT(next != buf);  /* attempt to free twice */
330       }
331 #endif
332       buf->next = pool_ctl[pool].free_buf;
333       pool_ctl[pool].free_buf = buf;
334    }
335    Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
336    V(mutex);
337 }
338
339 #endif /* SMARTALLOC */
340
341
342
343
344
345
346 /* Release all pooled memory */
347 void close_memory_pool()
348 {
349    struct abufhead *buf, *next;
350    int i;
351
352    sm_check(__FILE__, __LINE__, False);
353    P(mutex);
354    for (i=1; i<=PM_MAX; i++) {
355       buf = pool_ctl[i].free_buf;
356       while (buf) {
357          next = buf->next;
358          free((char *)buf);
359          buf = next;
360       }
361       pool_ctl[i].free_buf = NULL;
362    }
363    V(mutex);
364 }
365
366 #ifdef DEBUG
367
368 static char *pool_name(int pool)
369 {
370    static char *name[] = {"NoPool", "FNAME ", "MSG   ", "EMSG  "};
371    static char buf[30];
372
373    if (pool >= 0 && pool <= PM_MAX) {
374       return name[pool];
375    }
376    sprintf(buf, "%-6d", pool);
377    return buf;
378 }
379    
380 /* Print staticstics on memory pool usage   
381  */ 
382 void print_memory_pool_stats()
383 {
384    int i;
385
386    Dmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
387    for (i=0; i<=PM_MAX; i++)
388       Dmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_size,
389          pool_ctl[i].max_used, pool_ctl[i].in_use);
390
391    Dmsg0(-1, "\n");
392 }
393
394 #else
395 void print_memory_pool_stats() {} 
396 #endif /* DEBUG */