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