# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: henrik@henriknordstrom.net-20100528235108-\
#   fvvjfwdmd0ovbvpw
# target_branch: http://www.squid-cache.org/bzr/squid3/trunk/
# testament_sha1: b77080d7563b976aab0bf8bb77362627e0e3cd2d
# timestamp: 2010-05-29 01:51:44 +0200
# base_revision_id: henrik@henriknordstrom.net-20100528215627-\
#   agkq7l8rn7lertwg
# 
# Begin patch
=== modified file 'include/MemPool.h'
--- include/MemPool.h	2010-03-21 03:08:26 +0000
+++ include/MemPool.h	2010-05-28 23:51:08 +0000
@@ -1,5 +1,5 @@
-#ifndef _MEM_POOLS_H_
-#define _MEM_POOLS_H_
+#ifndef _MEM_POOL_H_
+#define _MEM_POOL_H_
 
 /**
  \defgroup MemPoolsAPI  Memory Management (Memory Pool Allocator)
@@ -63,7 +63,6 @@
 #define MEM_MAX_FREE  65535	/* ushort is max number of items per chunk */
 
 class MemImplementingAllocator;
-class MemChunk;
 class MemPoolStats;
 
 /// \ingroup MemPoolsAPI
@@ -97,17 +96,20 @@
 class MemPoolMeter
 {
 public:
+    MemPoolMeter();
     void flush();
     MemMeter alloc;
     MemMeter inuse;
     MemMeter idle;
 
-    /** account Allocations */
+
+    /** history Allocations */
+    mgb_t gb_allocated;
+    mgb_t gb_oallocated;
+
+    /** account Saved Allocations */
     mgb_t gb_saved;
 
-    /** history Allocations */
-    mgb_t gb_osaved;
-
     /** account Free calls */
     mgb_t gb_freed;
 };
@@ -130,13 +132,6 @@
     MemImplementingAllocator * create(const char *label, size_t obj_size);
 
     /**
-     \param label	Name for the pool. Displayed in stats.
-     \param obj_size	Size of elements in MemPool.
-     \param chunked	??
-     */
-    MemImplementingAllocator * create(const char *label, size_t obj_size, bool const chunked);
-
-    /**
      * Sets upper limit in bytes to amount of free ram kept in pools. This is
      * not strict upper limit, but a hint. When MemPools are over this limit,
      * totally free chunks are immediately considered for release. Otherwise
@@ -197,7 +192,7 @@
      \param stats	Object to be filled with statistical data about pool.
      \retval		Number of objects in use, ie. allocated.
      */
-    virtual int getStats(MemPoolStats * stats) = 0;
+    virtual int getStats(MemPoolStats * stats, int accumulate = 0) = 0;
 
     virtual MemPoolMeter const &getMeter() const = 0;
 
@@ -325,6 +320,7 @@
 {
 public:
     MemImplementingAllocator(char const *aLabel, size_t aSize);
+    ~MemImplementingAllocator();
     virtual MemPoolMeter const &getMeter() const;
     virtual MemPoolMeter &getMeter();
     virtual void flushMetersFull();
@@ -342,111 +338,23 @@
 
     virtual bool idleTrigger(int shift) const = 0;
     virtual void clean(time_t maxage) = 0;
-    /** Hint to the allocator - may be ignored */
-    virtual void setChunkSize(size_t chunksize) {}
     virtual size_t objectSize() const;
     virtual int getInUseCount() = 0;
 protected:
     virtual void *allocate() = 0;
     virtual void deallocate(void *) = 0;
-private:
     MemPoolMeter meter;
+    int memPID;
 public:
     MemImplementingAllocator *next;
 public:
     size_t alloc_calls;
     size_t free_calls;
+    size_t saved_calls;
     size_t obj_size;
 };
 
 /// \ingroup MemPoolsAPI
-class MemPool : public MemImplementingAllocator
-{
-public:
-    friend class MemChunk;
-    MemPool(const char *label, size_t obj_size);
-    ~MemPool();
-    void convertFreeCacheToChunkFreeCache();
-    virtual void clean(time_t maxage);
-
-    /**
-     \param stats	Object to be filled with statistical data about pool.
-     \retval		Number of objects in use, ie. allocated.
-     */
-    virtual int getStats(MemPoolStats * stats);
-
-    void createChunk();
-    void *get();
-    void push(void *obj);
-    virtual int getInUseCount();
-protected:
-    virtual void *allocate();
-    virtual void deallocate(void *);
-public:
-    /**
-     * Allows you tune chunk size of pooling. Objects are allocated in chunks
-     * instead of individually. This conserves memory, reduces fragmentation.
-     * Because of that memory can be freed also only in chunks. Therefore
-     * there is tradeoff between memory conservation due to chunking and free
-     * memory fragmentation.
-     *
-     \note  As a general guideline, increase chunk size only for pools that keep
-     *      very many items for relatively long time.
-     */
-    virtual void setChunkSize(size_t chunksize);
-
-    virtual bool idleTrigger(int shift) const;
-
-    size_t chunk_size;
-    int chunk_capacity;
-    int memPID;
-    int chunkCount;
-    size_t inuse;
-    size_t idle;
-    void *freeCache;
-    MemChunk *nextFreeChunk;
-    MemChunk *Chunks;
-    Splay<MemChunk *> allChunks;
-};
-
-/// \ingroup MemPoolsAPI
-class MemMalloc : public MemImplementingAllocator
-{
-public:
-    MemMalloc(char const *label, size_t aSize);
-    virtual bool idleTrigger(int shift) const;
-    virtual void clean(time_t maxage);
-
-    /**
-     \param stats	Object to be filled with statistical data about pool.
-     \retval		Number of objects in use, ie. allocated.
-     */
-    virtual int getStats(MemPoolStats * stats);
-
-    virtual int getInUseCount();
-protected:
-    virtual void *allocate();
-    virtual void deallocate(void *);
-private:
-    int inuse;
-};
-
-/// \ingroup MemPoolsAPI
-class MemChunk
-{
-public:
-    MemChunk(MemPool *pool);
-    ~MemChunk();
-    void *freeList;
-    void *objCache;
-    int inuse_count;
-    MemChunk *nextFreeChunk;
-    MemChunk *next;
-    time_t lastref;
-    MemPool *pool;
-};
-
-/// \ingroup MemPoolsAPI
 class MemPoolStats
 {
 public:
@@ -536,4 +444,4 @@
 }
 
 
-#endif /* _MEM_POOLS_H_ */
+#endif /* _MEM_POOL_H_ */

=== added file 'include/MemPoolChunked.h'
--- include/MemPoolChunked.h	1970-01-01 00:00:00 +0000
+++ include/MemPoolChunked.h	2010-05-28 21:53:06 +0000
@@ -0,0 +1,82 @@
+#ifndef _MEM_POOL_CHUNKED_H_
+#define _MEM_POOL_CHUNKED_H_
+
+#include "MemPool.h"
+
+/// \ingroup MemPoolsAPI
+#define MEM_PAGE_SIZE 4096
+/// \ingroup MemPoolsAPI
+#define MEM_CHUNK_SIZE 4096 * 4
+/// \ingroup MemPoolsAPI
+#define MEM_CHUNK_MAX_SIZE  256 * 1024	/* 2MB */
+/// \ingroup MemPoolsAPI
+#define MEM_MIN_FREE  32
+/// \ingroup MemPoolsAPI
+#define MEM_MAX_FREE  65535	/* ushort is max number of items per chunk */
+
+class MemChunk;
+
+/// \ingroup MemPoolsAPI
+class MemPoolChunked : public MemImplementingAllocator
+{
+public:
+    friend class MemChunk;
+    MemPoolChunked(const char *label, size_t obj_size);
+    ~MemPoolChunked();
+    void convertFreeCacheToChunkFreeCache();
+    virtual void clean(time_t maxage);
+
+    /**
+     \param stats	Object to be filled with statistical data about pool.
+     \retval		Number of objects in use, ie. allocated.
+     */
+    virtual int getStats(MemPoolStats * stats, int accumulate);
+
+    void createChunk();
+    void *get();
+    void push(void *obj);
+    virtual int getInUseCount();
+protected:
+    virtual void *allocate();
+    virtual void deallocate(void *);
+public:
+    /**
+     * Allows you tune chunk size of pooling. Objects are allocated in chunks
+     * instead of individually. This conserves memory, reduces fragmentation.
+     * Because of that memory can be freed also only in chunks. Therefore
+     * there is tradeoff between memory conservation due to chunking and free
+     * memory fragmentation.
+     *
+     \note  As a general guideline, increase chunk size only for pools that keep
+     *      very many items for relatively long time.
+     */
+    virtual void setChunkSize(size_t chunksize);
+
+    virtual bool idleTrigger(int shift) const;
+
+    size_t chunk_size;
+    int chunk_capacity;
+    int memPID;
+    int chunkCount;
+    void *freeCache;
+    MemChunk *nextFreeChunk;
+    MemChunk *Chunks;
+    Splay<MemChunk *> allChunks;
+};
+
+/// \ingroup MemPoolsAPI
+class MemChunk
+{
+public:
+    MemChunk(MemPoolChunked *pool);
+    ~MemChunk();
+    void *freeList;
+    void *objCache;
+    int inuse_count;
+    MemChunk *nextFreeChunk;
+    MemChunk *next;
+    time_t lastref;
+    MemPoolChunked *pool;
+};
+
+#endif /* _MEM_POOL_CHUNKED_H_ */

=== added file 'include/MemPoolMalloc.h'
--- include/MemPoolMalloc.h	1970-01-01 00:00:00 +0000
+++ include/MemPoolMalloc.h	2010-05-28 21:53:06 +0000
@@ -0,0 +1,47 @@
+#ifndef _MEM_POOL_MALLOC_H_
+#define _MEM_POOL_MALLOC_H_
+
+/**
+ \defgroup MemPoolsAPI  Memory Management (Memory Pool Allocator)
+ \ingroup Components
+ *
+ *\par
+ *  MemPools are a pooled memory allocator running on top of malloc(). It's
+ *  purpose is to reduce memory fragmentation and provide detailed statistics
+ *  on memory consumption.
+ *
+ \par
+ *  Preferably all memory allocations in Squid should be done using MemPools
+ *  or one of the types built on top of it (i.e. cbdata).
+ *
+ \note Usually it is better to use cbdata types as these gives you additional
+ *     safeguards in references and typechecking. However, for high usage pools where
+ *     the cbdata functionality of cbdata is not required directly using a MemPool
+ *     might be the way to go.
+ */
+
+#include "MemPool.h"
+
+/// \ingroup MemPoolsAPI
+class MemPoolMalloc : public MemImplementingAllocator
+{
+public:
+    MemPoolMalloc(char const *label, size_t aSize);
+    virtual bool idleTrigger(int shift) const;
+    virtual void clean(time_t maxage);
+
+    /**
+     \param stats	Object to be filled with statistical data about pool.
+     \retval		Number of objects in use, ie. allocated.
+     */
+    virtual int getStats(MemPoolStats * stats, int accumulate);
+
+    virtual int getInUseCount();
+protected:
+    virtual void *allocate();
+    virtual void deallocate(void *);
+private:
+};
+
+
+#endif /* _MEM_POOL_MALLOC_H_ */

=== modified file 'lib/Makefile.am'
--- lib/Makefile.am	2009-12-19 11:56:02 +0000
+++ lib/Makefile.am	2010-05-28 21:53:06 +0000
@@ -49,6 +49,8 @@
 	win32lib.c
 libmiscutil_a_SOURCES = \
 	MemPool.cc \
+	MemPoolChunked.cc \
+	MemPoolMalloc.cc \
 	base64.c \
 	charset.c \
 	getfullhostname.c \

=== modified file 'lib/MemPool.cc'
--- lib/MemPool.cc	2010-04-14 21:04:28 +0000
+++ lib/MemPool.cc	2010-05-28 23:51:08 +0000
@@ -87,6 +87,8 @@
 #endif
 
 #include "MemPool.h"
+#include "MemPoolChunked.h"
+#include "MemPoolMalloc.h"
 
 #define FLUSH_LIMIT 1000	/* Flush memPool counters to memMeters after flush limit calls */
 #define MEM_MAX_MMAP_CHUNKS 2048
@@ -107,10 +109,6 @@
 
 static int Pool_id_counter = 0;
 
-/* local prototypes */
-static int memCompChunks(MemChunk * const &, MemChunk * const &);
-static int memCompObjChunks(void * const &, MemChunk * const &);
-
 MemPools &
 MemPools::GetInstance()
 {
@@ -165,195 +163,6 @@
     return mem_idle_limit;
 }
 
-/* Compare chunks */
-static int
-memCompChunks(MemChunk * const &chunkA, MemChunk * const &chunkB)
-{
-    if (chunkA->objCache > chunkB->objCache)
-        return 1;
-    else if (chunkA->objCache < chunkB->objCache)
-        return -1;
-    else
-        return 0;
-}
-
-/* Compare object to chunk */
-static int
-memCompObjChunks(void *const &obj, MemChunk * const &chunk)
-{
-    /* object is lower in memory than the chunks arena */
-    if (obj < chunk->objCache)
-        return -1;
-    /* object is within the pool */
-    if (obj < (void *) ((char *) chunk->objCache + chunk->pool->chunk_size))
-        return 0;
-    /* object is above the pool */
-    return 1;
-}
-
-MemChunk::MemChunk(MemPool *aPool)
-{
-    /* should have a pool for this too -
-     * note that this requres:
-     * allocate one chunk for the pool of chunks's first chunk
-     * allocate a chunk from that pool
-     * move the contents of one chunk into the other
-     * free the first chunk.
-     */
-    inuse_count = 0;
-    next = NULL;
-    pool = aPool;
-
-    objCache = xcalloc(1, pool->chunk_size);
-    freeList = objCache;
-    void **Free = (void **)freeList;
-
-    for (int i = 1; i < pool->chunk_capacity; i++) {
-        *Free = (void *) ((char *) Free + pool->obj_size);
-        void **nextFree = (void **)*Free;
-        (void) VALGRIND_MAKE_MEM_NOACCESS(Free, pool->obj_size);
-        Free = nextFree;
-    }
-    nextFreeChunk = pool->nextFreeChunk;
-    pool->nextFreeChunk = this;
-
-    memMeterAdd(pool->getMeter().alloc, pool->chunk_capacity);
-    memMeterAdd(pool->getMeter().idle, pool->chunk_capacity);
-    pool->idle += pool->chunk_capacity;
-    pool->chunkCount++;
-    lastref = squid_curtime;
-    pool->allChunks.insert(this, memCompChunks);
-}
-
-MemPool::MemPool(const char *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize)
-{
-    chunk_size = 0;
-    chunk_capacity = 0;
-    memPID = 0;
-    chunkCount = 0;
-    inuse = 0;
-    idle = 0;
-    freeCache = 0;
-    nextFreeChunk = 0;
-    Chunks = 0;
-    next = 0;
-    MemImplementingAllocator *last_pool;
-
-    assert(aLabel != NULL && aSize);
-
-    setChunkSize(MEM_CHUNK_SIZE);
-
-    /* Append as Last */
-    for (last_pool = MemPools::GetInstance().pools; last_pool && last_pool->next;)
-        last_pool = last_pool->next;
-    if (last_pool)
-        last_pool->next = this;
-    else
-        MemPools::GetInstance().pools = this;
-
-    memPID = ++Pool_id_counter;
-}
-
-MemChunk::~MemChunk()
-{
-    memMeterDel(pool->getMeter().alloc, pool->chunk_capacity);
-    memMeterDel(pool->getMeter().idle, pool->chunk_capacity);
-    pool->idle -= pool->chunk_capacity;
-    pool->chunkCount--;
-    pool->allChunks.remove(this, memCompChunks);
-    xfree(objCache);
-}
-
-void
-MemPool::push(void *obj)
-{
-    void **Free;
-    /* XXX We should figure out a sane way of avoiding having to clear
-     * all buffers. For example data buffers such as used by MemBuf do
-     * not really need to be cleared.. There was a condition based on
-     * the object size here, but such condition is not safe.
-     */
-    if (doZeroOnPush)
-        memset(obj, 0, obj_size);
-    Free = (void **)obj;
-    *Free = freeCache;
-    freeCache = obj;
-    (void) VALGRIND_MAKE_MEM_NOACCESS(obj, obj_size);
-}
-
-/*
- * Find a chunk with a free item.
- * Create new chunk on demand if no chunk with frees found.
- * Insert new chunk in front of lowest ram chunk, making it preferred in future,
- * and resulting slow compaction towards lowest ram area.
- */
-void *
-MemPool::get()
-{
-    void **Free;
-
-    /* first, try cache */
-    if (freeCache) {
-        Free = (void **)freeCache;
-        (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size);
-        freeCache = *Free;
-        *Free = NULL;
-        return Free;
-    }
-    /* then try perchunk freelist chain */
-    if (nextFreeChunk == NULL) {
-        /* no chunk with frees, so create new one */
-        createChunk();
-    }
-    /* now we have some in perchunk freelist chain */
-    MemChunk *chunk = nextFreeChunk;
-
-    Free = (void **)chunk->freeList;
-    chunk->freeList = *Free;
-    *Free = NULL;
-    chunk->inuse_count++;
-    chunk->lastref = squid_curtime;
-
-    if (chunk->freeList == NULL) {
-        /* last free in this chunk, so remove us from perchunk freelist chain */
-        nextFreeChunk = chunk->nextFreeChunk;
-    }
-    (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size);
-    return Free;
-}
-
-/* just create a new chunk and place it into a good spot in the chunk chain */
-void
-MemPool::createChunk()
-{
-    MemChunk *chunk, *newChunk;
-
-    newChunk = new MemChunk(this);
-
-    chunk = Chunks;
-    if (chunk == NULL) {	/* first chunk in pool */
-        Chunks = newChunk;
-        return;
-    }
-    if (newChunk->objCache < chunk->objCache) {
-        /* we are lowest ram chunk, insert as first chunk */
-        newChunk->next = chunk;
-        Chunks = newChunk;
-        return;
-    }
-    while (chunk->next) {
-        if (newChunk->objCache < chunk->next->objCache) {
-            /* new chunk is in lower ram, insert here */
-            newChunk->next = chunk->next;
-            chunk->next = newChunk;
-            return;
-        }
-        chunk = chunk->next;
-    }
-    /* we are the worst chunk in chain, add as last */
-    chunk->next = newChunk;
-}
-
 /* Change the default calue of defaultIsChunked to override
  * all pools - including those used before main() starts where
  * MemPools::GetInstance().setDefaultPoolChunking() can be called.
@@ -369,49 +178,14 @@
 #endif
 }
 
-void
-MemPool::setChunkSize(size_t chunksize)
-{
-    int cap;
-    size_t csize = chunksize;
-
-    if (Chunks)		/* unsafe to tamper */
-        return;
-
-    csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE;	/* round up to page size */
-    cap = csize / obj_size;
-
-    if (cap < MEM_MIN_FREE)
-        cap = MEM_MIN_FREE;
-    if (cap * obj_size > MEM_CHUNK_MAX_SIZE)
-        cap = MEM_CHUNK_MAX_SIZE / obj_size;
-    if (cap > MEM_MAX_FREE)
-        cap = MEM_MAX_FREE;
-    if (cap < 1)
-        cap = 1;
-
-    csize = cap * obj_size;
-    csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE;	/* round up to page size */
-    cap = csize / obj_size;
-
-    chunk_capacity = cap;
-    chunk_size = csize;
-}
-
 MemImplementingAllocator *
 MemPools::create(const char *label, size_t obj_size)
 {
-    return create (label, obj_size, defaultIsChunked);
-}
-
-MemImplementingAllocator *
-MemPools::create(const char *label, size_t obj_size, bool const chunked)
-{
     ++poolCount;
-    if (chunked)
-        return new MemPool (label, obj_size);
+    if (defaultIsChunked)
+        return new MemPoolChunked (label, obj_size);
     else
-        return new MemMalloc (label, obj_size);
+        return new MemPoolMalloc (label, obj_size);
 }
 
 void
@@ -420,40 +194,6 @@
     defaultIsChunked = aBool;
 }
 
-/*
- * warning: we do not clean this entry from Pools assuming destruction
- * is used at the end of the program only
- */
-MemPool::~MemPool()
-{
-    MemChunk *chunk, *fchunk;
-    MemImplementingAllocator *find_pool, *prev_pool;
-
-    flushMetersFull();
-    clean(0);
-    assert(inuse == 0 && "While trying to destroy pool");
-
-    chunk = Chunks;
-    while ( (fchunk = chunk) != NULL) {
-        chunk = chunk->next;
-        delete fchunk;
-    }
-    /* TODO we should be doing something about the original Chunks pointer here. */
-
-    assert(MemPools::GetInstance().pools != NULL && "Called MemPool::~MemPool, but no pool exists!");
-
-    /* Pool clean, remove it from List and free */
-    for (find_pool = MemPools::GetInstance().pools, prev_pool = NULL; (find_pool && this != find_pool); find_pool = find_pool->next)
-        prev_pool = find_pool;
-    assert(find_pool != NULL && "pool to destroy not found");
-
-    if (prev_pool)
-        prev_pool->next = next;
-    else
-        MemPools::GetInstance().pools = next;
-    --MemPools::GetInstance().poolCount;
-}
-
 char const *
 MemAllocator::objectType() const
 {
@@ -473,17 +213,18 @@
 
     calls = free_calls;
     if (calls) {
-        getMeter().gb_freed.count += calls;
-        memMeterDel(getMeter().inuse, calls);
-        memMeterAdd(getMeter().idle, calls);
+        meter.gb_freed.count += calls;
         free_calls = 0;
     }
     calls = alloc_calls;
     if (calls) {
+        meter.gb_allocated.count += calls;
+        alloc_calls = 0;
+    }
+    calls = saved_calls;
+    if (calls) {
         meter.gb_saved.count += calls;
-        memMeterAdd(meter.inuse, calls);
-        memMeterDel(meter.idle, calls);
-        alloc_calls = 0;
+        saved_calls = 0;
     }
 }
 
@@ -491,6 +232,7 @@
 MemImplementingAllocator::flushMetersFull()
 {
     flushMeters();
+    getMeter().gb_allocated.bytes = getMeter().gb_allocated.count * obj_size;
     getMeter().gb_saved.bytes = getMeter().gb_saved.count * obj_size;
     getMeter().gb_freed.bytes = getMeter().gb_freed.count * obj_size;
 }
@@ -501,11 +243,21 @@
     alloc.level = 0;
     inuse.level = 0;
     idle.level = 0;
+    gb_allocated.count = 0;
+    gb_allocated.bytes = 0;
+    gb_oallocated.count = 0;
+    gb_oallocated.bytes = 0;
     gb_saved.count = 0;
     gb_saved.bytes = 0;
     gb_freed.count = 0;
     gb_freed.bytes = 0;
 }
+
+MemPoolMeter::MemPoolMeter()
+{
+    flush();
+}
+
 /*
  * Updates all pool counters, and recreates TheMeter totals from all pools
  */
@@ -523,8 +275,10 @@
         memMeterAdd(TheMeter.alloc, pool->getMeter().alloc.level * pool->obj_size);
         memMeterAdd(TheMeter.inuse, pool->getMeter().inuse.level * pool->obj_size);
         memMeterAdd(TheMeter.idle, pool->getMeter().idle.level * pool->obj_size);
+        TheMeter.gb_allocated.count += pool->getMeter().gb_allocated.count;
         TheMeter.gb_saved.count += pool->getMeter().gb_saved.count;
         TheMeter.gb_freed.count += pool->getMeter().gb_freed.count;
+        TheMeter.gb_allocated.bytes += pool->getMeter().gb_allocated.bytes;
         TheMeter.gb_saved.bytes += pool->getMeter().gb_saved.bytes;
         TheMeter.gb_freed.bytes += pool->getMeter().gb_freed.bytes;
     }
@@ -532,20 +286,6 @@
 }
 
 void *
-MemMalloc::allocate()
-{
-    inuse++;
-    return xcalloc(1, obj_size);
-}
-
-void
-MemMalloc::deallocate(void *obj)
-{
-    inuse--;
-    xfree(obj);
-}
-
-void *
 MemImplementingAllocator::alloc()
 {
     if (++alloc_calls == FLUSH_LIMIT)
@@ -563,123 +303,6 @@
     ++free_calls;
 }
 
-int
-MemPool::getInUseCount()
-{
-    return inuse;
-}
-
-void *
-MemPool::allocate()
-{
-    void *p = get();
-    assert(idle);
-    --idle;
-    ++inuse;
-    return p;
-}
-
-void
-MemPool::deallocate(void *obj)
-{
-    push(obj);
-    assert(inuse);
-    --inuse;
-    ++idle;
-}
-
-void
-MemPool::convertFreeCacheToChunkFreeCache()
-{
-    void *Free;
-    /*
-     * OK, so we have to go through all the global freeCache and find the Chunk
-     * any given Free belongs to, and stuff it into that Chunk's freelist
-     */
-
-    while ((Free = freeCache) != NULL) {
-        MemChunk *chunk = NULL;
-        chunk = const_cast<MemChunk *>(*allChunks.find(Free, memCompObjChunks));
-        assert(splayLastResult == 0);
-        assert(chunk->inuse_count > 0);
-        chunk->inuse_count--;
-        (void) VALGRIND_MAKE_MEM_DEFINED(Free, sizeof(void *));
-        freeCache = *(void **)Free;	/* remove from global cache */
-        *(void **)Free = chunk->freeList;	/* stuff into chunks freelist */
-        (void) VALGRIND_MAKE_MEM_NOACCESS(Free, sizeof(void *));
-        chunk->freeList = Free;
-        chunk->lastref = squid_curtime;
-    }
-
-}
-
-/* removes empty Chunks from pool */
-void
-MemPool::clean(time_t maxage)
-{
-    MemChunk *chunk, *freechunk, *listTail;
-    time_t age;
-
-    if (!this)
-        return;
-    if (!Chunks)
-        return;
-
-    flushMetersFull();
-    convertFreeCacheToChunkFreeCache();
-    /* Now we have all chunks in this pool cleared up, all free items returned to their home */
-    /* We start now checking all chunks to see if we can release any */
-    /* We start from Chunks->next, so first chunk is not released */
-    /* Recreate nextFreeChunk list from scratch */
-
-    chunk = Chunks;
-    while ((freechunk = chunk->next) != NULL) {
-        age = squid_curtime - freechunk->lastref;
-        freechunk->nextFreeChunk = NULL;
-        if (freechunk->inuse_count == 0)
-            if (age >= maxage) {
-                chunk->next = freechunk->next;
-                delete freechunk;
-                freechunk = NULL;
-            }
-        if (chunk->next == NULL)
-            break;
-        chunk = chunk->next;
-    }
-
-    /* Recreate nextFreeChunk list from scratch */
-    /* Populate nextFreeChunk list in order of "most filled chunk first" */
-    /* in case of equal fill, put chunk in lower ram first */
-    /* First (create time) chunk is always on top, no matter how full */
-
-    chunk = Chunks;
-    nextFreeChunk = chunk;
-    chunk->nextFreeChunk = NULL;
-
-    while (chunk->next) {
-        chunk->next->nextFreeChunk = NULL;
-        if (chunk->next->inuse_count < chunk_capacity) {
-            listTail = nextFreeChunk;
-            while (listTail->nextFreeChunk) {
-                if (chunk->next->inuse_count > listTail->nextFreeChunk->inuse_count)
-                    break;
-                if ((chunk->next->inuse_count == listTail->nextFreeChunk->inuse_count) &&
-                        (chunk->next->objCache < listTail->nextFreeChunk->objCache))
-                    break;
-                listTail = listTail->nextFreeChunk;
-            }
-            chunk->next->nextFreeChunk = listTail->nextFreeChunk;
-            listTail->nextFreeChunk = chunk->next;
-        }
-        chunk = chunk->next;
-    }
-    /* We started from 2nd chunk. If first chunk is full, remove it */
-    if (nextFreeChunk->inuse_count == chunk_capacity)
-        nextFreeChunk = nextFreeChunk->nextFreeChunk;
-
-    return;
-}
-
 /*
  * Returns all cached frees to their home chunks
  * If chunks unreferenced age is over, destroys Idle chunk
@@ -707,96 +330,10 @@
     memPoolIterateDone(&iter);
 }
 
-bool
-MemPool::idleTrigger(int shift) const
-{
-    return getMeter().idle.level > (chunk_capacity << shift);
-}
-
 /* Persistent Pool stats. for GlobalStats accumulation */
 static MemPoolStats pp_stats;
 
 /*
- * Update MemPoolStats struct for single pool
- */
-int
-MemPool::getStats(MemPoolStats * stats)
-{
-    MemChunk *chunk;
-    int chunks_free = 0;
-    int chunks_partial = 0;
-
-    if (stats != &pp_stats)	/* need skip memset for GlobalStats accumulation */
-        /* XXX Fixme */
-        memset(stats, 0, sizeof(MemPoolStats));
-
-    clean((time_t) 555555);	/* don't want to get chunks released before reporting */
-
-    stats->pool = this;
-    stats->label = objectType();
-    stats->meter = &getMeter();
-    stats->obj_size = obj_size;
-    stats->chunk_capacity = chunk_capacity;
-
-    /* gather stats for each Chunk */
-    chunk = Chunks;
-    while (chunk) {
-        if (chunk->inuse_count == 0)
-            chunks_free++;
-        else if (chunk->inuse_count < chunk_capacity)
-            chunks_partial++;
-        chunk = chunk->next;
-    }
-
-    stats->chunks_alloc += chunkCount;
-    stats->chunks_inuse += chunkCount - chunks_free;
-    stats->chunks_partial += chunks_partial;
-    stats->chunks_free += chunks_free;
-
-    stats->items_alloc += getMeter().alloc.level;
-    stats->items_inuse += getMeter().inuse.level;
-    stats->items_idle += getMeter().idle.level;
-
-    stats->overhead += sizeof(MemPool) + chunkCount * sizeof(MemChunk) + strlen(objectType()) + 1;
-
-    return getMeter().inuse.level;
-}
-
-/* TODO extract common logic to MemAllocate */
-int
-MemMalloc::getStats(MemPoolStats * stats)
-{
-    if (stats != &pp_stats)	/* need skip memset for GlobalStats accumulation */
-        /* XXX Fixme */
-        memset(stats, 0, sizeof(MemPoolStats));
-
-    stats->pool = this;
-    stats->label = objectType();
-    stats->meter = &getMeter();
-    stats->obj_size = obj_size;
-    stats->chunk_capacity = 0;
-
-    stats->chunks_alloc += 0;
-    stats->chunks_inuse += 0;
-    stats->chunks_partial += 0;
-    stats->chunks_free += 0;
-
-    stats->items_alloc += getMeter().alloc.level;
-    stats->items_inuse += getMeter().inuse.level;
-    stats->items_idle += getMeter().idle.level;
-
-    stats->overhead += sizeof(MemMalloc) + strlen(objectType()) + 1;
-
-    return getMeter().inuse.level;
-}
-
-int
-MemMalloc::getInUseCount()
-{
-    return inuse;
-}
-
-/*
  * Totals statistics is returned
  */
 int
@@ -814,7 +351,7 @@
     /* gather all stats for Totals */
     iter = memPoolIterate();
     while ((pool = memPoolIterateNext(iter))) {
-        if (pool->getStats(&pp_stats) > 0)
+        if (pool->getStats(&pp_stats, 1) > 0)
             pools_inuse++;
     }
     memPoolIterateDone(&iter);
@@ -833,7 +370,7 @@
     stats->tot_items_inuse = pp_stats.items_inuse;
     stats->tot_items_idle = pp_stats.items_idle;
 
-    stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(MemPool *);
+    stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(MemAllocator *);
     stats->mem_idle_limit = MemPools::GetInstance().mem_idle_limit;
 
     return pools_inuse;
@@ -848,19 +385,6 @@
     return ((s + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*);
 }
 
-MemMalloc::MemMalloc(char const *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize) { inuse = 0; }
-
-bool
-MemMalloc::idleTrigger(int shift) const
-{
-    return false;
-}
-
-void
-MemMalloc::clean(time_t maxage)
-{
-}
-
 int
 memPoolInUseCount(MemAllocator * pool)
 {
@@ -935,8 +459,39 @@
         next(NULL),
         alloc_calls(0),
         free_calls(0),
+        saved_calls(0),
         obj_size(RoundedSize(aSize))
 {
+    memPID = ++Pool_id_counter;
+
+    MemImplementingAllocator *last_pool;
+
+    assert(aLabel != NULL && aSize);
+    /* Append as Last */
+    for (last_pool = MemPools::GetInstance().pools; last_pool && last_pool->next;)
+        last_pool = last_pool->next;
+    if (last_pool)
+        last_pool->next = this;
+    else
+        MemPools::GetInstance().pools = this;
+}
+
+MemImplementingAllocator::~MemImplementingAllocator()
+{
+    MemImplementingAllocator *find_pool, *prev_pool;
+
+    assert(MemPools::GetInstance().pools != NULL && "Called MemImplementingAllocator::~MemImplementingAllocator, but no pool exists!");
+
+    /* Pool clean, remove it from List and free */
+    for (find_pool = MemPools::GetInstance().pools, prev_pool = NULL; (find_pool && this != find_pool); find_pool = find_pool->next)
+        prev_pool = find_pool;
+    assert(find_pool != NULL && "pool to destroy not found");
+
+    if (prev_pool)
+        prev_pool->next = next;
+    else
+        MemPools::GetInstance().pools = next;
+    --MemPools::GetInstance().poolCount;
 }
 
 void

=== added file 'lib/MemPoolChunked.cc'
--- lib/MemPoolChunked.cc	1970-01-01 00:00:00 +0000
+++ lib/MemPoolChunked.cc	2010-05-28 23:51:08 +0000
@@ -0,0 +1,498 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 63    Low Level Memory Pool Management
+ * AUTHOR: Alex Rousskov, Andres Kroonmaa, Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  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, USA.
+ *
+ */
+
+/*
+ * Old way:
+ *   xmalloc each item separately, upon free stack into idle pool array.
+ *   each item is individually malloc()ed from system, imposing libmalloc
+ *   overhead, and additionally we add our overhead of pointer size per item
+ *   as we keep a list of pointer to free items.
+ *
+ * Chunking:
+ *   xmalloc Chunk that fits at least MEM_MIN_FREE (32) items in an array, but
+ *   limit Chunk size to MEM_CHUNK_MAX_SIZE (256K). Chunk size is rounded up to
+ *   MEM_PAGE_SIZE (4K), trying to have chunks in multiples of VM_PAGE size.
+ *   Minimum Chunk size is MEM_CHUNK_SIZE (16K).
+ *   A number of items fits into a single chunk, depending on item size.
+ *   Maximum number of items per chunk is limited to MEM_MAX_FREE (65535).
+ *
+ *   We populate Chunk with a linkedlist, each node at first word of item,
+ *   and pointing at next free item. Chunk->FreeList is pointing at first
+ *   free node. Thus we stuff free housekeeping into the Chunk itself, and
+ *   omit pointer overhead per item.
+ *
+ *   Chunks are created on demand, and new chunks are inserted into linklist
+ *   of chunks so that Chunks with smaller pointer value are placed closer
+ *   to the linklist head. Head is a hotspot, servicing most of requests, so
+ *   slow sorting occurs and Chunks in highest memory tend to become idle
+ *   and freeable.
+ *
+ *   event is registered that runs every 15 secs and checks reference time
+ *   of each idle chunk. If a chunk is not referenced for 15 secs, it is
+ *   released.
+ *
+ *   [If mem_idle_limit is exceeded with pools, every chunk that becomes
+ *   idle is immediately considered for release, unless this is the only
+ *   chunk with free items in it.] (not implemented)
+ *
+ *   In cachemgr output, there are new columns for chunking. Special item,
+ *   Frag, is shown to estimate approximately fragmentation of chunked
+ *   pools. Fragmentation is calculated by taking amount of items in use,
+ *   calculating needed amount of chunks to fit all, and then comparing to
+ *   actual amount of chunks in use. Frag number, in percent, is showing
+ *   how many percent of chunks are in use excessively. 100% meaning that
+ *   twice the needed amount of chunks are in use.
+ *   "part" item shows number of chunks partially filled. This shows how
+ *   badly fragmentation is spread across all chunks.
+ *
+ *   Andres Kroonmaa.
+ *   Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
+ */
+
+#include "config.h"
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include "MemPoolChunked.h"
+
+#define FLUSH_LIMIT 1000	/* Flush memPool counters to memMeters after flush limit calls */
+#define MEM_MAX_MMAP_CHUNKS 2048
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+/*
+ * XXX This is a boundary violation between lib and src.. would be good
+ * if it could be solved otherwise, but left for now.
+ */
+extern time_t squid_curtime;
+
+/* local prototypes */
+static int memCompChunks(MemChunk * const &, MemChunk * const &);
+static int memCompObjChunks(void * const &, MemChunk * const &);
+
+/* Compare chunks */
+static int
+memCompChunks(MemChunk * const &chunkA, MemChunk * const &chunkB)
+{
+    if (chunkA->objCache > chunkB->objCache)
+        return 1;
+    else if (chunkA->objCache < chunkB->objCache)
+        return -1;
+    else
+        return 0;
+}
+
+/* Compare object to chunk */
+static int
+memCompObjChunks(void *const &obj, MemChunk * const &chunk)
+{
+    /* object is lower in memory than the chunks arena */
+    if (obj < chunk->objCache)
+        return -1;
+    /* object is within the pool */
+    if (obj < (void *) ((char *) chunk->objCache + chunk->pool->chunk_size))
+        return 0;
+    /* object is above the pool */
+    return 1;
+}
+
+MemChunk::MemChunk(MemPoolChunked *aPool)
+{
+    /* should have a pool for this too -
+     * note that this requres:
+     * allocate one chunk for the pool of chunks's first chunk
+     * allocate a chunk from that pool
+     * move the contents of one chunk into the other
+     * free the first chunk.
+     */
+    inuse_count = 0;
+    next = NULL;
+    pool = aPool;
+
+    objCache = xcalloc(1, pool->chunk_size);
+    freeList = objCache;
+    void **Free = (void **)freeList;
+
+    for (int i = 1; i < pool->chunk_capacity; i++) {
+        *Free = (void *) ((char *) Free + pool->obj_size);
+        void **nextFree = (void **)*Free;
+        (void) VALGRIND_MAKE_MEM_NOACCESS(Free, pool->obj_size);
+        Free = nextFree;
+    }
+    nextFreeChunk = pool->nextFreeChunk;
+    pool->nextFreeChunk = this;
+
+    memMeterAdd(pool->getMeter().alloc, pool->chunk_capacity);
+    memMeterAdd(pool->getMeter().idle, pool->chunk_capacity);
+    pool->chunkCount++;
+    lastref = squid_curtime;
+    pool->allChunks.insert(this, memCompChunks);
+}
+
+MemPoolChunked::MemPoolChunked(const char *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize)
+{
+    chunk_size = 0;
+    chunk_capacity = 0;
+    chunkCount = 0;
+    freeCache = 0;
+    nextFreeChunk = 0;
+    Chunks = 0;
+    next = 0;
+
+    setChunkSize(MEM_CHUNK_SIZE);
+}
+
+MemChunk::~MemChunk()
+{
+    memMeterDel(pool->getMeter().alloc, pool->chunk_capacity);
+    memMeterDel(pool->getMeter().idle, pool->chunk_capacity);
+    pool->chunkCount--;
+    pool->allChunks.remove(this, memCompChunks);
+    xfree(objCache);
+}
+
+void
+MemPoolChunked::push(void *obj)
+{
+    void **Free;
+    /* XXX We should figure out a sane way of avoiding having to clear
+     * all buffers. For example data buffers such as used by MemBuf do
+     * not really need to be cleared.. There was a condition based on
+     * the object size here, but such condition is not safe.
+     */
+    if (doZeroOnPush)
+        memset(obj, 0, obj_size);
+    Free = (void **)obj;
+    *Free = freeCache;
+    freeCache = obj;
+    (void) VALGRIND_MAKE_MEM_NOACCESS(obj, obj_size);
+}
+
+/*
+ * Find a chunk with a free item.
+ * Create new chunk on demand if no chunk with frees found.
+ * Insert new chunk in front of lowest ram chunk, making it preferred in future,
+ * and resulting slow compaction towards lowest ram area.
+ */
+void *
+MemPoolChunked::get()
+{
+    void **Free;
+
+    saved_calls++;
+
+    /* first, try cache */
+    if (freeCache) {
+        Free = (void **)freeCache;
+        (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size);
+        freeCache = *Free;
+        *Free = NULL;
+        return Free;
+    }
+    /* then try perchunk freelist chain */
+    if (nextFreeChunk == NULL) {
+        /* no chunk with frees, so create new one */
+	saved_calls--; // compensate for the ++ above
+        createChunk();
+    }
+    /* now we have some in perchunk freelist chain */
+    MemChunk *chunk = nextFreeChunk;
+
+    Free = (void **)chunk->freeList;
+    chunk->freeList = *Free;
+    *Free = NULL;
+    chunk->inuse_count++;
+    chunk->lastref = squid_curtime;
+
+    if (chunk->freeList == NULL) {
+        /* last free in this chunk, so remove us from perchunk freelist chain */
+        nextFreeChunk = chunk->nextFreeChunk;
+    }
+    (void) VALGRIND_MAKE_MEM_DEFINED(Free, obj_size);
+    return Free;
+}
+
+/* just create a new chunk and place it into a good spot in the chunk chain */
+void
+MemPoolChunked::createChunk()
+{
+    MemChunk *chunk, *newChunk;
+
+    newChunk = new MemChunk(this);
+
+    chunk = Chunks;
+    if (chunk == NULL) {	/* first chunk in pool */
+        Chunks = newChunk;
+        return;
+    }
+    if (newChunk->objCache < chunk->objCache) {
+        /* we are lowest ram chunk, insert as first chunk */
+        newChunk->next = chunk;
+        Chunks = newChunk;
+        return;
+    }
+    while (chunk->next) {
+        if (newChunk->objCache < chunk->next->objCache) {
+            /* new chunk is in lower ram, insert here */
+            newChunk->next = chunk->next;
+            chunk->next = newChunk;
+            return;
+        }
+        chunk = chunk->next;
+    }
+    /* we are the worst chunk in chain, add as last */
+    chunk->next = newChunk;
+}
+
+void
+MemPoolChunked::setChunkSize(size_t chunksize)
+{
+    int cap;
+    size_t csize = chunksize;
+
+    if (Chunks)		/* unsafe to tamper */
+        return;
+
+    csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE;	/* round up to page size */
+    cap = csize / obj_size;
+
+    if (cap < MEM_MIN_FREE)
+        cap = MEM_MIN_FREE;
+    if (cap * obj_size > MEM_CHUNK_MAX_SIZE)
+        cap = MEM_CHUNK_MAX_SIZE / obj_size;
+    if (cap > MEM_MAX_FREE)
+        cap = MEM_MAX_FREE;
+    if (cap < 1)
+        cap = 1;
+
+    csize = cap * obj_size;
+    csize = ((csize + MEM_PAGE_SIZE - 1) / MEM_PAGE_SIZE) * MEM_PAGE_SIZE;	/* round up to page size */
+    cap = csize / obj_size;
+
+    chunk_capacity = cap;
+    chunk_size = csize;
+}
+
+/*
+ * warning: we do not clean this entry from Pools assuming destruction
+ * is used at the end of the program only
+ */
+MemPoolChunked::~MemPoolChunked()
+{
+    MemChunk *chunk, *fchunk;
+
+    flushMetersFull();
+    clean(0);
+    assert(getMeter().inuse.level == 0 && "While trying to destroy pool");
+
+    chunk = Chunks;
+    while ( (fchunk = chunk) != NULL) {
+        chunk = chunk->next;
+        delete fchunk;
+    }
+    /* TODO we should be doing something about the original Chunks pointer here. */
+
+}
+
+int
+MemPoolChunked::getInUseCount()
+{
+    return getMeter().inuse.level;
+}
+
+void *
+MemPoolChunked::allocate()
+{
+    void *p = get();
+    assert(meter.idle.level > 0);
+    memMeterDec(meter.idle);
+    memMeterInc(meter.inuse);
+    return p;
+}
+
+void
+MemPoolChunked::deallocate(void *obj)
+{
+    push(obj);
+    assert(meter.inuse.level > 0);
+    memMeterDec(meter.inuse);
+    memMeterInc(meter.idle);
+}
+
+void
+MemPoolChunked::convertFreeCacheToChunkFreeCache()
+{
+    void *Free;
+    /*
+     * OK, so we have to go through all the global freeCache and find the Chunk
+     * any given Free belongs to, and stuff it into that Chunk's freelist
+     */
+
+    while ((Free = freeCache) != NULL) {
+        MemChunk *chunk = NULL;
+        chunk = const_cast<MemChunk *>(*allChunks.find(Free, memCompObjChunks));
+        assert(splayLastResult == 0);
+        assert(chunk->inuse_count > 0);
+        chunk->inuse_count--;
+        (void) VALGRIND_MAKE_MEM_DEFINED(Free, sizeof(void *));
+        freeCache = *(void **)Free;	/* remove from global cache */
+        *(void **)Free = chunk->freeList;	/* stuff into chunks freelist */
+        (void) VALGRIND_MAKE_MEM_NOACCESS(Free, sizeof(void *));
+        chunk->freeList = Free;
+        chunk->lastref = squid_curtime;
+    }
+
+}
+
+/* removes empty Chunks from pool */
+void
+MemPoolChunked::clean(time_t maxage)
+{
+    MemChunk *chunk, *freechunk, *listTail;
+    time_t age;
+
+    if (!this)
+        return;
+    if (!Chunks)
+        return;
+
+    flushMetersFull();
+    convertFreeCacheToChunkFreeCache();
+    /* Now we have all chunks in this pool cleared up, all free items returned to their home */
+    /* We start now checking all chunks to see if we can release any */
+    /* We start from Chunks->next, so first chunk is not released */
+    /* Recreate nextFreeChunk list from scratch */
+
+    chunk = Chunks;
+    while ((freechunk = chunk->next) != NULL) {
+        age = squid_curtime - freechunk->lastref;
+        freechunk->nextFreeChunk = NULL;
+        if (freechunk->inuse_count == 0)
+            if (age >= maxage) {
+                chunk->next = freechunk->next;
+                delete freechunk;
+                freechunk = NULL;
+            }
+        if (chunk->next == NULL)
+            break;
+        chunk = chunk->next;
+    }
+
+    /* Recreate nextFreeChunk list from scratch */
+    /* Populate nextFreeChunk list in order of "most filled chunk first" */
+    /* in case of equal fill, put chunk in lower ram first */
+    /* First (create time) chunk is always on top, no matter how full */
+
+    chunk = Chunks;
+    nextFreeChunk = chunk;
+    chunk->nextFreeChunk = NULL;
+
+    while (chunk->next) {
+        chunk->next->nextFreeChunk = NULL;
+        if (chunk->next->inuse_count < chunk_capacity) {
+            listTail = nextFreeChunk;
+            while (listTail->nextFreeChunk) {
+                if (chunk->next->inuse_count > listTail->nextFreeChunk->inuse_count)
+                    break;
+                if ((chunk->next->inuse_count == listTail->nextFreeChunk->inuse_count) &&
+                        (chunk->next->objCache < listTail->nextFreeChunk->objCache))
+                    break;
+                listTail = listTail->nextFreeChunk;
+            }
+            chunk->next->nextFreeChunk = listTail->nextFreeChunk;
+            listTail->nextFreeChunk = chunk->next;
+        }
+        chunk = chunk->next;
+    }
+    /* We started from 2nd chunk. If first chunk is full, remove it */
+    if (nextFreeChunk->inuse_count == chunk_capacity)
+        nextFreeChunk = nextFreeChunk->nextFreeChunk;
+
+    return;
+}
+
+bool
+MemPoolChunked::idleTrigger(int shift) const
+{
+    return getMeter().idle.level > (chunk_capacity << shift);
+}
+
+/*
+ * Update MemPoolStats struct for single pool
+ */
+int
+MemPoolChunked::getStats(MemPoolStats * stats, int accumulate)
+{
+    MemChunk *chunk;
+    int chunks_free = 0;
+    int chunks_partial = 0;
+
+    if (!accumulate)	/* need skip memset for GlobalStats accumulation */
+        memset(stats, 0, sizeof(MemPoolStats));
+
+    clean((time_t) 555555);	/* don't want to get chunks released before reporting */
+
+    stats->pool = this;
+    stats->label = objectType();
+    stats->meter = &getMeter();
+    stats->obj_size = obj_size;
+    stats->chunk_capacity = chunk_capacity;
+
+    /* gather stats for each Chunk */
+    chunk = Chunks;
+    while (chunk) {
+        if (chunk->inuse_count == 0)
+            chunks_free++;
+        else if (chunk->inuse_count < chunk_capacity)
+            chunks_partial++;
+        chunk = chunk->next;
+    }
+
+    stats->chunks_alloc += chunkCount;
+    stats->chunks_inuse += chunkCount - chunks_free;
+    stats->chunks_partial += chunks_partial;
+    stats->chunks_free += chunks_free;
+
+    stats->items_alloc += getMeter().alloc.level;
+    stats->items_inuse += getMeter().inuse.level;
+    stats->items_idle += getMeter().idle.level;
+
+    stats->overhead += sizeof(MemPoolChunked) + chunkCount * sizeof(MemChunk) + strlen(objectType()) + 1;
+
+    return getMeter().inuse.level;
+}

=== added file 'lib/MemPoolMalloc.cc'
--- lib/MemPoolMalloc.cc	1970-01-01 00:00:00 +0000
+++ lib/MemPoolMalloc.cc	2010-05-28 21:53:06 +0000
@@ -0,0 +1,117 @@
+
+/*
+ * $Id$
+ *
+ * DEBUG: section 63    Low Level Memory Pool Management
+ * AUTHOR: Alex Rousskov, Andres Kroonmaa, Robert Collins
+ *
+ * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by the
+ *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
+ *  the Regents of the University of California.  Please see the
+ *  COPYRIGHT file for full details.  Squid incorporates software
+ *  developed and/or copyrighted by other sources.  Please see the
+ *  CREDITS file for full details.
+ *
+ *  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, USA.
+ *
+ */
+
+
+#include "config.h"
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#include "MemPoolMalloc.h"
+
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+
+/*
+ * XXX This is a boundary violation between lib and src.. would be good
+ * if it could be solved otherwise, but left for now.
+ */
+extern time_t squid_curtime;
+
+void *
+MemPoolMalloc::allocate()
+{
+    memMeterInc(meter.alloc);
+    memMeterInc(meter.inuse);
+    return xcalloc(1, obj_size);
+}
+
+void
+MemPoolMalloc::deallocate(void *obj)
+{
+    memMeterDec(meter.inuse);
+    memMeterDec(meter.alloc);
+    xfree(obj);
+}
+
+/* TODO extract common logic to MemAllocate */
+int
+MemPoolMalloc::getStats(MemPoolStats * stats, int accumulate)
+{
+    if (!accumulate)	/* need skip memset for GlobalStats accumulation */
+        memset(stats, 0, sizeof(MemPoolStats));
+
+    stats->pool = this;
+    stats->label = objectType();
+    stats->meter = &getMeter();
+    stats->obj_size = obj_size;
+    stats->chunk_capacity = 0;
+
+    stats->chunks_alloc += 0;
+    stats->chunks_inuse += 0;
+    stats->chunks_partial += 0;
+    stats->chunks_free += 0;
+
+    stats->items_alloc += meter.alloc.level;
+    stats->items_inuse += meter.inuse.level;
+    stats->items_idle += meter.idle.level;
+
+    stats->overhead += sizeof(MemPoolMalloc) + strlen(objectType()) + 1;
+
+    return meter.inuse.level;
+}
+
+int
+MemPoolMalloc::getInUseCount()
+{
+    return meter.inuse.level;
+}
+
+MemPoolMalloc::MemPoolMalloc(char const *aLabel, size_t aSize) : MemImplementingAllocator(aLabel, aSize)
+{
+}
+
+bool
+MemPoolMalloc::idleTrigger(int shift) const
+{
+    return false;
+}
+
+void
+MemPoolMalloc::clean(time_t maxage)
+{
+}
+

=== modified file 'src/mem.cc'
--- src/mem.cc	2010-03-21 03:08:26 +0000
+++ src/mem.cc	2010-05-28 23:51:08 +0000
@@ -580,6 +580,9 @@
     MemPoolMeter *pm = mp_st->meter;
     const char *delim = "\t ";
 
+#if HAVE_IOMANIP
+    stream.setf(std::ios_base::fixed);
+#endif
     stream << std::setw(20) << std::left << mp_st->label << delim;
     stream << std::setw(4) << std::right << mp_st->obj_size << delim;
 
@@ -627,10 +630,10 @@
     stream << toKB(mp_st->obj_size * pm->idle.hwater_level) << delim;
     /* saved */
     stream << (int)pm->gb_saved.count << delim;
-    stream << std::setprecision(3) << xpercent(pm->gb_saved.count, AllMeter->gb_saved.count) << delim;
-    stream << std::setprecision(3) << xpercent(pm->gb_saved.bytes, AllMeter->gb_saved.bytes) << delim;
-    stream << std::setprecision(3) << xdiv(pm->gb_saved.count - pm->gb_osaved.count, xm_deltat) << "\n";
-    pm->gb_osaved.count = pm->gb_saved.count;
+    stream << std::setprecision(3) << xpercent(pm->gb_saved.count, AllMeter->gb_allocated.count) << delim;
+    stream << std::setprecision(3) << xpercent(pm->gb_saved.bytes, AllMeter->gb_allocated.bytes) << delim;
+    stream << std::setprecision(3) << xdiv(pm->gb_allocated.count - pm->gb_oallocated.count, xm_deltat) << "\n";
+    pm->gb_oallocated.count = pm->gb_allocated.count;
 }
 
 static int
@@ -683,7 +686,7 @@
     "In Use\t\t\t\t\t"
     "Idle\t\t\t"
     "Allocations Saved\t\t\t"
-    "Hit Rate\t"
+    "Rate\t"
     "\n"
     " \t (bytes)\t"
     "KB/ch\t obj/ch\t"
@@ -692,7 +695,7 @@
     "(#)\t (KB)\t high (KB)\t high (hrs)\t %alloc\t"
     "(#)\t (KB)\t high (KB)\t"
     "(#)\t %cnt\t %vol\t"
-    "(#) / sec\t"
+    "(#)/sec\t"
     "\n";
     xm_deltat = current_dtime - xm_time;
     xm_time = current_dtime;
@@ -712,7 +715,7 @@
         if (!mp_stats.pool)	/* pool destroyed */
             continue;
 
-        if (mp_stats.pool->getMeter().gb_saved.count > 0)	/* this pool has been used */
+        if (mp_stats.pool->getMeter().gb_allocated.count > 0)	/* this pool has been used */
             sortme[npools++] = mp_stats;
         else
             not_used++;
@@ -746,7 +749,7 @@
     PoolReport(&mp_stats, mp_total.TheMeter, stream);
 
     /* Cumulative */
-    stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.TheMeter->gb_saved.bytes) << "\n";
+    stream << "Cumulative allocated volume: "<< double_to_str(buf, 64, mp_total.TheMeter->gb_allocated.bytes) << "\n";
     /* overhead */
     stream << "Current overhead: " << mp_total.tot_overhead << " bytes (" <<
     std::setprecision(3) << xpercent(mp_total.tot_overhead, mp_total.TheMeter->inuse.level) << "%)\n";

# Begin bundle
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
CMh8h6zJ+TSov/4u5IpwoSDFDhuo

