]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
c7036c59bdacbe5a3d922d9894eacd562bd3aa48
[bacula/bacula] / bacula / src / lib / mem_pool.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2007 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 two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed 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 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 John Walker.
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  *   Version $Id$
48  */
49
50 #include "bacula.h"
51
52 struct s_pool_ctl {
53    int32_t size;                      /* default size */
54    int32_t max_allocated;             /* max allocated */
55    int32_t max_used;                  /* max buffers used */
56    int32_t in_use;                    /* number in use */
57    struct abufhead *free_buf;         /* pointer to free buffers */
58 };
59
60 /* Bacula Name length plus extra */
61 #define NLEN (MAX_NAME_LENGTH+2)
62
63 /* #define STRESS_TEST_POOL */
64 #ifndef STRESS_TEST_POOL
65 /*
66  * Define default Pool buffer sizes
67  */
68 static struct s_pool_ctl pool_ctl[] = {
69    {  256,  256, 0, 0, NULL },        /* PM_NOPOOL no pooling */
70    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
71    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
72    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
73    { 1024, 1024, 0, 0, NULL }         /* PM_EMSG error message buffer */
74 };
75 #else
76
77 /* This is used ONLY when stress testing the code */
78 static struct s_pool_ctl pool_ctl[] = {
79    {   20,   20, 0, 0, NULL },        /* PM_NOPOOL no pooling */
80    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
81    {   20,   20, 0, 0, NULL },        /* PM_FNAME filename buffers */
82    {   20,   20, 0, 0, NULL },        /* PM_MESSAGE message buffer */
83    {   20,   20, 0, 0, NULL }         /* PM_EMSG error message buffer */
84 };
85 #endif
86
87
88 /*  Memory allocation control structures and storage.  */
89 struct abufhead {
90    int32_t ablen;                     /* Buffer length in bytes */
91    int32_t pool;                      /* pool */
92    struct abufhead *next;             /* pointer to next free buffer */
93    int32_t bnet_size;                 /* dummy for bnet_send() */
94 };
95
96 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
97
98
99 #ifdef SMARTALLOC
100
101 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
102
103 POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
104 {
105    struct abufhead *buf;
106
107    if (pool > PM_MAX) {
108       Emsg2(M_ABORT, 0, _("MemPool index %d larger than max %d\n"), pool, PM_MAX);
109    }
110    P(mutex);
111    if (pool_ctl[pool].free_buf) {
112       buf = pool_ctl[pool].free_buf;
113       pool_ctl[pool].free_buf = buf->next;
114       pool_ctl[pool].in_use++;
115       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
116          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
117       }
118       V(mutex);
119       Dmsg3(1800, "sm_get_pool_memory reuse %p to %s:%d\n", buf, fname, lineno);
120       sm_new_owner(fname, lineno, (char *)buf);
121       return (POOLMEM *)((char *)buf+HEAD_SIZE);
122    }
123
124    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
125       V(mutex);
126       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
127    }
128    buf->ablen = pool_ctl[pool].size;
129    buf->pool = pool;
130    pool_ctl[pool].in_use++;
131    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
132       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
133    }
134    V(mutex);
135    Dmsg3(1800, "sm_get_pool_memory give %p to %s:%d\n", buf, fname, lineno);
136    return (POOLMEM *)((char *)buf+HEAD_SIZE);
137 }
138
139 /* Get nonpool memory of size requested */
140 POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size)
141 {
142    struct abufhead *buf;
143    int pool = 0;
144
145    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
146       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
147    }
148    buf->ablen = size;
149    buf->pool = pool;
150    buf->next = NULL;
151    pool_ctl[pool].in_use++;
152    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
153       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
154    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
155 }
156
157
158 /* Return the size of a memory buffer */
159 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
160 {
161    char *cp = (char *)obuf;
162
163    ASSERT(obuf);
164    cp -= HEAD_SIZE;
165    return ((struct abufhead *)cp)->ablen;
166 }
167
168 /* Realloc pool memory buffer */
169 POOLMEM *sm_realloc_pool_memory(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
170 {
171    char *cp = (char *)obuf;
172    void *buf;
173    int pool;
174
175    ASSERT(obuf);
176    P(mutex);
177    cp -= HEAD_SIZE;
178    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
179    if (buf == NULL) {
180       V(mutex);
181       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
182    }
183    ((struct abufhead *)buf)->ablen = size;
184    pool = ((struct abufhead *)buf)->pool;
185    if (size > pool_ctl[pool].max_allocated) {
186       pool_ctl[pool].max_allocated = size;
187    }
188    V(mutex);
189    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
190 }
191
192 POOLMEM *sm_check_pool_memory_size(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
193 {
194    ASSERT(obuf);
195    if (size <= sizeof_pool_memory(obuf)) {
196       return obuf;
197    }
198    return realloc_pool_memory(obuf, size);
199 }
200
201 /* Free a memory buffer */
202 void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
203 {
204    struct abufhead *buf;
205    int pool;
206
207    ASSERT(obuf);
208    P(mutex);
209    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
210    pool = buf->pool;
211    pool_ctl[pool].in_use--;
212    if (pool == 0) {
213       free((char *)buf);              /* free nonpooled memory */
214    } else {                           /* otherwise link it to the free pool chain */
215 #ifdef DEBUG
216       struct abufhead *next;
217       /* Don't let him free the same buffer twice */
218       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
219          if (next == buf) {
220             Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
221             Dmsg4(1800, "bad free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
222             V(mutex);                 /* unblock the pool */
223             ASSERT(next != buf);      /* attempt to free twice */
224          }
225       }
226 #endif
227       buf->next = pool_ctl[pool].free_buf;
228       pool_ctl[pool].free_buf = buf;
229    }
230    Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
231    V(mutex);
232 }
233
234
235 #else
236
237 /* =========  NO SMARTALLOC  =========================================  */
238
239 POOLMEM *get_pool_memory(int pool)
240 {
241    struct abufhead *buf;
242
243    P(mutex);
244    if (pool_ctl[pool].free_buf) {
245       buf = pool_ctl[pool].free_buf;
246       pool_ctl[pool].free_buf = buf->next;
247       V(mutex);
248       return (POOLMEM *)((char *)buf+HEAD_SIZE);
249    }
250
251    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
252       V(mutex);
253       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
254    }
255    buf->ablen = pool_ctl[pool].size;
256    buf->pool = pool;
257    buf->next = NULL;
258    pool_ctl[pool].in_use++;
259    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
260       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
261    }
262    V(mutex);
263    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
264 }
265
266 /* Get nonpool memory of size requested */
267 POOLMEM *get_memory(int32_t size)
268 {
269    struct abufhead *buf;
270    int pool = 0;
271
272    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
273       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
274    }
275    buf->ablen = size;
276    buf->pool = pool;
277    buf->next = NULL;
278    pool_ctl[pool].in_use++;
279    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
280       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
281    }
282    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
283 }
284
285
286 /* Return the size of a memory buffer */
287 int32_t sizeof_pool_memory(POOLMEM *obuf)
288 {
289    char *cp = (char *)obuf;
290
291    ASSERT(obuf);
292    cp -= HEAD_SIZE;
293    return ((struct abufhead *)cp)->ablen;
294 }
295
296
297
298 /* Realloc pool memory buffer */
299 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
300 {
301    char *cp = (char *)obuf;
302    void *buf;
303    int pool;
304
305    ASSERT(obuf);
306    P(mutex);
307    cp -= HEAD_SIZE;
308    buf = realloc(cp, size+HEAD_SIZE);
309    if (buf == NULL) {
310       V(mutex);
311       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
312    }
313    ((struct abufhead *)buf)->ablen = size;
314    pool = ((struct abufhead *)buf)->pool;
315    if (size > pool_ctl[pool].max_allocated) {
316       pool_ctl[pool].max_allocated = size;
317    }
318    V(mutex);
319    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
320 }
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
363 #endif /* SMARTALLOC */
364
365
366 /*
367  * Clean up memory pool periodically
368  *
369  */
370 static time_t last_garbage_collection = 0;
371 const int garbage_interval = 24 * 60 * 60;  /* garbage collect every 24 hours */
372
373 void garbage_collect_memory_pool()
374 {
375    time_t now;
376
377    Dmsg0(200, "garbage collect memory pool\n");
378    P(mutex);
379    if (last_garbage_collection == 0) {
380       last_garbage_collection = time(NULL);
381       V(mutex);
382       return;
383    }
384    now = time(NULL);
385    if (now >= last_garbage_collection + garbage_interval) {
386       last_garbage_collection = now;
387       V(mutex);
388       close_memory_pool();
389    } else {
390       V(mutex);
391    }
392 }
393
394
395
396
397 /* Release all pooled memory */
398 void close_memory_pool()
399 {
400    struct abufhead *buf, *next;
401    int count = 0;
402    uint64_t bytes = 0;
403    char ed1[50];
404
405    sm_check(__FILE__, __LINE__, false);
406    P(mutex);
407    for (int i=1; i<=PM_MAX; i++) {
408       buf = pool_ctl[i].free_buf;
409       while (buf) {
410          next = buf->next;
411          count++;
412          bytes += sizeof_pool_memory((char *)buf);
413          free((char *)buf);
414          buf = next;
415       }
416       pool_ctl[i].free_buf = NULL;
417    }
418    Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
419    V(mutex);
420
421 }
422
423 #ifdef DEBUG
424
425 static const char *pool_name(int pool)
426 {
427    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
428    static char buf[30];
429
430    if (pool >= 0 && pool <= PM_MAX) {
431       return name[pool];
432    }
433    sprintf(buf, "%-6d", pool);
434    return buf;
435 }
436
437 /* Print staticstics on memory pool usage
438  */
439 void print_memory_pool_stats()
440 {
441    Pmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
442    for (int i=0; i<=PM_MAX; i++)
443       Pmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_allocated,
444          pool_ctl[i].max_used, pool_ctl[i].in_use);
445
446    Pmsg0(-1, "\n");
447 }
448
449 #else
450 void print_memory_pool_stats() {}
451 #endif /* DEBUG */
452
453
454 /*
455  * Concatenate a string (str) onto a pool memory buffer pm
456  *   Returns: length of concatenated string
457  */
458 int pm_strcat(POOLMEM **pm, const char *str)
459 {
460    int pmlen = strlen(*pm);
461    int len;
462
463    if (!str) str = "";
464
465    len = strlen(str) + 1;
466    *pm = check_pool_memory_size(*pm, pmlen + len);
467    memcpy(*pm+pmlen, str, len);
468    return pmlen + len - 1;
469 }
470
471 int pm_strcat(POOLMEM *&pm, const char *str)
472 {
473    int pmlen = strlen(pm);
474    int len;
475
476    if (!str) str = "";
477
478    len = strlen(str) + 1;
479    pm = check_pool_memory_size(pm, pmlen + len);
480    memcpy(pm+pmlen, str, len);
481    return pmlen + len - 1;
482 }
483
484
485 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
486 {
487    int pmlen = strlen(pm);
488    int len = strlen(str.c_str()) + 1;
489
490    pm = check_pool_memory_size(pm, pmlen + len);
491    memcpy(pm+pmlen, str.c_str(), len);
492    return pmlen + len - 1;
493 }
494
495 int pm_strcat(POOL_MEM &pm, const char *str)
496 {
497    int pmlen = strlen(pm.c_str());
498    int len;
499
500    if (!str) str = "";
501
502    len = strlen(str) + 1;
503    pm.check_size(pmlen + len);
504    memcpy(pm.c_str()+pmlen, str, len);
505    return pmlen + len - 1;
506 }
507
508
509 /*
510  * Copy a string (str) into a pool memory buffer pm
511  *   Returns: length of string copied
512  */
513 int pm_strcpy(POOLMEM **pm, const char *str)
514 {
515    int len;
516
517    if (!str) str = "";
518
519    len = strlen(str) + 1;
520    *pm = check_pool_memory_size(*pm, len);
521    memcpy(*pm, str, len);
522    return len - 1;
523 }
524
525 int pm_strcpy(POOLMEM *&pm, const char *str)
526 {
527    int len;
528
529    if (!str) str = "";
530
531    len = strlen(str) + 1;
532    pm = check_pool_memory_size(pm, len);
533    memcpy(pm, str, len);
534    return len - 1;
535 }
536
537 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
538 {
539    int len = strlen(str.c_str()) + 1;
540
541    pm = check_pool_memory_size(pm, len);
542    memcpy(pm, str.c_str(), len);
543    return len - 1;
544 }
545
546
547 int pm_strcpy(POOL_MEM &pm, const char *str)
548 {
549    int len;
550
551    if (!str) str = "";
552
553    len = strlen(str) + 1;
554    pm.check_size(len);
555    memcpy(pm.c_str(), str, len);
556    return len - 1;
557 }
558
559 /* ==============  CLASS POOL_MEM   ============== */
560
561 /* Return the size of a memory buffer */
562 int32_t POOL_MEM::max_size()
563 {
564    int32_t size;
565    char *cp = mem;
566    cp -= HEAD_SIZE;
567    size = ((struct abufhead *)cp)->ablen;
568    Dmsg1(900, "max_size=%d\n", size);
569    return size;
570 }
571
572 void POOL_MEM::realloc_pm(int32_t size)
573 {
574    char *cp = mem;
575    char *buf;
576    int pool;
577
578    P(mutex);
579    cp -= HEAD_SIZE;
580    buf = (char *)realloc(cp, size+HEAD_SIZE);
581    if (buf == NULL) {
582       V(mutex);
583       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
584    }
585    Dmsg2(900, "Old buf=%p new buf=%p\n", cp, buf);
586    ((struct abufhead *)buf)->ablen = size;
587    pool = ((struct abufhead *)buf)->pool;
588    if (size > pool_ctl[pool].max_allocated) {
589       pool_ctl[pool].max_allocated = size;
590    }
591    mem = buf+HEAD_SIZE;
592    V(mutex);
593    Dmsg3(900, "Old buf=%p new buf=%p mem=%p\n", cp, buf, mem);
594 }
595
596 int POOL_MEM::strcat(const char *str)
597 {
598    int pmlen = strlen(mem);
599    int len;
600
601    if (!str) str = "";
602
603    len = strlen(str) + 1;
604    check_size(pmlen + len);
605    memcpy(mem+pmlen, str, len);
606    return pmlen + len - 1;
607 }
608
609
610 int POOL_MEM::strcpy(const char *str)
611 {
612    int len;
613
614    if (!str) str = "";
615
616    len = strlen(str) + 1;
617    check_size(len);
618    memcpy(mem, str, len);
619    return len - 1;
620 }