2 * Bacula memory pool routines.
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
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.
24 Copyright (C) 2000-2006 Kern Sibbald
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.
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.
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 */
48 /* Bacula Name length plus extra */
49 #define NLEN (MAX_NAME_LENGTH+2)
51 /* #define STRESS_TEST_POOL */
52 #ifndef STRESS_TEST_POOL
54 * Define default Pool buffer sizes
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 */
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 */
76 /* Memory allocation control structures and storage. */
78 int32_t ablen; /* Buffer length in bytes */
79 int32_t pool; /* pool */
80 struct abufhead *next; /* pointer to next free buffer */
83 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
88 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
90 POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
95 Emsg2(M_ABORT, 0, _("MemPool index %d larger than max %d\n"), pool, PM_MAX);
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;
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);
111 if ((buf = (struct abufhead *)sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
113 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
115 buf->ablen = pool_ctl[pool].size;
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;
122 Dmsg3(1800, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
123 return (POOLMEM *)((char *)buf+HEAD_SIZE);
126 /* Get nonpool memory of size requested */
127 POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size)
129 struct abufhead *buf;
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);
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);
145 /* Return the size of a memory buffer */
146 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
148 char *cp = (char *)obuf;
152 return ((struct abufhead *)cp)->ablen;
155 /* Realloc pool memory buffer */
156 POOLMEM *sm_realloc_pool_memory(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
158 char *cp = (char *)obuf;
165 buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
168 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
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;
176 return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
179 POOLMEM *sm_check_pool_memory_size(const char *fname, int lineno, POOLMEM *obuf, int32_t size)
182 if (size <= sizeof_pool_memory(obuf)) {
185 return realloc_pool_memory(obuf, size);
188 /* Free a memory buffer */
189 void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
191 struct abufhead *buf;
196 buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
198 pool_ctl[pool].in_use--;
200 free((char *)buf); /* free nonpooled memory */
201 } else { /* otherwise link it to the free pool chain */
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) {
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 */
213 buf->next = pool_ctl[pool].free_buf;
214 pool_ctl[pool].free_buf = buf;
216 Dmsg4(1800, "free_pool_memory %x pool=%d from %s:%d\n", buf, pool, fname, lineno);
223 /* ========= NO SMARTALLOC ========================================= */
225 POOLMEM *get_pool_memory(int pool)
227 struct abufhead *buf;
230 if (pool_ctl[pool].free_buf) {
231 buf = pool_ctl[pool].free_buf;
232 pool_ctl[pool].free_buf = buf->next;
234 return (POOLMEM *)((char *)buf+HEAD_SIZE);
237 if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
239 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
241 buf->ablen = pool_ctl[pool].size;
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;
249 return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
252 /* Get nonpool memory of size requested */
253 POOLMEM *get_memory(int32_t size)
255 struct abufhead *buf;
258 if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
259 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
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;
268 return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
272 /* Return the size of a memory buffer */
273 int32_t sizeof_pool_memory(POOLMEM *obuf)
275 char *cp = (char *)obuf;
279 return ((struct abufhead *)cp)->ablen;
284 /* Realloc pool memory buffer */
285 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
287 char *cp = (char *)obuf;
294 buf = realloc(cp, size+HEAD_SIZE);
297 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
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;
305 return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
309 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
312 if (size <= sizeof_pool_memory(obuf)) {
315 return realloc_pool_memory(obuf, size);
318 /* Free a memory buffer */
319 void free_pool_memory(POOLMEM *obuf)
321 struct abufhead *buf;
326 buf = (struct abufhead *)((char *)obuf - HEAD_SIZE);
328 pool_ctl[pool].in_use--;
330 free((char *)buf); /* free nonpooled memory */
331 } else { /* otherwise link it to the free pool chain */
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) {
338 ASSERT(next != buf); /* attempt to free twice */
342 buf->next = pool_ctl[pool].free_buf;
343 pool_ctl[pool].free_buf = buf;
345 Dmsg2(1800, "free_pool_memory %x pool=%d\n", buf, pool);
349 #endif /* SMARTALLOC */
353 * Clean up memory pool periodically
356 static time_t last_garbage_collection = 0;
357 const int garbage_interval = 24 * 60 * 60; /* garbage collect every 24 hours */
359 void garbage_collect_memory_pool()
363 Dmsg0(200, "garbage collect memory pool\n");
365 if (last_garbage_collection == 0) {
366 last_garbage_collection = time(NULL);
371 if (now >= last_garbage_collection + garbage_interval) {
372 last_garbage_collection = now;
383 /* Release all pooled memory */
384 void close_memory_pool()
386 struct abufhead *buf, *next;
391 sm_check(__FILE__, __LINE__, false);
393 for (int i=1; i<=PM_MAX; i++) {
394 buf = pool_ctl[i].free_buf;
398 bytes += sizeof_pool_memory((char *)buf);
402 pool_ctl[i].free_buf = NULL;
404 Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
411 static const char *pool_name(int pool)
413 static const char *name[] = {"NoPool", "NAME ", "FNAME ", "MSG ", "EMSG "};
416 if (pool >= 0 && pool <= PM_MAX) {
419 sprintf(buf, "%-6d", pool);
423 /* Print staticstics on memory pool usage
425 void print_memory_pool_stats()
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);
436 void print_memory_pool_stats() {}
441 * Concatenate a string (str) onto a pool memory buffer pm
442 * Returns: length of concatenated string
444 int pm_strcat(POOLMEM **pm, const char *str)
446 int pmlen = strlen(*pm);
447 int len = strlen(str) + 1;
449 *pm = check_pool_memory_size(*pm, pmlen + len);
450 memcpy(*pm+pmlen, str, len);
451 return pmlen + len - 1;
454 int pm_strcat(POOLMEM *&pm, const char *str)
456 int pmlen = strlen(pm);
457 int len = strlen(str) + 1;
459 pm = check_pool_memory_size(pm, pmlen + len);
460 memcpy(pm+pmlen, str, len);
461 return pmlen + len - 1;
465 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
467 int pmlen = strlen(pm);
468 int len = strlen(str.c_str()) + 1;
470 pm = check_pool_memory_size(pm, pmlen + len);
471 memcpy(pm+pmlen, str.c_str(), len);
472 return pmlen + len - 1;
475 int pm_strcat(POOL_MEM &pm, const char *str)
477 int pmlen = strlen(pm.c_str());
478 int len = strlen(str) + 1;
480 pm.check_size(pmlen + len);
481 memcpy(pm.c_str()+pmlen, str, len);
482 return pmlen + len - 1;
487 * Copy a string (str) into a pool memory buffer pm
488 * Returns: length of string copied
490 int pm_strcpy(POOLMEM **pm, const char *str)
492 int len = strlen(str) + 1;
494 *pm = check_pool_memory_size(*pm, len);
495 memcpy(*pm, str, len);
499 int pm_strcpy(POOLMEM *&pm, const char *str)
501 int len = strlen(str) + 1;
503 pm = check_pool_memory_size(pm, len);
504 memcpy(pm, str, len);
508 int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
510 int len = strlen(str.c_str()) + 1;
512 pm = check_pool_memory_size(pm, len);
513 memcpy(pm, str.c_str(), len);
518 int pm_strcpy(POOL_MEM &pm, const char *str)
520 int len = strlen(str) + 1;
522 memcpy(pm.c_str(), str, len);
526 /* ============== CLASS POOL_MEM ============== */
528 /* Return the size of a memory buffer */
529 int32_t POOL_MEM::max_size()
534 size = ((struct abufhead *)cp)->ablen;
535 Dmsg1(900, "max_size=%d\n", size);
539 void POOL_MEM::realloc_pm(int32_t size)
547 buf = (char *)realloc(cp, size+HEAD_SIZE);
550 Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
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;
560 Dmsg3(900, "Old buf=0x%x new buf=0x%x mem=0x%x\n", cp, buf, mem);
563 int POOL_MEM::strcat(const char *str)
565 int pmlen = strlen(mem);
566 int len = strlen(str) + 1;
568 check_size(pmlen + len);
569 memcpy(mem+pmlen, str, len);
570 return pmlen + len - 1;
574 int POOL_MEM::strcpy(const char *str)
576 int len = strlen(str) + 1;
578 memcpy(mem, str, len);