MEDIUM: memory: add accounting for failed allocations

We now keep a per-pool counter of failed memory allocations and
we report that, as well as the amount of memory allocated and used
on the CLI.
diff --git a/include/common/memory.h b/include/common/memory.h
index 410c97f..2b7121b 100644
--- a/include/common/memory.h
+++ b/include/common/memory.h
@@ -53,6 +53,7 @@
 	unsigned int size;	/* chunk size */
 	unsigned int flags;	/* MEM_F_* */
 	unsigned int users;	/* number of pools sharing this zone */
+	unsigned int failed;	/* failed allocations */
 	char name[12];		/* name of the pool */
 };
 
@@ -94,6 +95,9 @@
  */
 void dump_pools_to_trash();
 void dump_pools(void);
+int pool_total_failures();
+unsigned long pool_total_allocated();
+unsigned long pool_total_used();
 
 /*
  * This function frees whatever can be freed in pool <pool>.
diff --git a/src/dumpstats.c b/src/dumpstats.c
index b83dfb8..67686d3 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -2672,6 +2672,9 @@
 	             "Uptime: %dd %dh%02dm%02ds\n"
 	             "Uptime_sec: %d\n"
 	             "Memmax_MB: %d\n"
+		     "PoolAlloc_MB: %d\n"
+		     "PoolUsed_MB: %d\n"
+		     "PoolFailed: %d\n"
 	             "Ulimit-n: %d\n"
 	             "Maxsock: %d\n"
 	             "Maxconn: %d\n"
@@ -2724,6 +2727,9 @@
 	             up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60),
 	             up,
 	             global.rlimit_memmax,
+		     (int)(pool_total_allocated() / 1048576L),
+		     (int)(pool_total_used() / 1048576L),
+		     pool_total_failures(),
 	             global.rlimit_nofile,
 	             global.maxsock, global.maxconn, global.hardmaxconn,
 	             actconn, totalconn, global.req_count,
diff --git a/src/memory.c b/src/memory.c
index 691e1e3..036f786 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -103,6 +103,7 @@
 
 		ptr = MALLOC(pool->size + POOL_EXTRA);
 		if (!ptr) {
+			pool->failed++;
 			if (failed)
 				return NULL;
 			failed++;
@@ -206,9 +207,9 @@
 	allocated = used = nbpools = 0;
 	chunk_printf(&trash, "Dumping pools usage. Use SIGQUIT to flush them.\n");
 	list_for_each_entry(entry, &pools, list) {
-		chunk_appendf(&trash, "  - Pool %s (%d bytes) : %d allocated (%u bytes), %d used, %d users%s\n",
+		chunk_appendf(&trash, "  - Pool %s (%d bytes) : %d allocated (%u bytes), %d used, %d failures, %d users%s\n",
 			 entry->name, entry->size, entry->allocated,
-			 entry->size * entry->allocated, entry->used,
+		         entry->size * entry->allocated, entry->used, entry->failed,
 			 entry->users, (entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
 
 		allocated += entry->allocated * entry->size;
@@ -226,6 +227,39 @@
 	qfprintf(stderr, "%s", trash.str);
 }
 
+/* This function returns the total number of failed pool allocations */
+int pool_total_failures()
+{
+	struct pool_head *entry;
+	int failed = 0;
+
+	list_for_each_entry(entry, &pools, list)
+		failed += entry->failed;
+	return failed;
+}
+
+/* This function returns the total amount of memory allocated in pools (in bytes) */
+unsigned long pool_total_allocated()
+{
+	struct pool_head *entry;
+	unsigned long allocated = 0;
+
+	list_for_each_entry(entry, &pools, list)
+		allocated += entry->allocated * entry->size;
+	return allocated;
+}
+
+/* This function returns the total amount of memory used in pools (in bytes) */
+unsigned long pool_total_used()
+{
+	struct pool_head *entry;
+	unsigned long used = 0;
+
+	list_for_each_entry(entry, &pools, list)
+		used += entry->used * entry->size;
+	return used;
+}
+
 /*
  * Local variables:
  *  c-indent-level: 8