]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/mem_pool.c
kes Add dynamic dll entry point for SHGetFolderPath to Win32 code.
[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    Bacula® - The Network Backup Solution
24
25    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
26
27    The main author of Bacula is Kern Sibbald, with contributions from
28    many others, a complete list can be found in the file AUTHORS.
29    This program is Free Software; you can redistribute it and/or
30    modify it under the terms of version two of the GNU General Public
31    License as published by the Free Software Foundation plus additions
32    that are listed in the file LICENSE.
33
34    This program is distributed in the hope that it will be useful, but
35    WITHOUT ANY WARRANTY; without even the implied warranty of
36    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37    General Public License for more details.
38
39    You should have received a copy of the GNU General Public License
40    along with this program; if not, write to the Free Software
41    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
42    02110-1301, USA.
43
44    Bacula® is a registered trademark of John Walker.
45    The licensor of Bacula is the Free Software Foundation Europe
46    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
47    Switzerland, email:ftf@fsfeurope.org.
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 };
94
95 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
96
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
157 /* Return the size of a memory buffer */
158 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
159 {
160    char *cp = (char *)obuf;
161
162    ASSERT(obuf);
163    cp -= HEAD_SIZE;
164    return ((struct abufhead *)cp)->ablen;
165 }
166
167 /* Realloc pool memory buffer */
168 POOLMEM *sm_realloc_pool_memory(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
169 {
170    char *cp = (char *)obuf;
171    void *buf;
172    int pool;
173
174    ASSERT(obuf);
175    P(mutex);
176    cp -= HEAD_SIZE;
177    buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
178    if (buf == NULL) {
179       V(mutex);
180       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
181    }
182    ((struct abufhead *)buf)->ablen = size;
183    pool = ((struct abufhead *)buf)->pool;
184    if (size > pool_ctl[pool].max_allocated) {
185       pool_ctl[pool].max_allocated = size;
186    }
187    V(mutex);
188    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
189 }
190
191 POOLMEM *sm_check_pool_memory_size(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
192 {
193    ASSERT(obuf);
194    if (size <= sizeof_pool_memory(obuf)) {
195       return obuf;
196    }
197    return realloc_pool_memory(obuf, size);
198 }
199
200 /* Free a memory buffer */
201 void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
202 {
203    struct abufhead *buf;
204    int pool;
205
206    ASSERT(obuf);
207    P(mutex);
208    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
209    pool = buf->pool;
210    pool_ctl[pool].in_use--;
211    if (pool == 0) {
212       free((char *)buf);              /* free nonpooled memory */
213    } else {                           /* otherwise link it to the free pool chain */
214 #ifdef DEBUG
215       struct abufhead *next;
216       /* Don't let him free the same buffer twice */
217       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
218          if (next == buf) {
219             Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
220             Dmsg4(1800, "bad free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
221             V(mutex);                 /* unblock the pool */
222             ASSERT(next != buf);      /* attempt to free twice */
223          }
224       }
225 #endif
226       buf->next = pool_ctl[pool].free_buf;
227       pool_ctl[pool].free_buf = buf;
228    }
229    Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
230    V(mutex);
231 }
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
285 /* Return the size of a memory buffer */
286 int32_t sizeof_pool_memory(POOLMEM *obuf)
287 {
288    char *cp = (char *)obuf;
289
290    ASSERT(obuf);
291    cp -= HEAD_SIZE;
292    return ((struct abufhead *)cp)->ablen;
293 }
294
295
296
297 /* Realloc pool memory buffer */
298 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
299 {
300    char *cp = (char *)obuf;
301    void *buf;
302    int pool;
303
304    ASSERT(obuf);
305    P(mutex);
306    cp -= HEAD_SIZE;
307    buf = realloc(cp, size+HEAD_SIZE);
308    if (buf == NULL) {
309       V(mutex);
310       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
311    }
312    ((struct abufhead *)buf)->ablen = size;
313    pool = ((struct abufhead *)buf)->pool;
314    if (size > pool_ctl[pool].max_allocated) {
315       pool_ctl[pool].max_allocated = size;
316    }
317    V(mutex);
318    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
319 }
320
321
322 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
323 {
324    ASSERT(obuf);
325    if (size <= sizeof_pool_memory(obuf)) {
326       return obuf;
327    }
328    return realloc_pool_memory(obuf, size);
329 }
330
331 /* Free a memory buffer */
332 void free_pool_memory(POOLMEM *obuf)
333 {
334    struct abufhead *buf;
335    int pool;
336
337    ASSERT(obuf);
338    P(mutex);
339    buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
340    pool = buf->pool;
341    pool_ctl[pool].in_use--;
342    if (pool == 0) {
343       free((char *)buf);              /* free nonpooled memory */
344    } else {                           /* otherwise link it to the free pool chain */
345 #ifdef DEBUG
346       struct abufhead *next;
347       /* Don't let him free the same buffer twice */
348       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
349          if (next == buf) {
350             V(mutex);
351             ASSERT(next != buf);  /* attempt to free twice */
352          }
353       }
354 #endif
355       buf->next = pool_ctl[pool].free_buf;
356       pool_ctl[pool].free_buf = buf;
357    }
358    Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool);
359    V(mutex);
360 }
361
362 #endif /* SMARTALLOC */
363
364
365 /*
366  * Clean up memory pool periodically
367  *
368  */
369 static time_t last_garbage_collection = 0;
370 const int garbage_interval = 24 * 60 * 60;  /* garbage collect every 24 hours */
371
372 void garbage_collect_memory_pool()
373 {
374    time_t now;
375
376    Dmsg0(200, "garbage collect memory pool\n");
377    P(mutex);
378    if (last_garbage_collection == 0) {
379       last_garbage_collection = time(NULL);
380       V(mutex);
381       return;
382    }
383    now = time(NULL);
384    if (now >= last_garbage_collection + garbage_interval) {
385       last_garbage_collection = now;
386       V(mutex);
387       close_memory_pool();
388    } else {
389       V(mutex);
390    }
391 }
392
393
394
395
396 /* Release all pooled memory */
397 void close_memory_pool()
398 {
399    struct abufhead *buf, *next;
400    int count = 0;
401    uint64_t bytes = 0;
402    char ed1[50];
403
404    sm_check(__FILE__, __LINE__, false);
405    P(mutex);
406    for (int i=1; i<=PM_MAX; i++) {
407       buf = pool_ctl[i].free_buf;
408       while (buf) {
409          next = buf->next;
410          count++;
411          bytes += sizeof_pool_memory((char *)buf);
412          free((char *)buf);
413          buf = next;
414       }
415       pool_ctl[i].free_buf = NULL;
416    }
417    Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
418    V(mutex);
419
420 }
421
422 #ifdef DEBUG
423
424 static const char *pool_name(int pool)
425 {
426    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
427    static char buf[30];
428
429    if (pool >= 0 && pool <= PM_MAX) {
430       return name[pool];
431    }
432    sprintf(buf, "%-6d", pool);
433    return buf;
434 }
435
436 /* Print staticstics on memory pool usage
437  */
438 void print_memory_pool_stats()
439 {
440    Pmsg0(-1, "Pool   Maxsize  Maxused  Inuse\n");
441    for (int i=0; i<=PM_MAX; i++)
442       Pmsg4(-1, "%5s  %7d  %7d  %5d\n", pool_name(i), pool_ctl[i].max_allocated,
443          pool_ctl[i].max_used, pool_ctl[i].in_use);
444
445    Pmsg0(-1, "\n");
446 }
447
448 #else
449 void print_memory_pool_stats() {}
450 #endif /* DEBUG */
451
452
453 /*
454  * Concatenate a string (str) onto a pool memory buffer pm
455  *   Returns: length of concatenated string
456  */
457 int pm_strcat(POOLMEM **pm, const char *str)
458 {
459    int pmlen = strlen(*pm);
460    int len = strlen(str) + 1;
461
462    *pm = check_pool_memory_size(*pm, pmlen + len);
463    memcpy(*pm+pmlen, str, len);
464    return pmlen + len - 1;
465 }
466
467 int pm_strcat(POOLMEM *&pm, const char *str)
468 {
469    int pmlen = strlen(pm);
470    int len = strlen(str) + 1;
471
472    pm = check_pool_memory_size(pm, pmlen + len);
473    memcpy(pm+pmlen, str, len);
474    return pmlen + len - 1;
475 }
476
477
478 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
479 {
480    int pmlen = strlen(pm);
481    int len = strlen(str.c_str()) + 1;
482
483    pm = check_pool_memory_size(pm, pmlen + len);
484    memcpy(pm+pmlen, str.c_str(), len);
485    return pmlen + len - 1;
486 }
487
488 int pm_strcat(POOL_MEM &pm, const char *str)
489 {
490    int pmlen = strlen(pm.c_str());
491    int len = strlen(str) + 1;
492
493    pm.check_size(pmlen + len);
494    memcpy(pm.c_str()+pmlen, str, len);
495    return pmlen + len - 1;
496 }
497
498
499 /*
500  * Copy a string (str) into a pool memory buffer pm
501  *   Returns: length of string copied
502  */
503 int pm_strcpy(POOLMEM **pm, const char *str)
504 {
505    int len = strlen(str) + 1;
506
507    *pm = check_pool_memory_size(*pm, len);
508    memcpy(*pm, str, len);
509    return len - 1;
510 }
511
512 int pm_strcpy(POOLMEM *&pm, const char *str)
513 {
514    int len = strlen(str) + 1;
515
516    pm = check_pool_memory_size(pm, len);
517    memcpy(pm, str, len);
518    return len - 1;
519 }
520
521 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
522 {
523    int len = strlen(str.c_str()) + 1;
524
525    pm = check_pool_memory_size(pm, len);
526    memcpy(pm, str.c_str(), len);
527    return len - 1;
528 }
529
530
531 int pm_strcpy(POOL_MEM &pm, const char *str)
532 {
533    int len = strlen(str) + 1;
534    pm.check_size(len);
535    memcpy(pm.c_str(), str, len);
536    return len - 1;
537 }
538
539 /* ==============  CLASS POOL_MEM   ============== */
540
541 /* Return the size of a memory buffer */
542 int32_t POOL_MEM::max_size()
543 {
544    int32_t size;
545    char *cp = mem;
546    cp -= HEAD_SIZE;
547    size = ((struct abufhead *)cp)->ablen;
548    Dmsg1(900, "max_size=%d\n", size);
549    return size;
550 }
551
552 void POOL_MEM::realloc_pm(int32_t size)
553 {
554    char *cp = mem;
555    char *buf;
556    int pool;
557
558    P(mutex);
559    cp -= HEAD_SIZE;
560    buf = (char *)realloc(cp, size+HEAD_SIZE);
561    if (buf == NULL) {
562       V(mutex);
563       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
564    }
565    Dmsg2(900, "Old buf=%p new buf=%p\n", cp, buf);
566    ((struct abufhead *)buf)->ablen = size;
567    pool = ((struct abufhead *)buf)->pool;
568    if (size > pool_ctl[pool].max_allocated) {
569       pool_ctl[pool].max_allocated = size;
570    }
571    mem = buf+HEAD_SIZE;
572    V(mutex);
573    Dmsg3(900, "Old buf=%p new buf=%p mem=%p\n", cp, buf, mem);
574 }
575
576 int POOL_MEM::strcat(const char *str)
577 {
578    int pmlen = strlen(mem);
579    int len = strlen(str) + 1;
580
581    check_size(pmlen + len);
582    memcpy(mem+pmlen, str, len);
583    return pmlen + len - 1;
584 }
585
586
587 int POOL_MEM::strcpy(const char *str)
588 {
589    int len = strlen(str) + 1;
590    check_size(len);
591    memcpy(mem, str, len);
592    return len - 1;
593 }