]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
Fix compilation with gcc 4.6.1
[bacula/bacula] / bacula / src / lib / mem_pool.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *  Bacula memory pool routines.
30  *
31  *  The idea behind these routines is that there will be
32  *  pools of memory that are pre-allocated for quick
33  *  access. The pools will have a fixed memory size on allocation
34  *  but if need be, the size can be increased. This is
35  *  particularly useful for filename
36  *  buffers where 256 bytes should be sufficient in 99.99%
37  *  of the cases, but when it isn't we want to be able to
38  *  increase the size.
39  *
40  *  A major advantage of the pool memory aside from the speed
41  *  is that the buffer carrys around its size, so to ensure that
42  *  there is enough memory, simply call the check_pool_memory_size()
43  *  with the desired size and it will adjust only if necessary.
44  *
45  *           Kern E. Sibbald
46  *
47  */
48
49 #include "bacula.h"
50
51 #ifdef HAVE_MALLOC_TRIM
52 extern "C" int malloc_trim (size_t pad);
53 #endif
54
55 struct s_pool_ctl {
56    int32_t size;                      /* default size */
57    int32_t max_allocated;             /* max allocated */
58    int32_t max_used;                  /* max buffers used */
59    int32_t in_use;                    /* number in use */
60    struct abufhead *free_buf;         /* pointer to free buffers */
61 };
62
63 /* Bacula Name length plus extra */
64 #define NLEN (MAX_NAME_LENGTH+2)
65
66 /* #define STRESS_TEST_POOL */
67 #ifndef STRESS_TEST_POOL
68 /*
69  * Define default Pool buffer sizes
70  */
71 static struct s_pool_ctl pool_ctl[] = {
72    {  256,  256, 0, 0, NULL },        /* PM_NOPOOL no pooling */
73    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
74    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
75    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
76    { 1024, 1024, 0, 0, NULL },        /* PM_EMSG error message buffer */
77   {  4096, 4096, 0, 0, NULL }         /* PM_BSOCK message buffer */
78 };
79 #else
80
81 /* This is used ONLY when stress testing the code */
82 static struct s_pool_ctl pool_ctl[] = {
83    {   20,   20, 0, 0, NULL },        /* PM_NOPOOL no pooling */
84    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
85    {   20,   20, 0, 0, NULL },        /* PM_FNAME filename buffers */
86    {   20,   20, 0, 0, NULL },        /* PM_MESSAGE message buffer */
87    {   20,   20, 0, 0, NULL },        /* PM_EMSG error message buffer */
88    {   20,   20, 0, 0, NULL }         /* PM_BSOCK message buffer */
89 };
90 #endif
91
92
93 /*  Memory allocation control structures and storage.  */
94 struct abufhead {
95    int32_t ablen;                     /* Buffer length in bytes */
96    int32_t pool;                      /* pool */
97    struct abufhead *next;             /* pointer to next free buffer */
98    int32_t bnet_size;                 /* dummy for bnet_send() */
99 };
100
101 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
102
103 #ifdef SMARTALLOC
104
105 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
106
107 POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
108 {
109    struct abufhead *buf;
110
111    if (pool > PM_MAX) {
112       Emsg2(M_ABORT, 0, _("MemPool index %d larger than max %d\n"), pool, PM_MAX);
113    }
114    P(mutex);
115    if (pool_ctl[pool].free_buf) {
116       buf = pool_ctl[pool].free_buf;
117       pool_ctl[pool].free_buf = buf->next;
118       pool_ctl[pool].in_use++;
119       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
120          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
121       }
122       V(mutex);
123       Dmsg3(1800, "sm_get_pool_memory reuse %p to %s:%d\n", buf, fname, lineno);
124       sm_new_owner(fname, lineno, (char *)buf);
125       return (POOLMEM *)((char *)buf+HEAD_SIZE);
126    }
127
128    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
129       V(mutex);
130       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
131    }
132    buf->ablen = pool_ctl[pool].size;
133    buf->pool = pool;
134    pool_ctl[pool].in_use++;
135    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
136       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
137    }
138    V(mutex);
139    Dmsg3(1800, "sm_get_pool_memory give %p to %s:%d\n", buf, fname, lineno);
140    return (POOLMEM *)((char *)buf+HEAD_SIZE);
141 }
142
143 /* Get nonpool memory of size requested */
144 POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size)
145 {
146    struct abufhead *buf;
147    int pool = 0;
148
149    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
150       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
151    }
152    buf->ablen = size;
153    buf->pool = pool;
154    buf->next = NULL;
155    pool_ctl[pool].in_use++;
156    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
157       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
158    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
159 }
160
161 /* Return the size of a memory buffer */
162 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
163 {
164    char *cp = (char *)obuf;
165
166    if (obuf == NULL) {
167       Emsg0(M_ABORT, 0, _("obuf is NULL\n"));
168    }
169    cp -= HEAD_SIZE;
170    return ((struct abufhead *)cp)->ablen;
171 }
172
173 /* Realloc pool memory buffer */
174 POOLMEM *sm_realloc_pool_memory(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
175 {
176    char *cp = (char *)obuf;
177    void *buf;
178    int pool;
179
180    ASSERT(obuf);
181    P(mutex);
182    cp -= HEAD_SIZE;
183    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
184    if (buf == NULL) {
185       V(mutex);
186       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
187    }
188    ((struct abufhead *)buf)->ablen = size;
189    pool = ((struct abufhead *)buf)->pool;
190    if (size > pool_ctl[pool].max_allocated) {
191       pool_ctl[pool].max_allocated = size;
192    }
193    V(mutex);
194    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
195 }
196
197 POOLMEM *sm_check_pool_memory_size(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
198 {
199    ASSERT(obuf);
200    if (size <= sizeof_pool_memory(obuf)) {
201       return obuf;
202    }
203    return realloc_pool_memory(obuf, size);
204 }
205
206 /* Free a memory buffer */
207 void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
208 {
209    struct abufhead *buf;
210    int pool;
211
212    ASSERT(obuf);
213    P(mutex);
214    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
215    pool = buf->pool;
216    pool_ctl[pool].in_use--;
217    if (pool == 0) {
218       free((char *)buf);              /* free nonpooled memory */
219    } else {                           /* otherwise link it to the free pool chain */
220 #ifdef DEBUG
221       struct abufhead *next;
222       /* Don't let him free the same buffer twice */
223       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
224          if (next == buf) {
225             Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
226             Dmsg4(1800, "bad free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
227             V(mutex);                 /* unblock the pool */
228             ASSERT(next != buf);      /* attempt to free twice */
229          }
230       }
231 #endif
232       buf->next = pool_ctl[pool].free_buf;
233       pool_ctl[pool].free_buf = buf;
234    }
235    Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
236    V(mutex);
237 }
238
239 #else
240
241 /* =========  NO SMARTALLOC  =========================================  */
242
243 POOLMEM *get_pool_memory(int pool)
244 {
245    struct abufhead *buf;
246
247    P(mutex);
248    if (pool_ctl[pool].free_buf) {
249       buf = pool_ctl[pool].free_buf;
250       pool_ctl[pool].free_buf = buf->next;
251       V(mutex);
252       return (POOLMEM *)((char *)buf+HEAD_SIZE);
253    }
254
255    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
256       V(mutex);
257       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
258    }
259    buf->ablen = pool_ctl[pool].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    V(mutex);
267    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
268 }
269
270 /* Get nonpool memory of size requested */
271 POOLMEM *get_memory(int32_t size)
272 {
273    struct abufhead *buf;
274    int pool = 0;
275
276    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
277       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
278    }
279    buf->ablen = size;
280    buf->pool = pool;
281    buf->next = NULL;
282    pool_ctl[pool].in_use++;
283    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
284       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
285    }
286    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
287 }
288
289 /* Return the size of a memory buffer */
290 int32_t sizeof_pool_memory(POOLMEM *obuf)
291 {
292    char *cp = (char *)obuf;
293
294    ASSERT(obuf);
295    cp -= HEAD_SIZE;
296    return ((struct abufhead *)cp)->ablen;
297 }
298
299 /* Realloc pool memory buffer */
300 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
301 {
302    char *cp = (char *)obuf;
303    void *buf;
304    int pool;
305
306    ASSERT(obuf);
307    P(mutex);
308    cp -= HEAD_SIZE;
309    buf = realloc(cp, size+HEAD_SIZE);
310    if (buf == NULL) {
311       V(mutex);
312       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
313    }
314    ((struct abufhead *)buf)->ablen = size;
315    pool = ((struct abufhead *)buf)->pool;
316    if (size > pool_ctl[pool].max_allocated) {
317       pool_ctl[pool].max_allocated = size;
318    }
319    V(mutex);
320    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
321 }
322
323 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
324 {
325    ASSERT(obuf);
326    if (size <= sizeof_pool_memory(obuf)) {
327       return obuf;
328    }
329    return realloc_pool_memory(obuf, size);
330 }
331
332 /* Free a memory buffer */
333 void free_pool_memory(POOLMEM *obuf)
334 {
335    struct abufhead *buf;
336    int pool;
337
338    ASSERT(obuf);
339    P(mutex);
340    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
341    pool = buf->pool;
342    pool_ctl[pool].in_use--;
343    if (pool == 0) {
344       free((char *)buf);              /* free nonpooled memory */
345    } else {                           /* otherwise link it to the free pool chain */
346 #ifdef DEBUG
347       struct abufhead *next;
348       /* Don't let him free the same buffer twice */
349       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
350          if (next == buf) {
351             V(mutex);
352             ASSERT(next != buf);  /* attempt to free twice */
353          }
354       }
355 #endif
356       buf->next = pool_ctl[pool].free_buf;
357       pool_ctl[pool].free_buf = buf;
358    }
359    Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool);
360    V(mutex);
361 }
362 #endif /* SMARTALLOC */
363
364 /*
365  * Clean up memory pool periodically
366  *
367  */
368 static time_t last_garbage_collection = 0;
369 const int garbage_interval = 24 * 60 * 60;  /* garbage collect every 24 hours */
370
371 void garbage_collect_memory_pool()
372 {
373    time_t now;
374
375    Dmsg0(200, "garbage collect memory pool\n");
376    P(mutex);
377    if (last_garbage_collection == 0) {
378       last_garbage_collection = time(NULL);
379       V(mutex);
380       return;
381    }
382    now = time(NULL);
383    if (now >= last_garbage_collection + garbage_interval) {
384       last_garbage_collection = now;
385       V(mutex);
386       garbage_collect_memory();
387    } else {
388       V(mutex);
389    }
390 }
391
392 /* Release all freed pooled memory */
393 void close_memory_pool()
394 {
395    struct abufhead *buf, *next;
396    int count = 0;
397    uint64_t bytes = 0;
398    char ed1[50];
399
400    sm_check(__FILE__, __LINE__, false);
401    P(mutex);
402    for (int i=1; i<=PM_MAX; i++) {
403       buf = pool_ctl[i].free_buf;
404       while (buf) {
405          next = buf->next;
406          count++;
407          bytes += sizeof_pool_memory((char *)buf);
408          free((char *)buf);
409          buf = next;
410       }
411       pool_ctl[i].free_buf = NULL;
412    }
413    Dmsg2(001, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
414    if (debug_level >= 1) {
415       print_memory_pool_stats();
416    }
417    V(mutex);
418
419 }
420
421 /*
422  * Garbage collect and trim memory if possible
423  *  This should be called after all big memory usages
424  *  if possible.
425  */
426 void garbage_collect_memory()
427 {
428    close_memory_pool();         /* release free chain */
429 #ifdef HAVE_MALLOC_TRIM
430    P(mutex);
431    malloc_trim(8192);
432    V(mutex);
433 #endif
434 }
435
436 #ifdef DEBUG
437 static const char *pool_name(int pool)
438 {
439    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  ", "BSOCK "};
440    static char buf[30];
441
442    if (pool >= 0 && pool <= PM_MAX) {
443       return name[pool];
444    }
445    sprintf(buf, "%-6d", pool);
446    return buf;
447 }
448
449 /* Print staticstics on memory pool usage
450  */
451 void print_memory_pool_stats()
452 {
453    Pmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
454    for (int i=0; i<=PM_MAX; i++)
455       Pmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_allocated,
456          pool_ctl[i].max_used, pool_ctl[i].in_use);
457
458    Pmsg0(-1, "\n");
459 }
460
461 #else
462 void print_memory_pool_stats() {}
463 #endif /* DEBUG */
464
465 /*
466  * Concatenate a string (str) onto a pool memory buffer pm
467  *   Returns: length of concatenated string
468  */
469 int pm_strcat(POOLMEM **pm, const char *str)
470 {
471    int pmlen = strlen(*pm);
472    int len;
473
474    if (!str) str = "";
475
476    len = strlen(str) + 1;
477    *pm = check_pool_memory_size(*pm, pmlen + len);
478    memcpy(*pm+pmlen, str, len);
479    return pmlen + len - 1;
480 }
481
482 int pm_strcat(POOLMEM *&pm, const char *str)
483 {
484    int pmlen = strlen(pm);
485    int len;
486
487    if (!str) str = "";
488
489    len = strlen(str) + 1;
490    pm = check_pool_memory_size(pm, pmlen + len);
491    memcpy(pm+pmlen, str, len);
492    return pmlen + len - 1;
493 }
494
495 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
496 {
497    int pmlen = strlen(pm);
498    int len = strlen(str.c_str()) + 1;
499
500    pm = check_pool_memory_size(pm, pmlen + len);
501    memcpy(pm+pmlen, str.c_str(), len);
502    return pmlen + len - 1;
503 }
504
505 int pm_strcat(POOL_MEM &pm, const char *str)
506 {
507    int pmlen = strlen(pm.c_str());
508    int len;
509
510    if (!str) str = "";
511
512    len = strlen(str) + 1;
513    pm.check_size(pmlen + len);
514    memcpy(pm.c_str()+pmlen, str, len);
515    return pmlen + len - 1;
516 }
517
518 /*
519  * Copy a string (str) into a pool memory buffer pm
520  *   Returns: length of string copied
521  */
522 int pm_strcpy(POOLMEM **pm, const char *str)
523 {
524    int len;
525
526    if (!str) str = "";
527
528    len = strlen(str) + 1;
529    *pm = check_pool_memory_size(*pm, len);
530    memcpy(*pm, str, len);
531    return len - 1;
532 }
533
534 int pm_strcpy(POOLMEM *&pm, const char *str)
535 {
536    int len;
537
538    if (!str) str = "";
539
540    len = strlen(str) + 1;
541    pm = check_pool_memory_size(pm, len);
542    memcpy(pm, str, len);
543    return len - 1;
544 }
545
546 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
547 {
548    int len = strlen(str.c_str()) + 1;
549
550    pm = check_pool_memory_size(pm, len);
551    memcpy(pm, str.c_str(), len);
552    return len - 1;
553 }
554
555 int pm_strcpy(POOL_MEM &pm, const char *str)
556 {
557    int len;
558
559    if (!str) str = "";
560
561    len = strlen(str) + 1;
562    pm.check_size(len);
563    memcpy(pm.c_str(), str, len);
564    return len - 1;
565 }
566
567 /*
568  * Copy data into a pool memory buffer pm
569  *   Returns: length of data copied
570  */
571 int pm_memcpy(POOLMEM **pm, const char *data, int32_t n)
572 {
573    *pm = check_pool_memory_size(*pm, n);
574    memcpy(*pm, data, n);
575    return n;
576 }
577
578 int pm_memcpy(POOLMEM *&pm, const char *data, int32_t n)
579 {
580    pm = check_pool_memory_size(pm, n);
581    memcpy(pm, data, n);
582    return n;
583 }
584
585 int pm_memcpy(POOLMEM *&pm, POOL_MEM &data, int32_t n)
586 {
587    pm = check_pool_memory_size(pm, n);
588    memcpy(pm, data.c_str(), n);
589    return n;
590 }
591
592 int pm_memcpy(POOL_MEM &pm, const char *data, int32_t n)
593 {
594    pm.check_size(n);
595    memcpy(pm.c_str(), data, n);
596    return n;
597 }
598
599 /* ==============  CLASS POOL_MEM   ============== */
600
601 /* Return the size of a memory buffer */
602 int32_t POOL_MEM::max_size()
603 {
604    int32_t size;
605    char *cp = mem;
606    cp -= HEAD_SIZE;
607    size = ((struct abufhead *)cp)->ablen;
608    Dmsg1(900, "max_size=%d\n", size);
609    return size;
610 }
611
612 void POOL_MEM::realloc_pm(int32_t size)
613 {
614    char *cp = mem;
615    char *buf;
616    int pool;
617
618    P(mutex);
619    cp -= HEAD_SIZE;
620    buf = (char *)realloc(cp, size+HEAD_SIZE);
621    if (buf == NULL) {
622       V(mutex);
623       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
624    }
625    Dmsg2(900, "Old buf=%p new buf=%p\n", cp, buf);
626    ((struct abufhead *)buf)->ablen = size;
627    pool = ((struct abufhead *)buf)->pool;
628    if (size > pool_ctl[pool].max_allocated) {
629       pool_ctl[pool].max_allocated = size;
630    }
631    mem = buf+HEAD_SIZE;
632    V(mutex);
633    Dmsg3(900, "Old buf=%p new buf=%p mem=%p\n", cp, buf, mem);
634 }
635
636 int POOL_MEM::strcat(const char *str)
637 {
638    int pmlen = strlen(mem);
639    int len;
640
641    if (!str) str = "";
642
643    len = strlen(str) + 1;
644    check_size(pmlen + len);
645    memcpy(mem+pmlen, str, len);
646    return pmlen + len - 1;
647 }
648
649 int POOL_MEM::strcpy(const char *str)
650 {
651    int len;
652
653    if (!str) str = "";
654
655    len = strlen(str) + 1;
656    check_size(len);
657    memcpy(mem, str, len);
658    return len - 1;
659 }