/*
- * Bacula memory pool routines.
+ * Bacula memory pool routines.
*
* The idea behind these routines is that there will be
* pools of memory that are pre-allocated for quick
* access. The pools will have a fixed memory size on allocation
- * but if need be, the size can be increased. This is
+ * but if need be, the size can be increased. This is
* particularly useful for filename
* buffers where 256 bytes should be sufficient in 99.99%
* of the cases, but when it isn't we want to be able to
*/
/*
- Copyright (C) 2000-2004 Kern Sibbald and John Walker
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of
- the License, or (at your option) any later version.
+ modify it under the terms of the GNU General Public License
+ version 2 as amended with additional clauses defined in the
+ file LICENSE in the main source directory.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ the file LICENSE for additional details.
*/
struct abufhead *buf;
if (pool > PM_MAX) {
- Emsg2(M_ABORT, 0, "MemPool index %d larger than max %d\n", pool, PM_MAX);
+ Emsg2(M_ABORT, 0, _("MemPool index %d larger than max %d\n"), pool, PM_MAX);
}
P(mutex);
if (pool_ctl[pool].free_buf) {
pool_ctl[pool].max_used = pool_ctl[pool].in_use;
}
V(mutex);
- Dmsg3(300, "sm_get_pool_memory reuse %x to %s:%d\n", buf, fname, lineno);
+ Dmsg3(1800, "sm_get_pool_memory reuse %p to %s:%d\n", buf, fname, lineno);
sm_new_owner(fname, lineno, (char *)buf);
return (POOLMEM *)((char *)buf+HEAD_SIZE);
}
-
+
if ((buf = (struct abufhead *)sm_malloc(fname, lineno, pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
V(mutex);
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
}
buf->ablen = pool_ctl[pool].size;
buf->pool = pool;
pool_ctl[pool].max_used = pool_ctl[pool].in_use;
}
V(mutex);
- Dmsg3(300, "sm_get_pool_memory give %x to %s:%d\n", buf, fname, lineno);
+ Dmsg3(1800, "sm_get_pool_memory give %p to %s:%d\n", buf, fname, lineno);
return (POOLMEM *)((char *)buf+HEAD_SIZE);
}
int pool = 0;
if ((buf = (struct abufhead *)sm_malloc(fname, lineno, size+HEAD_SIZE)) == NULL) {
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
}
buf->ablen = size;
buf->pool = pool;
buf = sm_realloc(fname, lineno, cp, size+HEAD_SIZE);
if (buf == NULL) {
V(mutex);
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
}
((struct abufhead *)buf)->ablen = size;
pool = ((struct abufhead *)buf)->pool;
/* Don't let him free the same buffer twice */
for (next=pool_ctl[pool].free_buf; next; next=next->next) {
if (next == buf) {
- Dmsg4(300, "bad free_pool_memory %x pool=%d from %s:%d\n", buf, pool, fname, lineno);
+ Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
+ Dmsg4(1800, "bad free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
V(mutex); /* unblock the pool */
ASSERT(next != buf); /* attempt to free twice */
}
buf->next = pool_ctl[pool].free_buf;
pool_ctl[pool].free_buf = buf;
}
- Dmsg4(300, "free_pool_memory %x pool=%d from %s:%d\n", buf, pool, fname, lineno);
+ Dmsg4(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
V(mutex);
}
V(mutex);
return (POOLMEM *)((char *)buf+HEAD_SIZE);
}
-
+
if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
V(mutex);
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", pool_ctl[pool].size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), pool_ctl[pool].size);
}
buf->ablen = pool_ctl[pool].size;
buf->pool = pool;
int pool = 0;
if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
}
buf->ablen = size;
buf->pool = pool;
buf = realloc(cp, size+HEAD_SIZE);
if (buf == NULL) {
V(mutex);
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
}
((struct abufhead *)buf)->ablen = size;
pool = ((struct abufhead *)buf)->pool;
buf->next = pool_ctl[pool].free_buf;
pool_ctl[pool].free_buf = buf;
}
- Dmsg2(300, "free_pool_memory %x pool=%d\n", buf, pool);
+ Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool);
V(mutex);
}
#endif /* SMARTALLOC */
+/*
+ * Clean up memory pool periodically
+ *
+ */
+static time_t last_garbage_collection = 0;
+const int garbage_interval = 24 * 60 * 60; /* garbage collect every 24 hours */
+
+void garbage_collect_memory_pool()
+{
+ time_t now;
+
+ Dmsg0(200, "garbage collect memory pool\n");
+ P(mutex);
+ if (last_garbage_collection == 0) {
+ last_garbage_collection = time(NULL);
+ V(mutex);
+ return;
+ }
+ now = time(NULL);
+ if (now >= last_garbage_collection + garbage_interval) {
+ last_garbage_collection = now;
+ V(mutex);
+ close_memory_pool();
+ } else {
+ V(mutex);
+ }
+}
void close_memory_pool()
{
struct abufhead *buf, *next;
+ int count = 0;
+ uint64_t bytes = 0;
+ char ed1[50];
sm_check(__FILE__, __LINE__, false);
P(mutex);
buf = pool_ctl[i].free_buf;
while (buf) {
next = buf->next;
+ count++;
+ bytes += sizeof_pool_memory((char *)buf);
free((char *)buf);
buf = next;
}
pool_ctl[i].free_buf = NULL;
}
+ Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
V(mutex);
+
}
#ifdef DEBUG
sprintf(buf, "%-6d", pool);
return buf;
}
-
-/* Print staticstics on memory pool usage
- */
+
+/* Print staticstics on memory pool usage
+ */
void print_memory_pool_stats()
{
- Dmsg0(-1, "Pool Maxsize Maxused Inuse\n");
+ Pmsg0(-1, "Pool Maxsize Maxused Inuse\n");
for (int i=0; i<=PM_MAX; i++)
- Dmsg4(-1, "%5s %7d %7d %5d\n", pool_name(i), pool_ctl[i].max_allocated,
+ Pmsg4(-1, "%5s %7d %7d %5d\n", pool_name(i), pool_ctl[i].max_allocated,
pool_ctl[i].max_used, pool_ctl[i].in_use);
- Dmsg0(-1, "\n");
+ Pmsg0(-1, "\n");
}
#else
-void print_memory_pool_stats() {}
+void print_memory_pool_stats() {}
#endif /* DEBUG */
int pm_strcpy(POOL_MEM &pm, const char *str)
-{
+{
int len = strlen(str) + 1;
pm.check_size(len);
memcpy(pm.c_str(), str, len);
char *cp = mem;
cp -= HEAD_SIZE;
size = ((struct abufhead *)cp)->ablen;
- Dmsg1(000, "max_size=%d\n", size);
+ Dmsg1(900, "max_size=%d\n", size);
return size;
}
buf = (char *)realloc(cp, size+HEAD_SIZE);
if (buf == NULL) {
V(mutex);
- Emsg1(M_ABORT, 0, "Out of memory requesting %d bytes\n", size);
+ Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
}
- Dmsg2(000, "Old buf=0x%x new buf=0x%x\n", cp, buf);
+ Dmsg2(900, "Old buf=%p new buf=%p\n", cp, buf);
((struct abufhead *)buf)->ablen = size;
pool = ((struct abufhead *)buf)->pool;
if (size > pool_ctl[pool].max_allocated) {
}
mem = buf+HEAD_SIZE;
V(mutex);
- Dmsg3(000, "Old buf=0x%x new buf=0x%x mem=0x%x\n", cp, buf, mem);
+ Dmsg3(900, "Old buf=%p new buf=%p mem=%p\n", cp, buf, mem);
}
int POOL_MEM::strcat(const char *str)
int POOL_MEM::strcpy(const char *str)
-{
+{
int len = strlen(str) + 1;
check_size(len);
memcpy(mem, str, len);