]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
f5c2b5f11e17ae5dae7c3f0d7897474d1ed51856
[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-2004 Kern Sibbald
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    int32_t size;                      /* default size */
47    int32_t max_allocated;             /* max allocated */
48    int32_t max_used;                  /* max buffers used */
49    int32_t in_use;                    /* number in use */
50    struct abufhead *free_buf;         /* pointer to free buffers */
51 };
52
53 /* Bacula Name length plus extra */
54 #define NLEN (MAX_NAME_LENGTH+2)
55
56 /* #define STRESS_TEST_POOL */
57 #ifndef STRESS_TEST_POOL
58 /*
59  * Define default Pool buffer sizes
60  */
61 static struct s_pool_ctl pool_ctl[] = {
62    {  256,  256, 0, 0, NULL },        /* PM_NOPOOL no pooling */
63    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
64    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
65    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
66    { 1024, 1024, 0, 0, NULL }         /* PM_EMSG error message buffer */
67 };
68 #else
69
70 /* This is used ONLY when stress testing the code */
71 static struct s_pool_ctl pool_ctl[] = {
72    {   20,   20, 0, 0, NULL },        /* PM_NOPOOL no pooling */
73    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
74    {   20,   20, 0, 0, NULL },        /* PM_FNAME filename buffers */
75    {   20,   20, 0, 0, NULL },        /* PM_MESSAGE message buffer */
76    {   20,   20, 0, 0, NULL }         /* PM_EMSG error message buffer */
77 };
78 #endif
79
80
81 /*  Memory allocation control structures and storage.  */
82 struct abufhead {
83    int32_t ablen;                     /* Buffer length in bytes */
84    int32_t pool;                      /* pool */
85    struct abufhead *next;             /* pointer to next free buffer */
86 };
87
88 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
89
90
91 #ifdef SMARTALLOC
92
93 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
94
95 POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
96 {
97    struct abufhead *buf;
98
99    if (pool > PM_MAX) {
100       Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
101    }
102    P(mutex);
103    if (pool_ctl[pool].free_buf) {
104       buf = pool_ctl[pool].free_buf;
105       pool_ctl[pool].free_buf = buf->next;
106       pool_ctl[pool].in_use++;
107       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
108          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
109       }
110       V(mutex);
111       Dmsg3(1800, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
112       sm_new_owner(fname, lineno, (char *)buf);
113       return (POOLMEM *)((char *)buf+HEAD_SIZE);
114    }
115
116    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
117       V(mutex);
118       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
119    }
120    buf->ablen = pool_ctl[pool].size;
121    buf->pool = pool;
122    pool_ctl[pool].in_use++;
123    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
124       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
125    }
126    V(mutex);
127    Dmsg3(1800, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
128    return (POOLMEM *)((char *)buf+HEAD_SIZE);
129 }
130
131 /* Get nonpool memory of size requested */
132 POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size)
133 {
134    struct abufhead *buf;
135    int pool = 0;
136
137    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
138       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
139    }
140    buf->ablen = size;
141    buf->pool = pool;
142    buf->next = NULL;
143    pool_ctl[pool].in_use++;
144    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
145       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
146    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
147 }
148
149
150 /* Return the size of a memory buffer */
151 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
152 {
153    char *cp = (char *)obuf;
154
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(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
162 {
163    char *cp = (char *)obuf;
164    void *buf;
165    int pool;
166
167    ASSERT(obuf);
168    P(mutex);
169    cp -= HEAD_SIZE;
170    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
171    if (buf == NULL) {
172       V(mutex);
173       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
174    }
175    ((struct abufhead *)buf)->ablen = size;
176    pool = ((struct abufhead *)buf)->pool;
177    if (size > pool_ctl[pool].max_allocated) {
178       pool_ctl[pool].max_allocated = size;
179    }
180    V(mutex);
181    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
182 }
183
184 POOLMEM *sm_check_pool_memory_size(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
185 {
186    ASSERT(obuf);
187    if (size <= sizeof_pool_memory(obuf)) {
188       return obuf;
189    }
190    return realloc_pool_memory(obuf, size);
191 }
192
193 /* Free a memory buffer */
194 void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
195 {
196    struct abufhead *buf;
197    int pool;
198
199    ASSERT(obuf);
200    P(mutex);
201    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
202    pool = buf->pool;
203    pool_ctl[pool].in_use--;
204    if (pool == 0) {
205       free((char *)buf);              /* free nonpooled memory */
206    } else {                           /* otherwise link it to the free pool chain */
207 #ifdef DEBUG
208       struct abufhead *next;
209       /* Don't let him free the same buffer twice */
210       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
211          if (next == buf) {
212             Dmsg4(1800, "bad free_pool_memory %x pool=%d from %s:%d\n", buf, pool, fname, lineno);
213             V(mutex);                 /* unblock the pool */
214             ASSERT(next != buf);      /* attempt to free twice */
215          }
216       }
217 #endif
218       buf->next = pool_ctl[pool].free_buf;
219       pool_ctl[pool].free_buf = buf;
220    }
221    Dmsg4(1800, "free_pool_memory %x pool=%d from %s:%d\n", buf, pool, fname, lineno);
222    V(mutex);
223 }
224
225
226 #else
227
228 /* =========  NO SMARTALLOC  =========================================  */
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(int32_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 int32_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
288
289 /* Realloc pool memory buffer */
290 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
291 {
292    char *cp = (char *)obuf;
293    void *buf;
294    int pool;
295
296    ASSERT(obuf);
297    P(mutex);
298    cp -= HEAD_SIZE;
299    buf = realloc(cp, size+HEAD_SIZE);
300    if (buf == NULL) {
301       V(mutex);
302       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
303    }
304    ((struct abufhead *)buf)->ablen = size;
305    pool = ((struct abufhead *)buf)->pool;
306    if (size > pool_ctl[pool].max_allocated) {
307       pool_ctl[pool].max_allocated = size;
308    }
309    V(mutex);
310    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
311 }
312
313
314 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
315 {
316    ASSERT(obuf);
317    if (size <= sizeof_pool_memory(obuf)) {
318       return obuf;
319    }
320    return realloc_pool_memory(obuf, size);
321 }
322
323 /* Free a memory buffer */
324 void free_pool_memory(POOLMEM *obuf)
325 {
326    struct abufhead *buf;
327    int pool;
328
329    ASSERT(obuf);
330    P(mutex);
331    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
332    pool = buf->pool;
333    pool_ctl[pool].in_use--;
334    if (pool == 0) {
335       free((char *)buf);              /* free nonpooled memory */
336    } else {                           /* otherwise link it to the free pool chain */
337 #ifdef DEBUG
338       struct abufhead *next;
339       /* Don't let him free the same buffer twice */
340       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
341          if (next == buf) {
342             V(mutex);
343             ASSERT(next != buf);  /* attempt to free twice */
344          }
345       }
346 #endif
347       buf->next = pool_ctl[pool].free_buf;
348       pool_ctl[pool].free_buf = buf;
349    }
350    Dmsg2(1800, "free_pool_memory %x pool=%d\n", buf, pool);
351    V(mutex);
352 }
353
354 #endif /* SMARTALLOC */
355
356
357
358
359
360
361 /* Release all pooled memory */
362 void close_memory_pool()
363 {
364    struct abufhead *buf, *next;
365
366    sm_check(__FILE__, __LINE__, false);
367    P(mutex);
368    for (int i=1; i<=PM_MAX; i++) {
369       buf = pool_ctl[i].free_buf;
370       while (buf) {
371          next = buf->next;
372          free((char *)buf);
373          buf = next;
374       }
375       pool_ctl[i].free_buf = NULL;
376    }
377    V(mutex);
378 }
379
380 #ifdef DEBUG
381
382 static const char *pool_name(int pool)
383 {
384    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
385    static char buf[30];
386
387    if (pool >= 0 && pool <= PM_MAX) {
388       return name[pool];
389    }
390    sprintf(buf, "%-6d", pool);
391    return buf;
392 }
393
394 /* Print staticstics on memory pool usage
395  */
396 void print_memory_pool_stats()
397 {
398    Pmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
399    for (int i=0; i<=PM_MAX; i++)
400       Pmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_allocated,
401          pool_ctl[i].max_used, pool_ctl[i].in_use);
402
403    Pmsg0(-1, "\n");
404 }
405
406 #else
407 void print_memory_pool_stats() {}
408 #endif /* DEBUG */
409
410
411 /*
412  * Concatenate a string (str) onto a pool memory buffer pm
413  *   Returns: length of concatenated string
414  */
415 int pm_strcat(POOLMEM **pm, const char *str)
416 {
417    int pmlen = strlen(*pm);
418    int len = strlen(str) + 1;
419
420    *pm = check_pool_memory_size(*pm, pmlen + len);
421    memcpy(*pm+pmlen, str, len);
422    return pmlen + len - 1;
423 }
424
425 int pm_strcat(POOLMEM *&pm, const char *str)
426 {
427    int pmlen = strlen(pm);
428    int len = strlen(str) + 1;
429
430    pm = check_pool_memory_size(pm, pmlen + len);
431    memcpy(pm+pmlen, str, len);
432    return pmlen + len - 1;
433 }
434
435
436 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
437 {
438    int pmlen = strlen(pm);
439    int len = strlen(str.c_str()) + 1;
440
441    pm = check_pool_memory_size(pm, pmlen + len);
442    memcpy(pm+pmlen, str.c_str(), len);
443    return pmlen + len - 1;
444 }
445
446 int pm_strcat(POOL_MEM &pm, const char *str)
447 {
448    int pmlen = strlen(pm.c_str());
449    int len = strlen(str) + 1;
450
451    pm.check_size(pmlen + len);
452    memcpy(pm.c_str()+pmlen, str, len);
453    return pmlen + len - 1;
454 }
455
456
457 /*
458  * Copy a string (str) into a pool memory buffer pm
459  *   Returns: length of string copied
460  */
461 int pm_strcpy(POOLMEM **pm, const char *str)
462 {
463    int len = strlen(str) + 1;
464
465    *pm = check_pool_memory_size(*pm, len);
466    memcpy(*pm, str, len);
467    return len - 1;
468 }
469
470 int pm_strcpy(POOLMEM *&pm, const char *str)
471 {
472    int len = strlen(str) + 1;
473
474    pm = check_pool_memory_size(pm, len);
475    memcpy(pm, str, len);
476    return len - 1;
477 }
478
479 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
480 {
481    int len = strlen(str.c_str()) + 1;
482
483    pm = check_pool_memory_size(pm, len);
484    memcpy(pm, str.c_str(), len);
485    return len - 1;
486 }
487
488
489 int pm_strcpy(POOL_MEM &pm, const char *str)
490 {
491    int len = strlen(str) + 1;
492    pm.check_size(len);
493    memcpy(pm.c_str(), str, len);
494    return len - 1;
495 }
496
497 /* ==============  CLASS POOL_MEM   ============== */
498
499 /* Return the size of a memory buffer */
500 int32_t POOL_MEM::max_size()
501 {
502    int32_t size;
503    char *cp = mem;
504    cp -= HEAD_SIZE;
505    size = ((struct abufhead *)cp)->ablen;
506    Dmsg1(000, "max_size=%d\n", size);
507    return size;
508 }
509
510 void POOL_MEM::realloc_pm(int32_t size)
511 {
512    char *cp = mem;
513    char *buf;
514    int pool;
515
516    P(mutex);
517    cp -= HEAD_SIZE;
518    buf = (char *)realloc(cp, size+HEAD_SIZE);
519    if (buf == NULL) {
520       V(mutex);
521       Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
522    }
523    Dmsg2(000, "Old buf=0x%x new buf=0x%x\n", cp, buf);
524    ((struct abufhead *)buf)->ablen = size;
525    pool = ((struct abufhead *)buf)->pool;
526    if (size > pool_ctl[pool].max_allocated) {
527       pool_ctl[pool].max_allocated = size;
528    }
529    mem = buf+HEAD_SIZE;
530    V(mutex);
531    Dmsg3(000, "Old buf=0x%x new buf=0x%x mem=0x%x\n", cp, buf, mem);
532 }
533
534 int POOL_MEM::strcat(const char *str)
535 {
536    int pmlen = strlen(mem);
537    int len = strlen(str) + 1;
538
539    check_size(pmlen + len);
540    memcpy(mem+pmlen, str, len);
541    return pmlen + len - 1;
542 }
543
544
545 int POOL_MEM::strcpy(const char *str)
546 {
547    int len = strlen(str) + 1;
548    check_size(len);
549    memcpy(mem, str, len);
550    return len - 1;
551 }