]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/mem_pool.c
Add pool memory debug output
[bacula/bacula] / bacula / src / lib / mem_pool.c
index 0a2624243c2afc1c804cd7b87cf39426f1b1a80d..a371fdd737f746b5dbbc1cef0064bfbdc251d435 100644 (file)
@@ -1,10 +1,37 @@
 /*
- *  Bacula memory pool routines. 
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version three of the GNU Affero General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   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 Affero General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ *  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
  *
  *           Kern E. Sibbald
  *
- *   Version $Id$
- */
-
-/*
-   Copyright (C) 2000-2004 Kern Sibbald and John Walker
-
-   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.
-
-   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.
-
  */
 
 #include "bacula.h"
@@ -83,11 +89,11 @@ struct abufhead {
    int32_t ablen;                     /* Buffer length in bytes */
    int32_t pool;                      /* pool */
    struct abufhead *next;             /* pointer to next free buffer */
+   int32_t bnet_size;                 /* dummy for bnet_send() */
 };
 
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
-
 #ifdef SMARTALLOC
 
 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
@@ -97,7 +103,7 @@ POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
    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) {
@@ -108,14 +114,14 @@ POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
          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;
@@ -124,7 +130,7 @@ POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int 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);
 }
 
@@ -135,7 +141,7 @@ POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t 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;
@@ -146,13 +152,14 @@ POOLMEM *sm_get_memory(const char *fname, int lineno, int32_t size)
    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
 }
 
-
 /* Return the size of a memory buffer */
 int32_t sm_sizeof_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
 {
    char *cp = (char *)obuf;
 
-   ASSERT(obuf);
+   if (obuf == NULL) {
+      Emsg0(M_ABORT, 0, _("obuf is NULL\n"));
+   }
    cp -= HEAD_SIZE;
    return ((struct abufhead *)cp)->ablen;
 }
@@ -170,7 +177,7 @@ POOLMEM *sm_realloc_pool_memory(const char *fname, int lineno, POOLMEM *obuf, in
    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;
@@ -209,7 +216,8 @@ void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
       /* 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 */
          }
@@ -218,11 +226,10 @@ void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
       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);
 }
 
-
 #else
 
 /* =========  NO SMARTALLOC  =========================================  */
@@ -238,10 +245,10 @@ POOLMEM *get_pool_memory(int pool)
       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;
@@ -261,7 +268,7 @@ POOLMEM *get_memory(int32_t size)
    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;
@@ -273,7 +280,6 @@ POOLMEM *get_memory(int32_t size)
    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
 }
 
-
 /* Return the size of a memory buffer */
 int32_t sizeof_pool_memory(POOLMEM *obuf)
 {
@@ -284,8 +290,6 @@ int32_t sizeof_pool_memory(POOLMEM *obuf)
    return ((struct abufhead *)cp)->ablen;
 }
 
-
-
 /* Realloc pool memory buffer */
 POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
 {
@@ -299,7 +303,7 @@ POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
    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;
@@ -310,7 +314,6 @@ POOLMEM *realloc_pool_memory(POOLMEM *obuf, int32_t size)
    return (POOLMEM *)(((char *)buf)+HEAD_SIZE);
 }
 
-
 POOLMEM *check_pool_memory_size(POOLMEM *obuf, int32_t size)
 {
    ASSERT(obuf);
@@ -347,21 +350,46 @@ void free_pool_memory(POOLMEM *obuf)
       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);
+   }
+}
 
 /* Release all pooled memory */
 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);
@@ -369,16 +397,22 @@ void close_memory_pool()
       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(001, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
+   if (debug_level >= 1) {
+      print_memory_pool_stats();
+   }
    V(mutex);
+
 }
 
 #ifdef DEBUG
-
 static const char *pool_name(int pool)
 {
    static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
@@ -390,24 +424,23 @@ static const char *pool_name(int pool)
    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 */
 
-
 /*
  * Concatenate a string (str) onto a pool memory buffer pm
  *   Returns: length of concatenated string
@@ -415,8 +448,11 @@ void print_memory_pool_stats() {}
 int pm_strcat(POOLMEM **pm, const char *str)
 {
    int pmlen = strlen(*pm);
-   int len = strlen(str) + 1;
+   int len;
+
+   if (!str) str = "";
 
+   len = strlen(str) + 1;
    *pm = check_pool_memory_size(*pm, pmlen + len);
    memcpy(*pm+pmlen, str, len);
    return pmlen + len - 1;
@@ -425,14 +461,16 @@ int pm_strcat(POOLMEM **pm, const char *str)
 int pm_strcat(POOLMEM *&pm, const char *str)
 {
    int pmlen = strlen(pm);
-   int len = strlen(str) + 1;
+   int len;
 
+   if (!str) str = "";
+
+   len = strlen(str) + 1;
    pm = check_pool_memory_size(pm, pmlen + len);
    memcpy(pm+pmlen, str, len);
    return pmlen + len - 1;
 }
 
-
 int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
 {
    int pmlen = strlen(pm);
@@ -446,22 +484,27 @@ int pm_strcat(POOLMEM *&pm, POOL_MEM &str)
 int pm_strcat(POOL_MEM &pm, const char *str)
 {
    int pmlen = strlen(pm.c_str());
-   int len = strlen(str) + 1;
+   int len;
+
+   if (!str) str = "";
 
+   len = strlen(str) + 1;
    pm.check_size(pmlen + len);
    memcpy(pm.c_str()+pmlen, str, len);
    return pmlen + len - 1;
 }
 
-
 /*
  * Copy a string (str) into a pool memory buffer pm
  *   Returns: length of string copied
  */
 int pm_strcpy(POOLMEM **pm, const char *str)
 {
-   int len = strlen(str) + 1;
+   int len;
+
+   if (!str) str = "";
 
+   len = strlen(str) + 1;
    *pm = check_pool_memory_size(*pm, len);
    memcpy(*pm, str, len);
    return len - 1;
@@ -469,8 +512,11 @@ int pm_strcpy(POOLMEM **pm, const char *str)
 
 int pm_strcpy(POOLMEM *&pm, const char *str)
 {
-   int len = strlen(str) + 1;
+   int len;
 
+   if (!str) str = "";
+
+   len = strlen(str) + 1;
    pm = check_pool_memory_size(pm, len);
    memcpy(pm, str, len);
    return len - 1;
@@ -485,15 +531,50 @@ int pm_strcpy(POOLMEM *&pm, POOL_MEM &str)
    return len - 1;
 }
 
-
 int pm_strcpy(POOL_MEM &pm, const char *str)
-{  
-   int len = strlen(str) + 1;
+{
+   int len;
+
+   if (!str) str = "";
+
+   len = strlen(str) + 1;
    pm.check_size(len);
    memcpy(pm.c_str(), str, len);
    return len - 1;
 }
 
+/*
+ * Copy data into a pool memory buffer pm
+ *   Returns: length of data copied
+ */
+int pm_memcpy(POOLMEM **pm, const char *data, int32_t n)
+{
+   *pm = check_pool_memory_size(*pm, n);
+   memcpy(*pm, data, n);
+   return n;
+}
+
+int pm_memcpy(POOLMEM *&pm, const char *data, int32_t n)
+{
+   pm = check_pool_memory_size(pm, n);
+   memcpy(pm, data, n);
+   return n;
+}
+
+int pm_memcpy(POOLMEM *&pm, POOL_MEM &data, int32_t n)
+{
+   pm = check_pool_memory_size(pm, n);
+   memcpy(pm, data.c_str(), n);
+   return n;
+}
+
+int pm_memcpy(POOL_MEM &pm, const char *data, int32_t n)
+{
+   pm.check_size(n);
+   memcpy(pm.c_str(), data, n);
+   return n;
+}
+
 /* ==============  CLASS POOL_MEM   ============== */
 
 /* Return the size of a memory buffer */
@@ -503,7 +584,7 @@ int32_t POOL_MEM::max_size()
    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;
 }
 
@@ -518,9 +599,9 @@ void POOL_MEM::realloc_pm(int32_t 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) {
@@ -528,23 +609,29 @@ void POOL_MEM::realloc_pm(int32_t size)
    }
    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 pmlen = strlen(mem);
-   int len = strlen(str) + 1;
+   int len;
+
+   if (!str) str = "";
 
+   len = strlen(str) + 1;
    check_size(pmlen + len);
    memcpy(mem+pmlen, str, len);
    return pmlen + len - 1;
 }
 
-
 int POOL_MEM::strcpy(const char *str)
-{  
-   int len = strlen(str) + 1;
+{
+   int len;
+
+   if (!str) str = "";
+
+   len = strlen(str) + 1;
    check_size(len);
    memcpy(mem, str, len);
    return len - 1;