]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
kes Prepare to add JS_Warnings termination status.
[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 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 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  *   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 #ifdef SMARTALLOC
99
100 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
101
102 POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
103 {
104    struct abufhead *buf;
105
106    if (pool > PM_MAX) {
107       Emsg2(M_ABORT, 0, _("MemPool index %d larger than max %d\n"), pool, PM_MAX);
108    }
109    P(mutex);
110    if (pool_ctl[pool].free_buf) {
111       buf = pool_ctl[pool].free_buf;
112       pool_ctl[pool].free_buf = buf->next;
113       pool_ctl[pool].in_use++;
114       if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
115          pool_ctl[pool].max_used = pool_ctl[pool].in_use;
116       }
117       V(mutex);
118       Dmsg3(1800, "sm_get_pool_memory reuse %p to %s:%d\n", buf, fname, lineno);
119       sm_new_owner(fname, lineno, (char *)buf);
120       return (POOLMEM *)((char *)buf+HEAD_SIZE);
121    }
122
123    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
124       V(mutex);
125       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
126    }
127    buf->ablen = pool_ctl[pool].size;
128    buf->pool = pool;
129    pool_ctl[pool].in_use++;
130    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
131       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
132    }
133    V(mutex);
134    Dmsg3(1800, "sm_get_pool_memory give %p to %s:%d\n", buf, fname, lineno);
135    return (POOLMEM *)((char *)buf+HEAD_SIZE);
136 }
137
138 /* Get nonpool memory of size requested */
139 POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size)
140 {
141    struct abufhead *buf;
142    int pool = 0;
143
144    if ((buf = (struct abufhead *)sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
145       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
146    }
147    buf->ablen = size;
148    buf->pool = pool;
149    buf->next = NULL;
150    pool_ctl[pool].in_use++;
151    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used)
152       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
153    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
154 }
155
156 /* Return the size of a memory buffer */
157 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
158 {
159    char *cp = (char *)obuf;
160
161    if (obuf == NULL) {
162       Emsg0(M_ABORT, 0, _("obuf is NULL\n"));
163    }
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 #else
235
236 /* =========  NO SMARTALLOC  =========================================  */
237
238 POOLMEM *get_pool_memory(int pool)
239 {
240    struct abufhead *buf;
241
242    P(mutex);
243    if (pool_ctl[pool].free_buf) {
244       buf = pool_ctl[pool].free_buf;
245       pool_ctl[pool].free_buf = buf->next;
246       V(mutex);
247       return (POOLMEM *)((char *)buf+HEAD_SIZE);
248    }
249
250    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
251       V(mutex);
252       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
253    }
254    buf->ablen = pool_ctl[pool].size;
255    buf->pool = pool;
256    buf->next = NULL;
257    pool_ctl[pool].in_use++;
258    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
259       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
260    }
261    V(mutex);
262    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
263 }
264
265 /* Get nonpool memory of size requested */
266 POOLMEM *get_memory(int32_t size)
267 {
268    struct abufhead *buf;
269    int pool = 0;
270
271    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
272       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
273    }
274    buf->ablen = size;
275    buf->pool = pool;
276    buf->next = NULL;
277    pool_ctl[pool].in_use++;
278    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
279       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
280    }
281    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
282 }
283
284 /* Return the size of a memory buffer */
285 int32_t sizeof_pool_memory(POOLMEM *obuf)
286 {
287    char *cp = (char *)obuf;
288
289    ASSERT(obuf);
290    cp -= HEAD_SIZE;
291    return ((struct abufhead *)cp)->ablen;
292 }
293
294 /* Realloc pool memory buffer */
295 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
296 {
297    char *cp = (char *)obuf;
298    void *buf;
299    int pool;
300
301    ASSERT(obuf);
302    P(mutex);
303    cp -= HEAD_SIZE;
304    buf = realloc(cp, size+HEAD_SIZE);
305    if (buf == NULL) {
306       V(mutex);
307       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
308    }
309    ((struct abufhead *)buf)->ablen = size;
310    pool = ((struct abufhead *)buf)->pool;
311    if (size > pool_ctl[pool].max_allocated) {
312       pool_ctl[pool].max_allocated = size;
313    }
314    V(mutex);
315    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
316 }
317
318 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
319 {
320    ASSERT(obuf);
321    if (size <= sizeof_pool_memory(obuf)) {
322       return obuf;
323    }
324    return realloc_pool_memory(obuf, size);
325 }
326
327 /* Free a memory buffer */
328 void free_pool_memory(POOLMEM *obuf)
329 {
330    struct abufhead *buf;
331    int pool;
332
333    ASSERT(obuf);
334    P(mutex);
335    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
336    pool = buf->pool;
337    pool_ctl[pool].in_use--;
338    if (pool == 0) {
339       free((char *)buf);              /* free nonpooled memory */
340    } else {                           /* otherwise link it to the free pool chain */
341 #ifdef DEBUG
342       struct abufhead *next;
343       /* Don't let him free the same buffer twice */
344       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
345          if (next == buf) {
346             V(mutex);
347             ASSERT(next != buf);  /* attempt to free twice */
348          }
349       }
350 #endif
351       buf->next = pool_ctl[pool].free_buf;
352       pool_ctl[pool].free_buf = buf;
353    }
354    Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool);
355    V(mutex);
356 }
357 #endif /* SMARTALLOC */
358
359 /*
360  * Clean up memory pool periodically
361  *
362  */
363 static time_t last_garbage_collection = 0;
364 const int garbage_interval = 24 * 60 * 60;  /* garbage collect every 24 hours */
365
366 void garbage_collect_memory_pool()
367 {
368    time_t now;
369
370    Dmsg0(200, "garbage collect memory pool\n");
371    P(mutex);
372    if (last_garbage_collection == 0) {
373       last_garbage_collection = time(NULL);
374       V(mutex);
375       return;
376    }
377    now = time(NULL);
378    if (now >= last_garbage_collection + garbage_interval) {
379       last_garbage_collection = now;
380       V(mutex);
381       close_memory_pool();
382    } else {
383       V(mutex);
384    }
385 }
386
387 /* Release all pooled memory */
388 void close_memory_pool()
389 {
390    struct abufhead *buf, *next;
391    int count = 0;
392    uint64_t bytes = 0;
393    char ed1[50];
394
395    sm_check(__FILE__, __LINE__, false);
396    P(mutex);
397    for (int i=1; i<=PM_MAX; i++) {
398       buf = pool_ctl[i].free_buf;
399       while (buf) {
400          next = buf->next;
401          count++;
402          bytes += sizeof_pool_memory((char *)buf);
403          free((char *)buf);
404          buf = next;
405       }
406       pool_ctl[i].free_buf = NULL;
407    }
408    Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
409    V(mutex);
410
411 }
412
413 #ifdef DEBUG
414 static const char *pool_name(int pool)
415 {
416    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
417    static char buf[30];
418
419    if (pool >= 0 && pool <= PM_MAX) {
420       return name[pool];
421    }
422    sprintf(buf, "%-6d", pool);
423    return buf;
424 }
425
426 /* Print staticstics on memory pool usage
427  */
428 void print_memory_pool_stats()
429 {
430    Pmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
431    for (int i=0; i<=PM_MAX; i++)
432       Pmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_allocated,
433          pool_ctl[i].max_used, pool_ctl[i].in_use);
434
435    Pmsg0(-1, "\n");
436 }
437
438 #else
439 void print_memory_pool_stats() {}
440 #endif /* DEBUG */
441
442 /*
443  * Concatenate a string (str) onto a pool memory buffer pm
444  *   Returns: length of concatenated string
445  */
446 int pm_strcat(POOLMEM **pm, const char *str)
447 {
448    int pmlen = strlen(*pm);
449    int len;
450
451    if (!str) str = "";
452
453    len = strlen(str) + 1;
454    *pm = check_pool_memory_size(*pm, pmlen + len);
455    memcpy(*pm+pmlen, str, len);
456    return pmlen + len - 1;
457 }
458
459 int pm_strcat(POOLMEM *&pm, const char *str)
460 {
461    int pmlen = strlen(pm);
462    int len;
463
464    if (!str) str = "";
465
466    len = strlen(str) + 1;
467    pm = check_pool_memory_size(pm, pmlen + len);
468    memcpy(pm+pmlen, str, len);
469    return pmlen + len - 1;
470 }
471
472 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
473 {
474    int pmlen = strlen(pm);
475    int len = strlen(str.c_str()) + 1;
476
477    pm = check_pool_memory_size(pm, pmlen + len);
478    memcpy(pm+pmlen, str.c_str(), len);
479    return pmlen + len - 1;
480 }
481
482 int pm_strcat(POOL_MEM &pm, const char *str)
483 {
484    int pmlen = strlen(pm.c_str());
485    int len;
486
487    if (!str) str = "";
488
489    len = strlen(str) + 1;
490    pm.check_size(pmlen + len);
491    memcpy(pm.c_str()+pmlen, str, len);
492    return pmlen + len - 1;
493 }
494
495 /*
496  * Copy a string (str) into a pool memory buffer pm
497  *   Returns: length of string copied
498  */
499 int pm_strcpy(POOLMEM **pm, const char *str)
500 {
501    int len;
502
503    if (!str) str = "";
504
505    len = strlen(str) + 1;
506    *pm = check_pool_memory_size(*pm, len);
507    memcpy(*pm, str, len);
508    return len - 1;
509 }
510
511 int pm_strcpy(POOLMEM *&pm, const char *str)
512 {
513    int len;
514
515    if (!str) str = "";
516
517    len = strlen(str) + 1;
518    pm = check_pool_memory_size(pm, len);
519    memcpy(pm, str, len);
520    return len - 1;
521 }
522
523 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
524 {
525    int len = strlen(str.c_str()) + 1;
526
527    pm = check_pool_memory_size(pm, len);
528    memcpy(pm, str.c_str(), len);
529    return len - 1;
530 }
531
532 int pm_strcpy(POOL_MEM &pm, const char *str)
533 {
534    int len;
535
536    if (!str) str = "";
537
538    len = strlen(str) + 1;
539    pm.check_size(len);
540    memcpy(pm.c_str(), str, len);
541    return len - 1;
542 }
543
544 /*
545  * Copy data into a pool memory buffer pm
546  *   Returns: length of data copied
547  */
548 int pm_memcpy(POOLMEM **pm, const char *data, int32_t n)
549 {
550    *pm = check_pool_memory_size(*pm, n);
551    memcpy(*pm, data, n);
552    return n;
553 }
554
555 int pm_memcpy(POOLMEM *&pm, const char *data, int32_t n)
556 {
557    pm = check_pool_memory_size(pm, n);
558    memcpy(pm, data, n);
559    return n;
560 }
561
562 int pm_memcpy(POOLMEM *&pm, POOL_MEM &data, int32_t n)
563 {
564    pm = check_pool_memory_size(pm, n);
565    memcpy(pm, data.c_str(), n);
566    return n;
567 }
568
569 int pm_memcpy(POOL_MEM &pm, const char *data, int32_t n)
570 {
571    pm.check_size(n);
572    memcpy(pm.c_str(), data, n);
573    return n;
574 }
575
576 /* ==============  CLASS POOL_MEM   ============== */
577
578 /* Return the size of a memory buffer */
579 int32_t POOL_MEM::max_size()
580 {
581    int32_t size;
582    char *cp = mem;
583    cp -= HEAD_SIZE;
584    size = ((struct abufhead *)cp)->ablen;
585    Dmsg1(900, "max_size=%d\n", size);
586    return size;
587 }
588
589 void POOL_MEM::realloc_pm(int32_t size)
590 {
591    char *cp = mem;
592    char *buf;
593    int pool;
594
595    P(mutex);
596    cp -= HEAD_SIZE;
597    buf = (char *)realloc(cp, size+HEAD_SIZE);
598    if (buf == NULL) {
599       V(mutex);
600       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
601    }
602    Dmsg2(900, "Old buf=%p new buf=%p\n", cp, buf);
603    ((struct abufhead *)buf)->ablen = size;
604    pool = ((struct abufhead *)buf)->pool;
605    if (size > pool_ctl[pool].max_allocated) {
606       pool_ctl[pool].max_allocated = size;
607    }
608    mem = buf+HEAD_SIZE;
609    V(mutex);
610    Dmsg3(900, "Old buf=%p new buf=%p mem=%p\n", cp, buf, mem);
611 }
612
613 int POOL_MEM::strcat(const char *str)
614 {
615    int pmlen = strlen(mem);
616    int len;
617
618    if (!str) str = "";
619
620    len = strlen(str) + 1;
621    check_size(pmlen + len);
622    memcpy(mem+pmlen, str, len);
623    return pmlen + len - 1;
624 }
625
626 int POOL_MEM::strcpy(const char *str)
627 {
628    int len;
629
630    if (!str) str = "";
631
632    len = strlen(str) + 1;
633    check_size(len);
634    memcpy(mem, str, len);
635    return len - 1;
636 }