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