]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/lib/mem_pool.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / lib / mem_pool.c
index e36f63df6a4b9c6e70b5043b3e5017bf2a5fb767..a29e68ef38bf2fb302e0176f373097141dcb67b8 100644 (file)
@@ -1,29 +1,20 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2007 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 two of the GNU 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 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(R) - The Network Backup Solution
+
+   Copyright (C) 2000-2017 Kern Sibbald
+
+   The original author of Bacula is Kern Sibbald, with contributions
+   from many others, a complete list can be found in the file AUTHORS.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
+
+   This notice must be preserved when any source code is 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
  *  Bacula memory pool routines.
  *
  *           Kern E. Sibbald
  *
- *   Version $Id$
  */
 
 #include "bacula.h"
+#define dbglvl DT_MEMORY|800
+
+#ifdef HAVE_MALLOC_TRIM
+extern "C" int malloc_trim (size_t pad);
+#endif
 
 struct s_pool_ctl {
    int32_t size;                      /* default size */
@@ -70,7 +65,8 @@ static struct s_pool_ctl pool_ctl[] = {
    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
    {  256,  256, 0, 0, NULL },        /* PM_FNAME filename buffers */
    {  512,  512, 0, 0, NULL },        /* PM_MESSAGE message buffer */
-   { 1024, 1024, 0, 0, NULL }         /* PM_EMSG error message buffer */
+   { 1024, 1024, 0, 0, NULL },        /* PM_EMSG error message buffer */
+  {  4096, 4096, 0, 0, NULL }         /* PM_BSOCK message buffer */
 };
 #else
 
@@ -80,7 +76,8 @@ static struct s_pool_ctl pool_ctl[] = {
    {  NLEN, NLEN,0, 0, NULL },        /* PM_NAME Bacula name */
    {   20,   20, 0, 0, NULL },        /* PM_FNAME filename buffers */
    {   20,   20, 0, 0, NULL },        /* PM_MESSAGE message buffer */
-   {   20,   20, 0, 0, NULL }         /* PM_EMSG error message buffer */
+   {   20,   20, 0, 0, NULL },        /* PM_EMSG error message buffer */
+   {   20,   20, 0, 0, NULL }         /* PM_BSOCK message buffer */
 };
 #endif
 
@@ -91,14 +88,15 @@ struct abufhead {
    int32_t pool;                      /* pool */
    struct abufhead *next;             /* pointer to next free buffer */
    int32_t bnet_size;                 /* dummy for bnet_send() */
+   int32_t bnet_extension;            /* dummy for bnet extension */
 };
 
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
-#ifdef SMARTALLOC
-
 #define HEAD_SIZE BALIGN(sizeof(struct abufhead))
 
+#ifdef SMARTALLOC
+
 POOLMEM *sm_get_pool_memory(const char *fname, int lineno, int pool)
 {
    struct abufhead *buf;
@@ -115,7 +113,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(1800, "sm_get_pool_memory reuse %p to %s:%d\n", buf, fname, lineno);
+      Dmsg3(dbglvl, "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);
    }
@@ -131,7 +129,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(1800, "sm_get_pool_memory give %p to %s:%d\n", buf, fname, lineno);
+   Dmsg3(dbglvl, "sm_get_pool_memory give %p to %s:%d\n", buf, fname, lineno);
    return (POOLMEM *)((char *)buf+HEAD_SIZE);
 }
 
@@ -212,13 +210,15 @@ void sm_free_pool_memory(const char *fname, int lineno, POOLMEM *obuf)
    if (pool == 0) {
       free((char *)buf);              /* free nonpooled memory */
    } else {                           /* otherwise link it to the free pool chain */
-#ifdef DEBUG
+
+   /* Disabled because it hangs in #5507 */
+#ifdef xDEBUG
       struct abufhead *next;
       /* Don't let him free the same buffer twice */
       for (next=pool_ctl[pool].free_buf; next; next=next->next) {
          if (next == buf) {
-            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);
+            Dmsg4(dbglvl, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
+            Dmsg4(dbglvl, "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 */
          }
@@ -227,7 +227,7 @@ 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(1800, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
+   Dmsg4(dbglvl, "free_pool_memory %p pool=%d from %s:%d\n", buf, pool, fname, lineno);
    V(mutex);
 }
 
@@ -247,7 +247,7 @@ POOLMEM *get_pool_memory(int pool)
       return (POOLMEM *)((char *)buf+HEAD_SIZE);
    }
 
-   if ((buf=malloc(pool_ctl[pool].size+HEAD_SIZE)) == NULL) {
+   if ((buf=(struct abufhead*)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);
    }
@@ -268,7 +268,7 @@ POOLMEM *get_memory(int32_t size)
    struct abufhead *buf;
    int pool = 0;
 
-   if ((buf=malloc(size+HEAD_SIZE)) == NULL) {
+   if ((buf=(struct abufhead *)malloc(size+HEAD_SIZE)) == NULL) {
       Emsg1(M_ABORT, 0, _("Out of memory requesting %d bytes\n"), size);
    }
    buf->ablen = size;
@@ -351,7 +351,7 @@ void free_pool_memory(POOLMEM *obuf)
       buf->next = pool_ctl[pool].free_buf;
       pool_ctl[pool].free_buf = buf;
    }
-   Dmsg2(1800, "free_pool_memory %p pool=%d\n", buf, pool);
+   Dmsg2(dbglvl, "free_pool_memory %p pool=%d\n", buf, pool);
    V(mutex);
 }
 #endif /* SMARTALLOC */
@@ -375,16 +375,17 @@ void garbage_collect_memory_pool()
       return;
    }
    now = time(NULL);
-   if (now >= last_garbage_collection + garbage_interval) {
+   if (now >= last_garbage_collection + garbage_interval ||
+       sm_bytes > 500000) {
       last_garbage_collection = now;
       V(mutex);
-      close_memory_pool();
+      garbage_collect_memory();
    } else {
       V(mutex);
    }
 }
 
-/* Release all pooled memory */
+/* Release all freed pooled memory */
 void close_memory_pool()
 {
    struct abufhead *buf, *next;
@@ -405,15 +406,33 @@ void close_memory_pool()
       }
       pool_ctl[i].free_buf = NULL;
    }
-   Dmsg2(100, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
+   Dmsg2(DT_MEMORY|001, "Freed mem_pool count=%d size=%s\n", count, edit_uint64_with_commas(bytes, ed1));
+   if (chk_dbglvl(DT_MEMORY|1)) {
+      print_memory_pool_stats();
+   }
    V(mutex);
 
 }
 
+/*
+ * Garbage collect and trim memory if possible
+ *  This should be called after all big memory usages
+ *  if possible.
+ */
+void garbage_collect_memory()
+{
+   close_memory_pool();         /* release free chain */
+#ifdef HAVE_MALLOC_TRIM
+   P(mutex);
+   malloc_trim(8192);
+   V(mutex);
+#endif
+}
+
 #ifdef DEBUG
 static const char *pool_name(int pool)
 {
-   static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  "};
+   static const char *name[] = {"NoPool", "NAME  ", "FNAME ", "MSG   ", "EMSG  ", "BSOCK "};
    static char buf[30];
 
    if (pool >= 0 && pool <= PM_MAX) {
@@ -492,6 +511,17 @@ int pm_strcat(POOL_MEM &pm, const char *str)
    return pmlen + len - 1;
 }
 
+int pm_strcat(POOL_MEM &pm, POOL_MEM &str)
+{
+   int pmlen = strlen(pm.c_str());
+   int len;
+
+   len = strlen(str.c_str()) + 1;
+   pm.check_size(pmlen + len);
+   memcpy(pm.c_str()+pmlen, str.c_str(), len);
+   return pmlen + len - 1;
+}
+
 /*
  * Copy a string (str) into a pool memory buffer pm
  *   Returns: length of string copied
@@ -545,28 +575,28 @@ int pm_strcpy(POOL_MEM &pm, const char *str)
  * Copy data into a pool memory buffer pm
  *   Returns: length of data copied
  */
-int pm_memcpy(POOLMEM **pm, const void *data, size_t 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, const void *data, size_t 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, size_t 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 void *data, size_t n)
+int pm_memcpy(POOL_MEM &pm, const char *data, int32_t n)
 {
    pm.check_size(n);
    memcpy(pm.c_str(), data, n);