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