]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
mtx-changer update, message fixes
[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 extern POOLMEM *sm_malloc(char *fname, int lineno, int nbytes);
91
92 POOLMEM *sm_get_pool_memory(char *fname, int lineno, int pool)
93 {
94    struct abufhead *buf;
95
96    sm_check(fname, lineno, True);
97    if (pool > PM_MAX) {
98       Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
99    }
100    P(mutex);
101    if (pool_ctl[pool].free_buf) {
102       buf = pool_ctl[pool].free_buf;
103       pool_ctl[pool].free_buf = buf->next;
104       pool_ctl[pool].in_use++;
105       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
106          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
107       }
108       V(mutex);
109       Dmsg3(150, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
110       sm_new_owner(fname, lineno, (char *)buf);
111       return (POOLMEM *)((char *)buf+HEAD_SIZE);
112    }
113       
114    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
115       V(mutex);
116       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
117    }
118    buf->ablen = pool_ctl[pool].size;
119    buf->pool = pool;
120    pool_ctl[pool].in_use++;
121    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
122       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
123    }
124    V(mutex);
125    Dmsg3(150, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
126    return (POOLMEM *)((char *)buf+HEAD_SIZE);
127 }
128
129 /* Get nonpool memory of size requested */
130 POOLMEM *sm_get_memory(char *fname, int lineno, size_t size)
131 {
132    struct abufhead *buf;
133    int pool = 0;
134
135    sm_check(fname, lineno, True);
136    if ((buf = (struct abufhead *) sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
137       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
138    }
139    buf->ablen = size;
140    buf->pool = pool;
141    buf->next = NULL;
142    pool_ctl[pool].in_use++;
143    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
144       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
145    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
146 }
147
148
149 /* Return the size of a memory buffer */
150 size_t sm_sizeof_pool_memory(char *fname, int lineno, POOLMEM *obuf)
151 {
152    char *cp = (char *)obuf;
153
154    sm_check(fname, lineno, False);
155    ASSERT(obuf);
156    cp -= HEAD_SIZE;
157    return ((struct abufhead *)cp)->ablen;
158 }
159
160 /* Realloc pool memory buffer */
161 POOLMEM *sm_realloc_pool_memory(char *fname, int lineno, POOLMEM *obuf, size_t size)
162 {
163    char *cp = (char *)obuf;
164    void *buf;
165    int pool;
166
167    sm_check(fname, lineno, False);
168    ASSERT(obuf);
169    P(mutex);
170    cp -= HEAD_SIZE;
171    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
172    sm_check(fname, lineno, True);
173    if (buf == NULL) {
174       V(mutex);
175       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
176    }
177    ((struct abufhead *)buf)->ablen = size;
178    pool = ((struct abufhead *)buf)->pool;
179    if (size > pool_ctl[pool].max_size) {
180       pool_ctl[pool].max_size = size;
181    }
182    V(mutex);
183    sm_check(fname, lineno, False);
184    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
185 }
186
187 POOLMEM *sm_check_pool_memory_size(char *fname, int lineno, POOLMEM *obuf, size_t size)
188 {
189    sm_check(fname, lineno, False);
190    ASSERT(obuf);
191    if (size <= sizeof_pool_memory(obuf)) {
192       return obuf;
193    }
194    return realloc_pool_memory(obuf, size);
195 }
196
197 /* Free a memory buffer */
198 void sm_free_pool_memory(char *fname, int lineno, POOLMEM *obuf)
199 {
200    struct abufhead *buf;
201    int pool;
202
203    sm_check(fname, lineno, True);
204    ASSERT(obuf);
205    P(mutex);
206    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
207    pool = buf->pool;
208    pool_ctl[pool].in_use--;
209    if (pool == 0) {
210       free((char *)buf);              /* free nonpooled memory */
211    } else {                           /* otherwise link it to the free pool chain */
212 #ifdef DEBUG
213       struct abufhead *next;
214       /* Don't let him free the same buffer twice */
215       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
216          ASSERT(next != buf);  /* attempt to free twice */
217       }
218 #endif
219       buf->next = pool_ctl[pool].free_buf;
220       pool_ctl[pool].free_buf = buf;
221    }
222    Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
223    V(mutex);
224 }
225
226
227 #else
228
229 /* ===================================================================  */
230
231 POOLMEM *get_pool_memory(int pool)
232 {
233    struct abufhead *buf;
234
235    P(mutex);
236    if (pool_ctl[pool].free_buf) {
237       buf = pool_ctl[pool].free_buf;
238       pool_ctl[pool].free_buf = buf->next;
239       V(mutex);
240       return (POOLMEM *)((char *)buf+HEAD_SIZE);
241    }
242       
243    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
244       V(mutex);
245       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
246    }
247    buf->ablen = pool_ctl[pool].size;
248    buf->pool = pool;
249    buf->next = NULL;
250    pool_ctl[pool].in_use++;
251    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
252       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
253    }
254    V(mutex);
255    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
256 }
257
258 /* Get nonpool memory of size requested */
259 POOLMEM *get_memory(size_t size)
260 {
261    struct abufhead *buf;
262    int pool = 0;
263
264    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
265       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
266    }
267    buf->ablen = size;
268    buf->pool = pool;
269    buf->next = NULL;
270    pool_ctl[pool].in_use++;
271    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
272       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
273    }
274    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
275 }
276
277
278 /* Return the size of a memory buffer */
279 size_t sizeof_pool_memory(POOLMEM *obuf)
280 {
281    char *cp = (char *)obuf;
282
283    ASSERT(obuf);
284    cp -= HEAD_SIZE;
285    return ((struct abufhead *)cp)->ablen;
286 }
287
288 /* Realloc pool memory buffer */
289 POOLMEM *realloc_pool_memory(POOLMEM *obuf, size_t size)
290 {
291    char *cp = (char *)obuf;
292    void *buf;
293    int pool;
294
295    ASSERT(obuf);
296    P(mutex);
297    cp -= HEAD_SIZE;
298    buf = realloc(cp, size+HEAD_SIZE);
299    if (buf == NULL) {
300       V(mutex);
301       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
302    }
303    ((struct abufhead *)buf)->ablen = size;
304    pool = ((struct abufhead *)buf)->pool;
305    if (size > pool_ctl[pool].max_size) {
306       pool_ctl[pool].max_size = size;
307    }
308    V(mutex);
309    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
310 }
311
312 POOLMEM *check_pool_memory_size(POOLMEM *obuf, size_t size)
313 {
314    ASSERT(obuf);
315    if (size <= sizeof_pool_memory(obuf)) {
316       return obuf;
317    }
318    return realloc_pool_memory(obuf, size);
319 }
320
321 /* Free a memory buffer */
322 void free_pool_memory(POOLMEM *obuf)
323 {
324    struct abufhead *buf;
325    int pool;
326
327    sm_check(__FILE__, __LINE__, False);
328    ASSERT(obuf);
329    P(mutex);
330    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
331    pool = buf->pool;
332    pool_ctl[pool].in_use--;
333    if (pool == 0) {
334       free((char *)buf);              /* free nonpooled memory */
335    } else {                           /* otherwise link it to the free pool chain */
336 #ifdef DEBUG
337       struct abufhead *next;
338       /* Don't let him free the same buffer twice */
339       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
340          ASSERT(next != buf);  /* attempt to free twice */
341       }
342 #endif
343       buf->next = pool_ctl[pool].free_buf;
344       pool_ctl[pool].free_buf = buf;
345    }
346    Dmsg2(150, "free_pool_memory %x pool=%d\n", buf, pool);
347    V(mutex);
348 }
349
350 #endif /* SMARTALLOC */
351
352
353
354
355
356
357 /* Release all pooled memory */
358 void close_memory_pool()
359 {
360    struct abufhead *buf, *next;
361    int i;
362
363    sm_check(__FILE__, __LINE__, False);
364    P(mutex);
365    for (i=1; i<=PM_MAX; i++) {
366       buf = pool_ctl[i].free_buf;
367       while (buf) {
368          next = buf->next;
369          free((char *)buf);
370          buf = next;
371       }
372       pool_ctl[i].free_buf = NULL;
373    }
374    V(mutex);
375 }
376
377 #ifdef DEBUG
378
379 static char *pool_name(int pool)
380 {
381    static char *name[] = {"NoPool", "FNAME ", "MSG   ", "EMSG  "};
382    static char buf[30];
383
384    if (pool >= 0 && pool <= PM_MAX) {
385       return name[pool];
386    }
387    sprintf(buf, "%-6d", pool);
388    return buf;
389 }
390    
391 /* Print staticstics on memory pool usage   
392  */ 
393 void print_memory_pool_stats()
394 {
395    int i;
396
397    Dmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
398    for (i=0; i<=PM_MAX; i++)
399       Dmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_size,
400          pool_ctl[i].max_used, pool_ctl[i].in_use);
401
402    Dmsg0(-1, "\n");
403 }
404
405 #else
406 void print_memory_pool_stats() {} 
407 #endif /* DEBUG */