]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
More changes to ensure that during thread switches the jcr
[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
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    if (obuf == NULL) {
164       Emsg0(M_ABORT, 0, _("obuf is NULL\n"));
165    }
166    cp -= HEAD_SIZE;
167    return ((struct abufhead *)cp)->ablen;
168 }
169
170 /* Realloc pool memory buffer */
171 POOLMEM *sm_realloc_pool_memory(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
172 {
173    char *cp = (char *)obuf;
174    void *buf;
175    int pool;
176
177    ASSERT(obuf);
178    P(mutex);
179    cp -= HEAD_SIZE;
180    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
181    if (buf == NULL) {
182       V(mutex);
183       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
184    }
185    ((struct abufhead *)buf)->ablen = size;
186    pool = ((struct abufhead *)buf)->pool;
187    if (size > pool_ctl[pool].max_allocated) {
188       pool_ctl[pool].max_allocated = size;
189    }
190    V(mutex);
191    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
192 }
193
194 POOLMEM *sm_check_pool_memory_size(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
195 {
196    ASSERT(obuf);
197    if (size <= sizeof_pool_memory(obuf)) {
198       return obuf;
199    }
200    return realloc_pool_memory(obuf, size);
201 }
202
203 /* Free a memory buffer */
204 void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
205 {
206    struct abufhead *buf;
207    int pool;
208
209    ASSERT(obuf);
210    P(mutex);
211    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
212    pool = buf->pool;
213    pool_ctl[pool].in_use--;
214    if (pool == 0) {
215       free((char *)buf);              /* free nonpooled memory */
216    } else {                           /* otherwise link it to the free pool chain */
217 #ifdef DEBUG
218       struct abufhead *next;
219       /* Don't let him free the same buffer twice */
220       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
221          if (next == buf) {
222             Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
223             Dmsg4(1800, "bad free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
224             V(mutex);                 /* unblock the pool */
225             ASSERT(next != buf);      /* attempt to free twice */
226          }
227       }
228 #endif
229       buf->next = pool_ctl[pool].free_buf;
230       pool_ctl[pool].free_buf = buf;
231    }
232    Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
233    V(mutex);
234 }
235
236
237 #else
238
239 /* =========  NO SMARTALLOC  =========================================  */
240
241 POOLMEM *get_pool_memory(int pool)
242 {
243    struct abufhead *buf;
244
245    P(mutex);
246    if (pool_ctl[pool].free_buf) {
247       buf = pool_ctl[pool].free_buf;
248       pool_ctl[pool].free_buf = buf->next;
249       V(mutex);
250       return (POOLMEM *)((char *)buf+HEAD_SIZE);
251    }
252
253    if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
254       V(mutex);
255       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
256    }
257    buf->ablen = pool_ctl[pool].size;
258    buf->pool = pool;
259    buf->next = NULL;
260    pool_ctl[pool].in_use++;
261    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
262       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
263    }
264    V(mutex);
265    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
266 }
267
268 /* Get nonpool memory of size requested */
269 POOLMEM *get_memory(int32_t size)
270 {
271    struct abufhead *buf;
272    int pool = 0;
273
274    if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
275       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
276    }
277    buf->ablen = size;
278    buf->pool = pool;
279    buf->next = NULL;
280    pool_ctl[pool].in_use++;
281    if (pool_ctl[pool].in_use > pool_ctl[pool].max_used) {
282       pool_ctl[pool].max_used = pool_ctl[pool].in_use;
283    }
284    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
285 }
286
287
288 /* Return the size of a memory buffer */
289 int32_t sizeof_pool_memory(POOLMEM *obuf)
290 {
291    char *cp = (char *)obuf;
292
293    ASSERT(obuf);
294    cp -= HEAD_SIZE;
295    return ((struct abufhead *)cp)->ablen;
296 }
297
298
299
300 /* Realloc pool memory buffer */
301 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
302 {
303    char *cp = (char *)obuf;
304    void *buf;
305    int pool;
306
307    ASSERT(obuf);
308    P(mutex);
309    cp -= HEAD_SIZE;
310    buf = realloc(cp, size+HEAD_SIZE);
311    if (buf == NULL) {
312       V(mutex);
313       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
314    }
315    ((struct abufhead *)buf)->ablen = size;
316    pool = ((struct abufhead *)buf)->pool;
317    if (size > pool_ctl[pool].max_allocated) {
318       pool_ctl[pool].max_allocated = size;
319    }
320    V(mutex);
321    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
322 }
323
324
325 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
326 {
327    ASSERT(obuf);
328    if (size <= sizeof_pool_memory(obuf)) {
329       return obuf;
330    }
331    return realloc_pool_memory(obuf, size);
332 }
333
334 /* Free a memory buffer */
335 void free_pool_memory(POOLMEM *obuf)
336 {
337    struct abufhead *buf;
338    int pool;
339
340    ASSERT(obuf);
341    P(mutex);
342    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
343    pool = buf->pool;
344    pool_ctl[pool].in_use--;
345    if (pool == 0) {
346       free((char *)buf);              /* free nonpooled memory */
347    } else {                           /* otherwise link it to the free pool chain */
348 #ifdef DEBUG
349       struct abufhead *next;
350       /* Don't let him free the same buffer twice */
351       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
352          if (next == buf) {
353             V(mutex);
354             ASSERT(next != buf);  /* attempt to free twice */
355          }
356       }
357 #endif
358       buf->next = pool_ctl[pool].free_buf;
359       pool_ctl[pool].free_buf = buf;
360    }
361    Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool);
362    V(mutex);
363 }
364
365 #endif /* SMARTALLOC */
366
367
368 /*
369  * Clean up memory pool periodically
370  *
371  */
372 static time_t last_garbage_collection = 0;
373 const int garbage_interval = 24 * 60 * 60;  /* garbage collect every 24 hours */
374
375 void garbage_collect_memory_pool()
376 {
377    time_t now;
378
379    Dmsg0(200, "garbage collect memory pool\n");
380    P(mutex);
381    if (last_garbage_collection == 0) {
382       last_garbage_collection = time(NULL);
383       V(mutex);
384       return;
385    }
386    now = time(NULL);
387    if (now >= last_garbage_collection + garbage_interval) {
388       last_garbage_collection = now;
389       V(mutex);
390       close_memory_pool();
391    } else {
392       V(mutex);
393    }
394 }
395
396
397
398
399 /* Release all pooled memory */
400 void close_memory_pool()
401 {
402    struct abufhead *buf, *next;
403    int count = 0;
404    uint64_t bytes = 0;
405    char ed1[50];
406
407    sm_check(__FILE__, __LINE__, false);
408    P(mutex);
409    for (int i=1; i<=PM_MAX; i++) {
410       buf = pool_ctl[i].free_buf;
411       while (buf) {
412          next = buf->next;
413          count++;
414          bytes += sizeof_pool_memory((char *)buf);
415          free((char *)buf);
416          buf = next;
417       }
418       pool_ctl[i].free_buf = NULL;
419    }
420    Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
421    V(mutex);
422
423 }
424
425 #ifdef DEBUG
426
427 static const char *pool_name(int pool)
428 {
429    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
430    static char buf[30];
431
432    if (pool >= 0 && pool <= PM_MAX) {
433       return name[pool];
434    }
435    sprintf(buf, "%-6d", pool);
436    return buf;
437 }
438
439 /* Print staticstics on memory pool usage
440  */
441 void print_memory_pool_stats()
442 {
443    Pmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
444    for (int i=0; i<=PM_MAX; i++)
445       Pmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_allocated,
446          pool_ctl[i].max_used, pool_ctl[i].in_use);
447
448    Pmsg0(-1, "\n");
449 }
450
451 #else
452 void print_memory_pool_stats() {}
453 #endif /* DEBUG */
454
455
456 /*
457  * Concatenate a string (str) onto a pool memory buffer pm
458  *   Returns: length of concatenated string
459  */
460 int pm_strcat(POOLMEM **pm, const char *str)
461 {
462    int pmlen = strlen(*pm);
463    int len;
464
465    if (!str) str = "";
466
467    len = strlen(str) + 1;
468    *pm = check_pool_memory_size(*pm, pmlen + len);
469    memcpy(*pm+pmlen, str, len);
470    return pmlen + len - 1;
471 }
472
473 int pm_strcat(POOLMEM *&pm, const char *str)
474 {
475    int pmlen = strlen(pm);
476    int len;
477
478    if (!str) str = "";
479
480    len = strlen(str) + 1;
481    pm = check_pool_memory_size(pm, pmlen + len);
482    memcpy(pm+pmlen, str, len);
483    return pmlen + len - 1;
484 }
485
486
487 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
488 {
489    int pmlen = strlen(pm);
490    int len = strlen(str.c_str()) + 1;
491
492    pm = check_pool_memory_size(pm, pmlen + len);
493    memcpy(pm+pmlen, str.c_str(), len);
494    return pmlen + len - 1;
495 }
496
497 int pm_strcat(POOL_MEM &pm, const char *str)
498 {
499    int pmlen = strlen(pm.c_str());
500    int len;
501
502    if (!str) str = "";
503
504    len = strlen(str) + 1;
505    pm.check_size(pmlen + len);
506    memcpy(pm.c_str()+pmlen, str, len);
507    return pmlen + len - 1;
508 }
509
510
511 /*
512  * Copy a string (str) into a pool memory buffer pm
513  *   Returns: length of string copied
514  */
515 int pm_strcpy(POOLMEM **pm, const char *str)
516 {
517    int len;
518
519    if (!str) str = "";
520
521    len = strlen(str) + 1;
522    *pm = check_pool_memory_size(*pm, len);
523    memcpy(*pm, str, len);
524    return len - 1;
525 }
526
527 int pm_strcpy(POOLMEM *&pm, const char *str)
528 {
529    int len;
530
531    if (!str) str = "";
532
533    len = strlen(str) + 1;
534    pm = check_pool_memory_size(pm, len);
535    memcpy(pm, str, len);
536    return len - 1;
537 }
538
539 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
540 {
541    int len = strlen(str.c_str()) + 1;
542
543    pm = check_pool_memory_size(pm, len);
544    memcpy(pm, str.c_str(), len);
545    return len - 1;
546 }
547
548
549 int pm_strcpy(POOL_MEM &pm, const char *str)
550 {
551    int len;
552
553    if (!str) str = "";
554
555    len = strlen(str) + 1;
556    pm.check_size(len);
557    memcpy(pm.c_str(), str, len);
558    return len - 1;
559 }
560
561 /* ==============  CLASS POOL_MEM   ============== */
562
563 /* Return the size of a memory buffer */
564 int32_t POOL_MEM::max_size()
565 {
566    int32_t size;
567    char *cp = mem;
568    cp -= HEAD_SIZE;
569    size = ((struct abufhead *)cp)->ablen;
570    Dmsg1(900, "max_size=%d\n", size);
571    return size;
572 }
573
574 void POOL_MEM::realloc_pm(int32_t size)
575 {
576    char *cp = mem;
577    char *buf;
578    int pool;
579
580    P(mutex);
581    cp -= HEAD_SIZE;
582    buf = (char *)realloc(cp, size+HEAD_SIZE);
583    if (buf == NULL) {
584       V(mutex);
585       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
586    }
587    Dmsg2(900, "Old buf=%p new buf=%p\n", cp, buf);
588    ((struct abufhead *)buf)->ablen = size;
589    pool = ((struct abufhead *)buf)->pool;
590    if (size > pool_ctl[pool].max_allocated) {
591       pool_ctl[pool].max_allocated = size;
592    }
593    mem = buf+HEAD_SIZE;
594    V(mutex);
595    Dmsg3(900, "Old buf=%p new buf=%p mem=%p\n", cp, buf, mem);
596 }
597
598 int POOL_MEM::strcat(const char *str)
599 {
600    int pmlen = strlen(mem);
601    int len;
602
603    if (!str) str = "";
604
605    len = strlen(str) + 1;
606    check_size(pmlen + len);
607    memcpy(mem+pmlen, str, len);
608    return pmlen + len - 1;
609 }
610
611
612 int POOL_MEM::strcpy(const char *str)
613 {
614    int len;
615
616    if (!str) str = "";
617
618    len = strlen(str) + 1;
619    check_size(len);
620    memcpy(mem, str, len);
621    return len - 1;
622 }