=== modified file 'src/CacheDigest.cc'
--- src/CacheDigest.cc	2010-12-13 11:31:14 +0000
+++ src/CacheDigest.cc	2011-12-15 21:17:34 +0000
@@ -17,40 +17,41 @@
  *  incorporates software developed and/or copyrighted by other
  *  sources; 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 "squid.h"
+#include "StatCounters.h"
 #include "Store.h"
 
 #if USE_CACHE_DIGESTS
 
 /* local types */
 
 typedef struct {
     int bit_count;		/* total number of bits */
     int bit_on_count;		/* #bits turned on */
     int bseq_len_sum;		/* sum of all bit seq length */
     int bseq_count;		/* number of bit seqs */
 } CacheDigestStats;
 
 /* local functions */
 static void cacheDigestHashKey(const CacheDigest * cd, const cache_key * key);
 
 /* static array used by cacheDigestHashKey for optimization purposes */
 static uint32_t hashed_keys[4];
 
 static void
@@ -159,41 +160,41 @@
         if (!CBIT_TEST(cd->mask, hashed_keys[0])) {
             CBIT_SET(cd->mask, hashed_keys[0]);
             on_xition_cnt++;
         }
 
         if (!CBIT_TEST(cd->mask, hashed_keys[1])) {
             CBIT_SET(cd->mask, hashed_keys[1]);
             on_xition_cnt++;
         }
 
         if (!CBIT_TEST(cd->mask, hashed_keys[2])) {
             CBIT_SET(cd->mask, hashed_keys[2]);
             on_xition_cnt++;
         }
 
         if (!CBIT_TEST(cd->mask, hashed_keys[3])) {
             CBIT_SET(cd->mask, hashed_keys[3]);
             on_xition_cnt++;
         }
 
-        statHistCount(&statCounter.cd.on_xition_count, on_xition_cnt);
+        statCounter.cd.on_xition_count.count(on_xition_cnt);
     }
 #endif
     cd->count++;
 }
 
 void
 cacheDigestDel(CacheDigest * cd, const cache_key * key)
 {
     assert(cd && key);
     cd->del_count++;
     /* we do not support deletions from the digest */
 }
 
 /* returns mask utilization parameters */
 static void
 cacheDigestStats(const CacheDigest * cd, CacheDigestStats * stats)
 {
     int on_count = 0;
     int pos = cd->mask_size * 8;
     int seq_len_sum = 0;
@@ -218,91 +219,91 @@
 
         cur_seq_len++;
     }
 
     stats->bit_count = cd->mask_size * 8;
     stats->bit_on_count = on_count;
     stats->bseq_len_sum = seq_len_sum;
     stats->bseq_count = seq_count;
 }
 
 int
 cacheDigestBitUtil(const CacheDigest * cd)
 {
     CacheDigestStats stats;
     assert(cd);
     cacheDigestStats(cd, &stats);
     return xpercentInt(stats.bit_on_count, stats.bit_count);
 }
 
 void
-cacheDigestGuessStatsUpdate(cd_guess_stats * stats, int real_hit, int guess_hit)
+cacheDigestGuessStatsUpdate(CacheDigestGuessStats * stats, int real_hit, int guess_hit)
 {
     assert(stats);
 
     if (real_hit) {
         if (guess_hit)
-            stats->true_hits++;
+            ++stats->trueHits;
         else
-            stats->false_misses++;
+            ++stats->falseMisses;
     } else {
         if (guess_hit)
-            stats->false_hits++;
+            ++stats->falseHits;
         else
-            stats->true_misses++;
+            ++stats->trueMisses;
     }
 }
 
 void
-cacheDigestGuessStatsReport(const cd_guess_stats * stats, StoreEntry * sentry, const char *label)
+cacheDigestGuessStatsReport(const CacheDigestGuessStats * stats, StoreEntry * sentry, const char *label)
 {
-    const int true_count = stats->true_hits + stats->true_misses;
-    const int false_count = stats->false_hits + stats->false_misses;
-    const int hit_count = stats->true_hits + stats->false_hits;
-    const int miss_count = stats->true_misses + stats->false_misses;
+    const int true_count = stats->trueHits + stats->trueMisses;
+    const int false_count = stats->falseHits + stats->falseMisses;
+    const int hit_count = stats->trueHits + stats->falseHits;
+    const int miss_count = stats->trueMisses + stats->falseMisses;
     const int tot_count = true_count + false_count;
 
     assert(label);
     assert(tot_count == hit_count + miss_count);	/* paranoid */
 
     if (!tot_count) {
         storeAppendPrintf(sentry, "no guess stats for %s available\n", label);
         return;
     }
 
     storeAppendPrintf(sentry, "Digest guesses stats for %s:\n", label);
     storeAppendPrintf(sentry, "guess\t hit\t\t miss\t\t total\t\t\n");
     storeAppendPrintf(sentry, " \t #\t %%\t #\t %%\t #\t %%\t\n");
     storeAppendPrintf(sentry, "true\t %d\t %.2f\t %d\t %.2f\t %d\t %.2f\n",
-                      stats->true_hits, xpercent(stats->true_hits, tot_count),
-                      stats->true_misses, xpercent(stats->true_misses, tot_count),
+                      stats->trueHits, xpercent(stats->trueHits, tot_count),
+                      stats->trueMisses, xpercent(stats->trueMisses, tot_count),
                       true_count, xpercent(true_count, tot_count));
     storeAppendPrintf(sentry, "false\t %d\t %.2f\t %d\t %.2f\t %d\t %.2f\n",
-                      stats->false_hits, xpercent(stats->false_hits, tot_count),
-                      stats->false_misses, xpercent(stats->false_misses, tot_count),
+                      stats->falseHits, xpercent(stats->falseHits, tot_count),
+                      stats->falseMisses, xpercent(stats->falseMisses, tot_count),
                       false_count, xpercent(false_count, tot_count));
     storeAppendPrintf(sentry, "all\t %d\t %.2f\t %d\t %.2f\t %d\t %.2f\n",
                       hit_count, xpercent(hit_count, tot_count),
                       miss_count, xpercent(miss_count, tot_count),
                       tot_count, xpercent(tot_count, tot_count));
     storeAppendPrintf(sentry, "\tclose_hits: %d ( %d%%) /* cd said hit, doc was in the peer cache, but we got a miss */\n",
-                      stats->close_hits, xpercentInt(stats->close_hits, stats->false_hits));
+                      stats->closeHits, xpercentInt(stats->closeHits, stats->falseHits));
 }
 
 void
 cacheDigestReport(CacheDigest * cd, const char *label, StoreEntry * e)
 {
     CacheDigestStats stats;
     assert(cd && e);
     cacheDigestStats(cd, &stats);
     storeAppendPrintf(e, "%s digest: size: %d bytes\n",
                       label ? label : "", stats.bit_count / 8
                      );
     storeAppendPrintf(e, "\t entries: count: %d capacity: %d util: %d%%\n",
                       cd->count,
                       cd->capacity,
                       xpercentInt(cd->count, cd->capacity)
                      );
     storeAppendPrintf(e, "\t deletion attempts: %d\n",
                       cd->del_count
                      );
     storeAppendPrintf(e, "\t bits: per entry: %d on: %d capacity: %d util: %d%%\n",

=== modified file 'src/DiskIO/DiskDaemon/DiskdFile.cc'
--- src/DiskIO/DiskDaemon/DiskdFile.cc	2010-12-13 11:31:14 +0000
+++ src/DiskIO/DiskDaemon/DiskdFile.cc	2011-12-10 15:21:36 +0000
@@ -30,40 +30,41 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  * CopyRight (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 
 #include <sys/ipc.h>
 #include <sys/msg.h>
 #include <sys/shm.h>
 
 #include "DiskdFile.h"
 #include "ConfigOption.h"
 #include "diomsg.h"
 
 #include "DiskdIOStrategy.h"
 #include "DiskIO/IORequestor.h"
 #include "DiskIO/ReadRequest.h"
 #include "DiskIO/WriteRequest.h"
+#include "StatCounters.h"
 CBDATA_CLASS_INIT(DiskdFile);
 
 void *
 DiskdFile::operator new(size_t unused)
 {
     CBDATA_INIT_TYPE(DiskdFile);
     DiskdFile *result = cbdataAlloc(DiskdFile);
     /* Mark result as being owned - we want the refcounter to do the delete
      * call */
     debugs(79, 3, "diskdFile with base " << result << " allocating");
     return result;
 }
 
 void
 DiskdFile::operator delete(void *address)
 {
     DiskdFile *t = static_cast<DiskdFile *>(address);
     debugs(79, 3, "diskdFile with base " << t << " deleting");
     cbdataFree(t);
 }
@@ -258,58 +259,58 @@
         readDone(M);
         break;
 
     case _MQD_WRITE:
         writeDone(M);
         break;
 
     case _MQD_UNLINK:
         assert (0);
         break;
 
     default:
         assert(0);
         break;
     }
 }
 
 void
 DiskdFile::openDone(diomsg *M)
 {
-    statCounter.syscalls.disk.opens++;
+    ++statCounter.syscalls.disk.opens;
     debugs(79, 3, "storeDiskdOpenDone: status " << M->status);
 
     if (M->status < 0) {
         diskd_stats.open.fail++;
         errorOccured = true;
     } else {
         diskd_stats.open.success++;
     }
 
     ioCompleted();
     notifyClient();
 }
 
 void
 DiskdFile::createDone(diomsg *M)
 {
-    statCounter.syscalls.disk.opens++;
+    ++statCounter.syscalls.disk.opens;
     debugs(79, 3, "storeDiskdCreateDone: status " << M->status);
 
     if (M->status < 0) {
         diskd_stats.create.fail++;
         errorOccured = true;
     } else {
         diskd_stats.create.success++;
     }
 
     ioCompleted();
     notifyClient();
 }
 
 void
 DiskdFile::write(WriteRequest *aRequest)
 {
     debugs(79, 3, "DiskdFile::write: this " << (void *)this << ", buf " << (void *)aRequest->buf << ", off " << aRequest->offset << ", len " << aRequest->len);
     ssize_t shm_offset;
     char *sbuf = (char *)IO->shm.get(&shm_offset);
     memcpy(sbuf, aRequest->buf, aRequest->len);
@@ -338,86 +339,86 @@
     }
 
     diskd_stats.write.ops++;
 }
 
 void
 DiskdFile::ioAway()
 {
     ++inProgressIOs;
 }
 
 void
 DiskdFile::ioCompleted()
 {
     --inProgressIOs;
 }
 
 void
 DiskdFile::closeDone(diomsg * M)
 {
-    statCounter.syscalls.disk.closes++;
+    ++statCounter.syscalls.disk.closes;
     debugs(79, 3, "DiskdFile::closeDone: status " << M->status);
 
     if (M->status < 0) {
         diskd_stats.close.fail++;
         errorOccured = true;
     } else {
         diskd_stats.close.success++;
     }
 
     ioCompleted();
 
     if (canNotifyClient())
         ioRequestor->closeCompleted();
 
     ioRequestor = NULL;
 }
 
 void
 DiskdFile::readDone(diomsg * M)
 {
-    statCounter.syscalls.disk.reads++;
+    ++statCounter.syscalls.disk.reads;
     debugs(79, 3, "DiskdFile::readDone: status " << M->status);
     assert (M->requestor);
     ReadRequest::Pointer readRequest = dynamic_cast<ReadRequest *>(M->requestor);
     /* remove the free protection */
     readRequest->RefCountDereference();
 
     if (M->status < 0) {
         diskd_stats.read.fail++;
         ioCompleted();
         errorOccured = true;
         ioRequestor->readCompleted(NULL, -1, DISK_ERROR, readRequest);
         return;
     }
 
     diskd_stats.read.success++;
 
     ioCompleted();
     ioRequestor->readCompleted (IO->shm.buf + M->shm_offset,  M->status, DISK_OK, readRequest);
 }
 
 void
 DiskdFile::writeDone(diomsg *M)
 {
-    statCounter.syscalls.disk.writes++;
+    ++statCounter.syscalls.disk.writes;
     debugs(79, 3, "storeDiskdWriteDone: status " << M->status);
     assert (M->requestor);
     WriteRequest::Pointer writeRequest = dynamic_cast<WriteRequest *>(M->requestor);
     /* remove the free protection */
     writeRequest->RefCountDereference();
 
     if (M->status < 0) {
         errorOccured = true;
         diskd_stats.write.fail++;
         ioCompleted();
         ioRequestor->writeCompleted (DISK_ERROR,0, writeRequest);
         return;
     }
 
     diskd_stats.write.success++;
     ioCompleted();
     ioRequestor->writeCompleted (DISK_OK,M->status, writeRequest);
 }
 
 bool

=== modified file 'src/DiskIO/DiskDaemon/DiskdIOStrategy.cc'
--- src/DiskIO/DiskDaemon/DiskdIOStrategy.cc	2011-10-27 23:14:28 +0000
+++ src/DiskIO/DiskDaemon/DiskdIOStrategy.cc	2011-12-10 15:24:11 +0000
@@ -29,40 +29,41 @@
  *  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.
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "comm/Loops.h"
 
 #include <sys/ipc.h>
 #include <sys/msg.h>
 #include <sys/shm.h>
 #include "DiskdIOStrategy.h"
 #include "ConfigOption.h"
 #include "DiskIO/DiskFile.h"
 #include "DiskdFile.h"
 #include "diomsg.h"
 /* for statfs */
 #include "Store.h"
+#include "StatCounters.h"
 #include "SquidTime.h"
 
 diskd_stats_t diskd_stats;
 
 size_t DiskdIOStrategy::nextInstanceID (0);
 const int diomsg::msg_snd_rcv_sz = sizeof(diomsg) - sizeof(mtyp_t);
 
 size_t
 DiskdIOStrategy::newInstance()
 {
     return ++nextInstanceID;
 }
 
 bool
 DiskdIOStrategy::shedLoad()
 {
     /*
      * Fail on open() if there are too many requests queued.
      */
 
@@ -276,41 +277,41 @@
     buf = (char *)shmat(id, NULL, 0);
 
     if (buf == (void *) -1) {
         debugs(50, 0, "storeDiskdInit: shmat: " << xstrerror());
         fatal("shmat failed");
     }
 
     inuse_map = (char *)xcalloc((nbufs + 7) / 8, 1);
     diskd_stats.shmbuf_count += nbufs;
 
     for (int i = 0; i < nbufs; i++) {
         CBIT_SET(inuse_map, i);
         put (i * SHMBUF_BLKSZ);
     }
 }
 
 void
 DiskdIOStrategy::unlinkDone(diomsg * M)
 {
     debugs(79, 3, "storeDiskdUnlinkDone: file " << shm.buf + M->shm_offset << " status " << M->status);
-    statCounter.syscalls.disk.unlinks++;
+    ++statCounter.syscalls.disk.unlinks;
 
     if (M->status < 0)
         diskd_stats.unlink.fail++;
     else
         diskd_stats.unlink.success++;
 }
 
 void
 DiskdIOStrategy::handle(diomsg * M)
 {
     if (!cbdataReferenceValid (M->callback_data)) {
         /* I.e. already closed file
          * - say when we have a error opening after
          *   a read was already queued
          */
         debugs(79, 3, "storeDiskdHandle: Invalid callback_data " << M->callback_data);
         cbdataReferenceDone (M->callback_data);
         return;
     }
 

=== modified file 'src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc'
--- src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc	2009-03-31 12:39:30 +0000
+++ src/DiskIO/DiskThreads/DiskThreadsDiskFile.cc	2011-12-10 15:24:11 +0000
@@ -24,40 +24,41 @@
  *  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.
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 
 #include "squid.h"
 #include "DiskThreadsDiskFile.h"
 #include "Store.h"
 #include "Generic.h"
 #include "DiskIO/IORequestor.h"
 #include "DiskIO/ReadRequest.h"
 #include "DiskIO/WriteRequest.h"
+#include "StatCounters.h"
 
 /* === PUBLIC =========================================================== */
 
 CBDATA_CLASS_INIT(DiskThreadsDiskFile);
 void *
 DiskThreadsDiskFile::operator new (size_t)
 {
     CBDATA_INIT_TYPE(DiskThreadsDiskFile);
     DiskThreadsDiskFile *result = cbdataAlloc(DiskThreadsDiskFile);
     /*
      * We used to call squidaio_init() here, but if the first transaction
      * is to unlink a file (e.g., if Squid starts up over the disk space
      * limit) then "squidaio" won't be initialized yet.
      */
 
     return result;
 }
 
 void
 DiskThreadsDiskFile::operator delete(void *address)
@@ -66,90 +67,90 @@
     cbdataFree(t);
 }
 
 DiskThreadsDiskFile::DiskThreadsDiskFile(char const *aPath, DiskThreadsIOStrategy *anIO):fd(-1), errorOccured (false), IO(anIO),
         inProgressIOs (0)
 {
     assert (aPath);
     debugs(79, 3, "UFSFile::UFSFile: " << aPath);
     path_ = xstrdup (aPath);
 }
 
 DiskThreadsDiskFile::~DiskThreadsDiskFile()
 {
     safe_free (path_);
     doClose();
 }
 
 void
 DiskThreadsDiskFile::open(int flags, mode_t mode, RefCount<IORequestor> callback)
 {
-    statCounter.syscalls.disk.opens++;
+    ++statCounter.syscalls.disk.opens;
 #if !ASYNC_OPEN
 
     fd = file_open(path_, flags);
 
     if (fd < 0) {
         debugs(79, 3, "DiskThreadsDiskFile::open: got failure (" << errno << ")");
         errorOccured = true;
         return;
     }
 
 #endif
     Opening_FD++;
 
     ioRequestor = callback;
 
     ++inProgressIOs;
 
 #if ASYNC_OPEN
 
     aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
 
 #else
 
     openDone(fd, NULL, fd, 0);
 
 #endif
 }
 
 void
 DiskThreadsDiskFile::read(ReadRequest * request)
 {
     debugs(79, 3, "DiskThreadsDiskFile::read: " << this << ", size " << request->len);
     assert (fd > -1);
     assert (ioRequestor.getRaw());
-    statCounter.syscalls.disk.reads++;
+    ++statCounter.syscalls.disk.reads;
     ++inProgressIOs;
 #if ASYNC_READ
 
     aioRead(fd, request->offset, request->len, ReadDone, new IoResult<ReadRequest>(this, request));
 #else
 
     file_read(fd, request->buf, request->len, request->offset, ReadDone, new IoResult<ReadRequest>(this, request));
 #endif
 }
 
 void
 DiskThreadsDiskFile::create(int flags, mode_t mode, RefCount<IORequestor> callback)
 {
-    statCounter.syscalls.disk.opens++;
+    ++statCounter.syscalls.disk.opens;
 #if !ASYNC_CREATE
 
     int fd = file_open(path_, flags);
 
     if (fd < 0) {
         debugs(79, 3, "DiskThreadsDiskFile::create: got failure (" << errno << ")");
         errorOccured = true;
         return;
     }
 
 #endif
     Opening_FD++;
 
     ioRequestor = callback;
 
     ++inProgressIOs;
 
 #if ASYNC_CREATE
 
     aioOpen(path_, flags, mode, DiskThreadsDiskFile::OpenDone, this);
@@ -186,41 +187,41 @@
         errno = errflag;
         debugs(79, 0, "DiskThreadsDiskFile::openDone: " << xstrerror());
         debugs(79, 1, "\t" << path_);
         errorOccured = true;
     } else {
         store_open_disk_fd++;
         commSetCloseOnExec(fd);
         fd_open(fd, FD_FILE, path_);
     }
 
     IORequestor::Pointer t = ioRequestor;
     --inProgressIOs;
     t->ioCompletedNotification();
 
     debugs(79, 3, "DiskThreadsDiskFile::openDone: exiting");
 }
 
 void DiskThreadsDiskFile::doClose()
 {
     if (fd > -1) {
-        statCounter.syscalls.disk.closes++;
+        ++statCounter.syscalls.disk.closes;
 #if ASYNC_CLOSE
 
         aioClose(fd);
         fd_close(fd);
 #else
 
         aioCancel(fd);
         file_close(fd);
 #endif
 
         store_open_disk_fd--;
         fd = -1;
     }
 }
 
 void
 DiskThreadsDiskFile::close()
 {
     debugs(79, 3, "DiskThreadsDiskFile::close: " << this << " closing for " << ioRequestor.getRaw());
 
@@ -229,41 +230,41 @@
         assert (ioRequestor != NULL);
         ioRequestor->closeCompleted();
         return;
     } else {
         debugs(79,0,HERE << "DiskThreadsDiskFile::close: " <<
                "did NOT close because ioInProgress() is true.  now what?");
     }
 }
 
 bool
 DiskThreadsDiskFile::canRead() const
 {
     debugs(79, 3, "DiskThreadsDiskFile::canRead: fd is " << fd);
     return fd > -1;
 }
 
 void
 DiskThreadsDiskFile::write(WriteRequest * writeRequest)
 {
     debugs(79, 3, "DiskThreadsDiskFile::write: FD " << fd);
-    statCounter.syscalls.disk.writes++;
+    ++statCounter.syscalls.disk.writes;
     ++inProgressIOs;
 #if ASYNC_WRITE
 
     aioWrite(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
              writeRequest->free_func);
 #else
 
     file_write(fd, writeRequest->offset, (char *)writeRequest->buf, writeRequest->len, WriteDone, new IoResult<WriteRequest>(this, writeRequest),
                writeRequest->free_func);
 #endif
 }
 
 bool
 DiskThreadsDiskFile::canWrite() const
 {
     return fd > -1;
 }
 
 bool
 DiskThreadsDiskFile::ioInProgress() const

=== modified file 'src/DiskIO/DiskThreads/DiskThreadsIOStrategy.cc'
--- src/DiskIO/DiskThreads/DiskThreadsIOStrategy.cc	2011-10-27 23:14:28 +0000
+++ src/DiskIO/DiskThreads/DiskThreadsIOStrategy.cc	2011-12-10 15:24:11 +0000
@@ -23,40 +23,41 @@
  *  (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.
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 
 #include "DiskThreadsDiskFile.h"
 #include "DiskThreadsIOStrategy.h"
 #include "fde.h"
 #include "mgr/Registration.h"
+#include "StatCounters.h"
 /* for statfs */
 #include "Store.h"
 
 
 void
 DiskThreadsIOStrategy::init(void)
 {
     if (initialised)
         return;
 
     squidaio_ctrl_pool = memPoolCreate("aio_ctrl", sizeof(squidaio_ctrl_t));
 
     initialised = true;
 
     /*
      * We'd like to call squidaio_init() here, but the configuration
      * hasn't been parsed yet and we don't know how many cache_dirs
      * there are, which means we don't know how many threads to start.
      */
 
@@ -246,23 +247,23 @@
 
 DiskFile::Pointer
 DiskThreadsIOStrategy::newFile (char const *path)
 {
     if (shedLoad()) {
         return NULL;
     }
 
     return new DiskThreadsDiskFile (path, this);
 }
 
 bool
 DiskThreadsIOStrategy::unlinkdUseful() const
 {
     return false;
 }
 
 void
 DiskThreadsIOStrategy::unlinkFile(char const *path)
 {
-    statCounter.syscalls.disk.unlinks++;
+    ++statCounter.syscalls.disk.unlinks;
     aioUnlink(path, NULL, NULL);
 }

=== modified file 'src/DiskIO/IpcIo/IpcIoFile.cc'
--- src/DiskIO/IpcIo/IpcIoFile.cc	2011-10-28 01:07:48 +0000
+++ src/DiskIO/IpcIo/IpcIoFile.cc	2011-12-10 15:24:30 +0000
@@ -1,39 +1,40 @@
 /*
  * $Id$
  *
  * DEBUG: section 47    Store Directory Routines
  */
 
 #include "config.h"
 #include "base/RunnersRegistry.h"
 #include "base/TextException.h"
 #include "DiskIO/IORequestor.h"
 #include "DiskIO/IpcIo/IpcIoFile.h"
 #include "DiskIO/ReadRequest.h"
 #include "DiskIO/WriteRequest.h"
 #include "ipc/Messages.h"
 #include "ipc/Port.h"
 #include "ipc/Queue.h"
 #include "ipc/StrandSearch.h"
 #include "ipc/UdsOp.h"
 #include "ipc/mem/Pages.h"
+#include "StatCounters.h"
 #include "SquidTime.h"
 
 CBDATA_CLASS_INIT(IpcIoFile);
 
 /// shared memory segment path to use for IpcIoFile maps
 static const char *const ShmLabel = "io_file";
 /// a single worker-to-disker or disker-to-worker queue capacity; up
 /// to 2*QueueCapacity I/O requests queued between a single worker and
 /// a single disker
 // TODO: make configurable or compute from squid.conf settings if possible
 static const int QueueCapacity = 1024;
 
 const double IpcIoFile::Timeout = 7; // seconds;  XXX: ALL,9 may require more
 IpcIoFile::IpcIoFileList IpcIoFile::WaitingForOpen;
 IpcIoFile::IpcIoFilesMap IpcIoFile::IpcIoFiles;
 std::auto_ptr<IpcIoFile::Queue> IpcIoFile::queue;
 
 bool IpcIoFile::DiskerHandleMoreRequestsScheduled = false;
 
 static bool DiskerOpen(const String &path, int flags, mode_t mode);
@@ -611,63 +612,63 @@
     }
 }
 
 
 
 /* XXX: disker code that should probably be moved elsewhere */
 
 static int TheFile = -1; ///< db file descriptor
 
 static void
 diskerRead(IpcIoMsg &ipcIo)
 {
     if (!Ipc::Mem::GetPage(Ipc::Mem::PageId::ioPage, ipcIo.page)) {
         ipcIo.len = 0;
         debugs(47,2, HERE << "run out of shared memory pages for IPC I/O");
         return;
     }
 
     char *const buf = Ipc::Mem::PagePointer(ipcIo.page);
     const ssize_t read = pread(TheFile, buf, min(ipcIo.len, Ipc::Mem::PageSize()), ipcIo.offset);
-    statCounter.syscalls.disk.reads++;
+    ++statCounter.syscalls.disk.reads;
     fd_bytes(TheFile, read, FD_READ);
 
     if (read >= 0) {
         ipcIo.xerrno = 0;
         const size_t len = static_cast<size_t>(read); // safe because read > 0
         debugs(47,8, HERE << "disker" << KidIdentifier << " read " <<
                (len == ipcIo.len ? "all " : "just ") << read);
         ipcIo.len = len;
     } else {
         ipcIo.xerrno = errno;
         ipcIo.len = 0;
         debugs(47,5, HERE << "disker" << KidIdentifier << " read error: " <<
                ipcIo.xerrno);
     }
 }
 
 static void
 diskerWrite(IpcIoMsg &ipcIo)
 {
     const char *const buf = Ipc::Mem::PagePointer(ipcIo.page);
     const ssize_t wrote = pwrite(TheFile, buf, min(ipcIo.len, Ipc::Mem::PageSize()), ipcIo.offset);
-    statCounter.syscalls.disk.writes++;
+    ++statCounter.syscalls.disk.writes;
     fd_bytes(TheFile, wrote, FD_WRITE);
 
     if (wrote >= 0) {
         ipcIo.xerrno = 0;
         const size_t len = static_cast<size_t>(wrote); // safe because wrote > 0
         debugs(47,8, HERE << "disker" << KidIdentifier << " wrote " <<
                (len == ipcIo.len ? "all " : "just ") << wrote);
         ipcIo.len = len;
     } else {
         ipcIo.xerrno = errno;
         ipcIo.len = 0;
         debugs(47,5, HERE << "disker" << KidIdentifier << " write error: " <<
                ipcIo.xerrno);
     }
 
     Ipc::Mem::PutPage(ipcIo.page);
 }
 
 
 void

=== modified file 'src/HttpHdrCc.cc'
--- src/HttpHdrCc.cc	2011-10-05 00:19:46 +0000
+++ src/HttpHdrCc.cc	2011-12-09 20:34:51 +0000
@@ -15,43 +15,45 @@
  *  sources; 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 "squid.h"
 #include "base/StringArea.h"
-#include "Store.h"
 #include "HttpHeader.h"
+#include "HttpHeaderStat.h"
 #include "HttpHdrCc.h"
+#include "StatHist.h"
+#include "Store.h"
 
 #if HAVE_MAP
 #include <map>
 #endif
 
 /* a row in the table used for parsing cache control header and statistics */
 typedef struct {
     const char *name;
     http_hdr_cc_type id;
     HttpHeaderFieldStat stat;
 } HttpHeaderCcFields;
 
 /* order must match that of enum http_hdr_cc_type. The constraint is verified at initialization time */
 static HttpHeaderCcFields CcAttrs[CC_ENUM_END] = {
     {"public", CC_PUBLIC},
     {"private", CC_PRIVATE},
     {"no-cache", CC_NO_CACHE},
     {"no-store", CC_NO_STORE},
     {"no-transform", CC_NO_TRANSFORM},
     {"must-revalidate", CC_MUST_REVALIDATE},
@@ -268,39 +270,39 @@
                 break;
             }
 
             ++pcount;
         }
     }
 
     if (other.size() != 0)
         packerPrintf(p, (pcount ? ", " SQUIDSTRINGPH : SQUIDSTRINGPH),
                      SQUIDSTRINGPRINT(other));
 }
 
 void
 httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist)
 {
     http_hdr_cc_type c;
     assert(cc);
 
     for (c = CC_PUBLIC; c < CC_ENUM_END; ++c)
         if (cc->isSet(c))
-            statHistCount(hist, c);
+            hist->count(c);
 }
 
 void
 httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count)
 {
     extern const HttpHeaderStat *dump_stat;	/* argh! */
     const int id = (int) val;
     const int valid_id = id >= 0 && id < CC_ENUM_END;
     const char *name = valid_id ? CcAttrs[id].name : "INVALID";
 
     if (count || valid_id)
         storeAppendPrintf(sentry, "%2d\t %-20s\t %5d\t %6.2f\n",
                           id, name, count, xdiv(count, dump_stat->ccParsedCount));
 }
 
 #if !_USE_INLINE_
 #include "HttpHdrCc.cci"
 #endif

=== modified file 'src/HttpHdrSc.cc'
--- src/HttpHdrSc.cc	2011-12-04 01:33:38 +0000
+++ src/HttpHdrSc.cc	2011-12-09 20:35:32 +0000
@@ -22,40 +22,41 @@
  *
  *  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 "squid.h"
 #include "Store.h"
 #include "HttpHeader.h"
+#include "HttpHeaderStat.h"
 #include "HttpHdrSc.h"
 
 #if HAVE_MAP
 #include <map>
 #endif
 
 /* a row in the table used for parsing surrogate-control header and statistics */
 typedef struct {
     const char *name;
     http_hdr_sc_type id;
     HttpHeaderFieldStat stat;
 } HttpHeaderScFields;
 
 /* this table is used for parsing surrogate control header */
 /* order must match that of enum http_hdr_sc_type. The constraint is verified at initialization time */
 //todo: implement constraint
 static const HttpHeaderFieldAttrs ScAttrs[SC_ENUM_END] = {
     {"no-store", (http_hdr_type)SC_NO_STORE},
     {"no-store-remote", (http_hdr_type)SC_NO_STORE_REMOTE},
     {"max-age", (http_hdr_type)SC_MAX_AGE},

=== modified file 'src/HttpHdrScTarget.cc'
--- src/HttpHdrScTarget.cc	2011-12-03 12:40:23 +0000
+++ src/HttpHdrScTarget.cc	2011-12-09 15:14:10 +0000
@@ -20,56 +20,57 @@
  *  sources; 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 "squid.h"
 #include "HttpHdrSc.h"
+#include "StatHist.h"
 
 extern http_hdr_sc_type &operator++ (http_hdr_sc_type &aHeader);
 /* copies non-extant fields from new_sc to this sc */
 void
 HttpHdrScTarget::mergeWith(const HttpHdrScTarget * new_sc)
 {
     assert(new_sc);
     /* Don't touch the target - this is used to get the operations for a
      * single surrogate
      */
 
     if (new_sc->hasNoStore())
         noStore(true);
 
     if (new_sc->hasNoStoreRemote())
         noStoreRemote(true);
 
     if (new_sc->hasMaxAge() && !hasMaxAge()) {
         maxAge(new_sc->maxAge());
         maxStale(new_sc->maxStale());
     }
 
     if (new_sc->hasContent() && !hasContent())
         Content(new_sc->content());
 
 }
 
 void
 HttpHdrScTarget::updateStats(StatHist * hist) const
 {
     http_hdr_sc_type c;
 
     for (c = SC_NO_STORE; c < SC_ENUM_END; ++c)
         if (isSet(c))
-            statHistCount(hist, c);
+            hist->count(c);
 }

=== modified file 'src/HttpHeader.cc'
--- src/HttpHeader.cc	2011-12-03 12:40:23 +0000
+++ src/HttpHeader.cc	2011-12-12 18:31:54 +0000
@@ -22,43 +22,45 @@
  *  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 "squid.h"
 #include "base64.h"
 #include "HttpHdrContRange.h"
 #include "HttpHdrCc.h"
 #include "HttpHdrSc.h"
 #include "HttpHeader.h"
+#include "HttpHeaderStat.h"
 #include "MemBuf.h"
 #include "mgr/Registration.h"
 #include "rfc1123.h"
+#include "StatHist.h"
 #include "Store.h"
 #include "TimeOrTag.h"
 
 /*
  * On naming conventions:
  *
  * HTTP/1.1 defines message-header as
  *
  * message-header = field-name ":" [ field-value ] CRLF
  * field-name     = token
  * field-value    = *( field-content | LWS )
  *
  * HTTP/1.1 does not give a name name a group of all message-headers in a message.
  * Squid 1.1 seems to refer to that group _plus_ start-line as "headers".
  *
  * HttpHeader is an object that represents all message-headers in a message.
  * HttpHeader does not manage start-line.
  *
  * HttpHeader is implemented as a collection of header "entries".
  * An entry is a (field_id, field_name, field_value) triplet.
@@ -353,44 +355,44 @@
 
     httpHeaderRegisterWithCacheManager();
 }
 
 void
 httpHeaderCleanModule(void)
 {
     httpHeaderDestroyFieldsInfo(Headers, HDR_ENUM_END);
     Headers = NULL;
     httpHdrCcCleanModule();
     httpHdrScCleanModule();
 }
 
 static void
 httpHeaderStatInit(HttpHeaderStat * hs, const char *label)
 {
     assert(hs);
     assert(label);
     memset(hs, 0, sizeof(HttpHeaderStat));
     hs->label = label;
-    statHistEnumInit(&hs->hdrUCountDistr, 32);	/* not a real enum */
-    statHistEnumInit(&hs->fieldTypeDistr, HDR_ENUM_END);
-    statHistEnumInit(&hs->ccTypeDistr, CC_ENUM_END);
-    statHistEnumInit(&hs->scTypeDistr, SC_ENUM_END);
+    hs->hdrUCountDistr.enumInit(32);	/* not a real enum */
+    hs->fieldTypeDistr.enumInit(HDR_ENUM_END);
+    hs->ccTypeDistr.enumInit(CC_ENUM_END);
+    hs->scTypeDistr.enumInit(SC_ENUM_END);
 }
 
 /*
  * HttpHeader Implementation
  */
 
 HttpHeader::HttpHeader() : owner (hoNone), len (0)
 {
     httpHeaderMaskInit(&mask, 0);
 }
 
 HttpHeader::HttpHeader(const http_hdr_owner_type anOwner): owner(anOwner), len(0)
 {
     assert(anOwner > hoNone && anOwner < hoEnd);
     debugs(55, 7, "init-ing hdr: " << this << " owner: " << owner);
     httpHeaderMaskInit(&mask, 0);
 }
 
 HttpHeader::HttpHeader(const HttpHeader &other): owner(other.owner), len(other.len)
 {
@@ -423,53 +425,53 @@
     HttpHeaderEntry *e;
 
     assert(owner > hoNone && owner < hoEnd);
     debugs(55, 7, "cleaning hdr: " << this << " owner: " << owner);
 
     PROF_start(HttpHeaderClean);
 
     /*
      * An unfortunate bug.  The entries array is initialized
      * such that count is set to zero.  httpHeaderClean() seems to
      * be called both when 'hdr' is created, and destroyed.  Thus,
      * we accumulate a large number of zero counts for 'hdr' before
      * it is ever used.  Can't think of a good way to fix it, except
      * adding a state variable that indicates whether or not 'hdr'
      * has been used.  As a hack, just never count zero-sized header
      * arrays.
      */
 
     if (owner <= hoReply) {
         if (0 != entries.count)
-            statHistCount(&HttpHeaderStats[owner].hdrUCountDistr, entries.count);
+            HttpHeaderStats[owner].hdrUCountDistr.count(entries.count);
 
         HttpHeaderStats[owner].destroyedCount++;
 
         HttpHeaderStats[owner].busyDestroyedCount += entries.count > 0;
 
         while ((e = getEntry(&pos))) {
             /* tmp hack to try to avoid coredumps */
 
             if (e->id < 0 || e->id >= HDR_ENUM_END) {
                 debugs(55, 0, "HttpHeader::clean BUG: entry[" << pos << "] is invalid (" << e->id << "). Ignored.");
             } else {
-                statHistCount(&HttpHeaderStats[owner].fieldTypeDistr, e->id);
+                HttpHeaderStats[owner].fieldTypeDistr.count(e->id);
                 /* yes, this deletion leaves us in an inconsistent state */
                 delete e;
             }
         }
     } // if (owner <= hoReply)
     entries.clean();
     httpHeaderMaskInit(&mask, 0);
     len = 0;
     PROF_stop(HttpHeaderClean);
 }
 
 /* append entries (also see httpHeaderUpdate) */
 void
 HttpHeader::append(const HttpHeader * src)
 {
     const HttpHeaderEntry *e;
     HttpHeaderPos pos = HttpHeaderInitPos;
     assert(src);
     assert(src != this);
     debugs(55, 7, "appending hdr: " << this << " += " << src);
@@ -1670,53 +1672,53 @@
 static void
 httpHeaderFldsPerHdrDumper(StoreEntry * sentry, int idx, double val, double size, int count)
 {
     if (count)
         storeAppendPrintf(sentry, "%2d\t %5d\t %5d\t %6.2f\n",
                           idx, (int) val, count,
                           xpercent(count, dump_stat->destroyedCount));
 }
 
 
 static void
 httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e)
 {
     assert(hs && e);
 
     dump_stat = hs;
     storeAppendPrintf(e, "\nHeader Stats: %s\n", hs->label);
     storeAppendPrintf(e, "\nField type distribution\n");
     storeAppendPrintf(e, "%2s\t %-20s\t %5s\t %6s\n",
                       "id", "name", "count", "#/header");
-    statHistDump(&hs->fieldTypeDistr, e, httpHeaderFieldStatDumper);
+    hs->fieldTypeDistr.dump(e, httpHeaderFieldStatDumper);
     storeAppendPrintf(e, "\nCache-control directives distribution\n");
     storeAppendPrintf(e, "%2s\t %-20s\t %5s\t %6s\n",
                       "id", "name", "count", "#/cc_field");
-    statHistDump(&hs->ccTypeDistr, e, httpHdrCcStatDumper);
+    hs->ccTypeDistr.dump(e, httpHdrCcStatDumper);
     storeAppendPrintf(e, "\nSurrogate-control directives distribution\n");
     storeAppendPrintf(e, "%2s\t %-20s\t %5s\t %6s\n",
                       "id", "name", "count", "#/sc_field");
-    statHistDump(&hs->scTypeDistr, e, httpHdrScStatDumper);
+    hs->scTypeDistr.dump(e, httpHdrScStatDumper);
     storeAppendPrintf(e, "\nNumber of fields per header distribution\n");
     storeAppendPrintf(e, "%2s\t %-5s\t %5s\t %6s\n",
                       "id", "#flds", "count", "%total");
-    statHistDump(&hs->hdrUCountDistr, e, httpHeaderFldsPerHdrDumper);
+    hs->hdrUCountDistr.dump(e, httpHeaderFldsPerHdrDumper);
     dump_stat = NULL;
 }
 
 void
 httpHeaderStoreReport(StoreEntry * e)
 {
     int i;
     http_hdr_type ht;
     assert(e);
 
     HttpHeaderStats[0].parsedCount =
         HttpHeaderStats[hoRequest].parsedCount + HttpHeaderStats[hoReply].parsedCount;
     HttpHeaderStats[0].ccParsedCount =
         HttpHeaderStats[hoRequest].ccParsedCount + HttpHeaderStats[hoReply].ccParsedCount;
     HttpHeaderStats[0].destroyedCount =
         HttpHeaderStats[hoRequest].destroyedCount + HttpHeaderStats[hoReply].destroyedCount;
     HttpHeaderStats[0].busyDestroyedCount =
         HttpHeaderStats[hoRequest].busyDestroyedCount + HttpHeaderStats[hoReply].busyDestroyedCount;
 
     for (i = 1; i < HttpHeaderStatCount; i++) {

=== added file 'src/HttpHeaderStat.h'
--- src/HttpHeaderStat.h	1970-01-01 00:00:00 +0000
+++ src/HttpHeaderStat.h	2011-12-09 17:53:59 +0000
@@ -0,0 +1,32 @@
+/*
+ * HttpHeaderStat.h
+ *
+ *  Created on: Dec 9, 2011
+ *      Author: kinkie
+ */
+
+#ifndef HTTPHEADERSTAT_H_
+#define HTTPHEADERSTAT_H_
+
+/* per header statistics */
+
+#include "StatHist.h"
+class HttpHeaderStat {
+public:
+    const char *label;
+    HttpHeaderMask *owner_mask;
+
+    StatHist hdrUCountDistr;
+    StatHist fieldTypeDistr;
+    StatHist ccTypeDistr;
+    StatHist scTypeDistr;
+
+    int parsedCount;
+    int ccParsedCount;
+    int scParsedCount;
+    int destroyedCount;
+    int busyDestroyedCount;
+};
+
+
+#endif /* HTTPHEADERSTAT_H_ */

=== modified file 'src/Makefile.am'
--- src/Makefile.am	2011-12-07 18:56:59 +0000
+++ src/Makefile.am	2011-12-15 06:36:47 +0000
@@ -337,40 +337,41 @@
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	hier_code.h \
 	HierarchyLogEntry.h \
 	$(HTCPSOURCE) \
 	http.cc \
 	http.h \
 	HttpStatusCode.h \
 	HttpStatusLine.cc \
 	HttpStatusLine.h \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrSc.h \
 	HttpHdrScTarget.cc \
 	HttpHdrScTarget.h \
 	HttpHdrContRange.cc \
 	HttpHdrContRange.h \
+	HttpHeaderStat.h \
 	HttpHeader.cc \
 	HttpHeader.h \
 	HttpHeaderMask.h \
 	HttpHeaderRange.h \
 	HttpHeaderTools.cc \
 	HttpBody.h \
 	HttpBody.cc \
 	HttpControlMsg.h \
 	HttpMsg.cc \
 	HttpMsg.h \
 	HttpParser.cc \
 	HttpParser.h \
 	HttpReply.cc \
 	HttpReply.h \
 	HttpRequest.cc \
 	HttpRequest.h \
 	HttpRequestMethod.cc \
 	HttpRequestMethod.h \
 	HttpVersion.h \
 	ICP.h \
@@ -408,40 +409,43 @@
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	PeerSelectState.h \
 	PingData.h \
 	protos.h \
 	redirect.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	RemovalPolicy.h \
 	send-announce.cc \
 	$(SBUF_SOURCE) \
 	$(SNMP_SOURCE) \
 	squid.h \
 	SquidMath.h \
 	SquidMath.cc \
 	SquidNew.cc \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	String.cc \
 	stmem.cc \
 	stmem.h \
 	store.cc \
 	Store.h \
 	StoreFileSystem.cc \
 	StoreFileSystem.h \
 	StoreHashIndex.h \
 	store_io.cc \
 	StoreIOBuffer.h \
 	StoreIOState.cc \
 	StoreIOState.h \
 	store_client.cc \
 	StoreClient.h \
 	store_digest.cc \
 	store_dir.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
@@ -1064,40 +1068,43 @@
 	HttpMsg.cc \
 	HttpMsg.h \
 	HttpReply.cc \
 	HttpReply.h \
 	HttpStatusCode.h \
 	HttpStatusLine.cc \
 	HttpStatusLine.h \
 	mem.cc \
 	MemBuf.cc \
 	MemBuf.h \
 	mime_header.cc \
 	Packer.cc \
 	Packer.h \
 	SquidString.h \
 	SquidTime.h \
 	String.cc \
 	tests/stub_cache_cf.cc \
 	tests/stub_cache_manager.cc \
 	tests/stub_debug.cc \
 	tests/stub_HelperChildConfig.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	tests/stub_StatHist.cc \
 	tests/stub_store.cc \
 	tests/stub_store_stats.cc \
 	tests/testHttpReply.cc \
 	tests/testHttpReply.h \
 	tests/testMain.cc \
 	time.cc \
 	wordlist.cc
 nodist_tests_testHttpReply_SOURCES=\
 	$(TESTSOURCES)
 tests_testHttpReply_LDFLAGS = $(LIBADD_DL)
 tests_testHttpReply_LDADD=\
 	acl/libapi.la \
 	acl/libstate.la \
 	$(AUTH_LIBS) \
 	ip/libip.la \
 	base/libbase.la \
 	$(top_builddir)/lib/libmisccontainers.la \
 	$(top_builddir)/lib/libmiscencoding.la \
 	$(top_builddir)/lib/libmiscutil.la \
@@ -1141,40 +1148,42 @@
 	filemap.cc \
 	HelperChildConfig.h \
 	HelperChildConfig.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpMsg.cc \
 	HttpRequestMethod.cc \
 	int.cc \
 	list.cc \
 	mem_node.cc \
 	Packer.cc \
 	Parsing.cc \
 	SquidMath.cc \
+	StatCounters.h \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	String.cc \
 	store_dir.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
 	StoreMetaURL.cc \
 	StoreMetaVary.cc \
 	StoreSwapLogData.cc \
 	store_key_md5.cc \
 	swap_log_op.cc \
 	swap_log_op.h \
 	SwapDir.cc \
 	SwapDir.h \
 	tests/stub_access_log.cc \
 	tests/stub_cache_cf.cc \
@@ -1339,40 +1348,43 @@
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
@@ -1462,40 +1474,43 @@
 	HttpHdrContRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHdrRange.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	int.cc \
 	list.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mem_node.cc \
 	mem.cc \
 	Packer.cc \
 	Parsing.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
 	StoreMetaURL.cc \
 	StoreMetaVary.cc \
 	StoreSwapLogData.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_swapout.cc \
 	store_swapmeta.cc \
 	store.cc \
 	String.cc \
 	SwapDir.cc \
@@ -1666,40 +1681,43 @@
 	multicast.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	ProtoPort.cc \
 	ProtoPort.h \
 	redirect.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.cc \
 	SquidMath.h \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
@@ -1856,40 +1874,43 @@
 	multicast.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	ProtoPort.cc \
 	ProtoPort.h \
 	RemovalPolicy.cc \
 	redirect.cc \
 	refresh.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
@@ -2042,40 +2063,43 @@
 	mime.cc \
 	mime_header.cc \
 	multicast.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	pconn.cc \
 	redirect.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_key_md5.cc \
 	store_io.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
@@ -2266,40 +2290,43 @@
 	MemObject.cc \
 	mime.cc \
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	redirect.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
@@ -2381,40 +2408,43 @@
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	HttpMsg.cc \
 	HttpRequestMethod.cc \
 	int.cc \
 	list.cc \
 	mem.cc \
 	mem_node.cc \
 	MemBuf.cc \
 	Packer.cc \
 	Parsing.cc \
 	RemovalPolicy.cc \
 	refresh.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_swapout.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \
 	StoreMetaURL.cc \
 	StoreMetaVary.cc \
 	StoreSwapLogData.cc \
 	store_key_md5.cc \
 	String.cc \
 	SwapDir.cc \
 	tests/CapturingStoreEntry.h \
 	tests/stub_access_log.cc \
@@ -2613,40 +2643,43 @@
 	String.cc \
 	tests/stub_debug.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	mem_node.cc \
 	stmem.cc \
 	tests/stub_mime.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	mem.cc \
 	ClientInfo.h \
 	MemBuf.cc \
 	HttpHdrContRange.cc \
 	Packer.cc \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	url.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	HttpHdrRange.cc \
 	ETag.cc \
 	tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc \
 	tests/stub_access_log.cc \
 	refresh.cc \
 	tests/stub_store_client.cc \
 	tests/stub_tools.cc \
 	tests/testStoreSupport.cc \
 	tests/testStoreSupport.h \
 	time.cc \
 	URLScheme.cc \
 	wordlist.cc \
 	$(DISKIO_SOURCE)
 
 nodist_tests_testUfs_SOURCES = \
 	$(TESTSOURCES) \
 	$(DISKIO_GEN_SOURCE) \
 	SquidMath.cc \
@@ -2706,40 +2739,43 @@
 	HttpHdrCc.cc \
 	HttpHdrContRange.cc \
 	HttpHdrRange.cc \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	HttpHeader.cc \
 	HttpHeaderTools.cc \
 	HttpMsg.cc \
 	HttpReply.cc \
 	HttpRequestMethod.cc \
 	HttpStatusLine.cc \
 	int.cc \
 	list.cc \
 	mem.cc \
 	MemBuf.cc \
 	MemObject.cc \
 	mem_node.cc \
 	Packer.cc \
 	Parsing.cc \
 	RemovalPolicy.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaURL.cc \
 	StoreMetaUnpacker.cc \
 	StoreMetaVary.cc \
 	StoreSwapLogData.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	String.cc \
 	SwapDir.cc \
@@ -2874,40 +2910,43 @@
 	cbdata.cc \
 	String.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	mem_node.cc \
 	stmem.cc \
 	tests/stub_mime.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	mem.cc \
 	ClientInfo.h \
 	MemBuf.cc \
 	HttpHdrContRange.cc \
 	Packer.cc \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	url.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	HttpHdrRange.cc \
 	ETag.cc \
 	tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc \
 	tests/stub_access_log.cc \
 	refresh.cc \
 	tests/stub_MemStore.cc \
 	tests/stub_Port.cc \
 	tests/stub_store_client.cc \
 	tests/stub_store_stats.cc \
 	tests/stub_tools.cc \
 	tests/stub_UdsOp.cc \
 	tests/testStoreSupport.cc \
 	tests/testStoreSupport.h \
 	time.cc \
 	URLScheme.cc \
 	wordlist.cc \
 	$(DISKIO_SOURCE)
 
@@ -3009,40 +3048,43 @@
 	tests/stub_comm.cc \
 	tests/stub_debug.cc \
 	tests/stub_client_side_request.cc \
 	tests/stub_http.cc \
 	mem_node.cc \
 	stmem.cc \
 	tests/stub_mime.cc \
 	HttpHeaderTools.cc \
 	HttpHeader.cc \
 	mem.cc \
 	ClientInfo.h \
 	MemBuf.cc \
 	HttpHdrContRange.cc \
 	Packer.cc \
 	HttpHdrCc.h \
 	HttpHdrCc.cc \
 	HttpHdrCc.cci \
 	HttpHdrSc.cc \
 	HttpHdrScTarget.cc \
 	url.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	HttpHdrRange.cc \
 	ETag.cc \
 	tests/stub_errorpage.cc \
 	tests/stub_HttpRequest.cc \
 	tests/stub_access_log.cc \
 	refresh.cc \
 	tests/stub_store_client.cc \
 	tests/stub_store_stats.cc \
 	tests/stub_tools.cc \
 	tests/testStoreSupport.cc \
 	tests/testStoreSupport.h \
 	time.cc \
 	URLScheme.cc \
 	wordlist.cc \
 	$(DISKIO_SOURCE)
 
 nodist_tests_testNull_SOURCES = \
 	$(TESTSOURCES) \
 	$(DISKIO_GEN_SOURCE)
@@ -3159,40 +3201,43 @@
 	mime_header.cc \
 	neighbors.cc \
 	Packer.cc \
 	Parsing.cc \
 	pconn.cc \
 	peer_digest.cc \
 	peer_proxy_negotiate_auth.cc \
 	peer_select.cc \
 	peer_sourcehash.cc \
 	peer_userhash.cc \
 	ProtoPort.cc \
 	ProtoPort.h \
 	redirect.cc \
 	refresh.cc \
 	RemovalPolicy.cc \
 	Server.cc \
 	$(SNMP_SOURCE) \
 	SquidMath.h \
 	SquidMath.cc \
 	stat.cc \
+	StatCounters.h \
+	StatCounters.cc \
+	StatHist.h \
 	StatHist.cc \
 	stmem.cc \
 	store.cc \
 	store_client.cc \
 	store_digest.cc \
 	store_dir.cc \
 	store_io.cc \
 	store_key_md5.cc \
 	store_log.cc \
 	store_rebuild.cc \
 	store_swapin.cc \
 	store_swapmeta.cc \
 	store_swapout.cc \
 	StoreFileSystem.cc \
 	StoreIOState.cc \
 	StoreMeta.cc \
 	StoreMetaMD5.cc \
 	StoreMetaSTD.cc \
 	StoreMetaSTDLFS.cc \
 	StoreMetaUnpacker.cc \

=== modified file 'src/PeerDigest.h'
--- src/PeerDigest.h	2009-01-21 03:47:47 +0000
+++ src/PeerDigest.h	2011-12-15 21:17:34 +0000
@@ -23,40 +23,43 @@
  *  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.
  *
  */
 
 #ifndef   SQUID_PEERDIGEST_H
 #define   SQUID_PEERDIGEST_H
 
 #include "squid.h"
 
 #if USE_CACHE_DIGESTS
 
 #include "cbdata.h"
 
+/* for CacheDigestGuessStats */
+#include "StatCounters.h"
+
 struct _Version {
     short int current;		/* current version */
     short int required;		/* minimal version that can safely handle current version */
 };
 
 /* digest control block; used for transmission and storage */
 
 class StoreDigestCBlock
 {
 public:
     Version ver;
     int capacity;
     int count;
     int del_count;
     int mask_size;
     unsigned char bits_per_entry;
     unsigned char hash_func_count;
     short int reserved_short;
     int reserved[32 - 6];
 };
@@ -99,38 +102,38 @@
 
     struct {
         unsigned int needed:1;          /**< there were requests for this digest */
         unsigned int usable:1;          /**< can be used for lookups */
         unsigned int requested:1;       /**< in process of receiving [fresh] digest */
     } flags;
 
     struct {
         /* all times are absolute unless augmented with _delay */
         time_t initialized;	/* creation */
         time_t needed;		/* first lookup/use by a peer */
         time_t next_check;	/* next scheduled check/refresh event */
         time_t retry_delay;	/* delay before re-checking _invalid_ digest */
         time_t requested;	/* requested a fresh copy of a digest */
         time_t req_delay;	/* last request response time */
         time_t received;	/* received the current copy of a digest */
         time_t disabled;	/* disabled for good */
     } times;
 
     struct {
-        cd_guess_stats guess;
+        CacheDigestGuessStats guess;
         int used_count;
 
         struct {
             int msgs;
             kb_t kbytes;
         } sent, recv;
     } stats;
 
 private:
     CBDATA_CLASS(PeerDigest);
 };
 
 extern const Version CacheDigestVer;
 
 #endif /* USE_CACHE_DIGESTS */
 
 #endif /* SQUID_PEERDIGEST_H */

=== modified file 'src/Server.cc'
--- src/Server.cc	2011-11-27 12:37:35 +0000
+++ src/Server.cc	2011-12-10 15:30:19 +0000
@@ -27,40 +27,41 @@
  *  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 "squid.h"
 #include "acl/Gadgets.h"
 #include "base/TextException.h"
 #include "comm/Connection.h"
 #include "comm/forward.h"
 #include "comm/Write.h"
 #include "Server.h"
 #include "Store.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "errorpage.h"
 #include "err_detail_type.h"
+#include "StatCounters.h"
 #include "SquidTime.h"
 
 #if USE_ADAPTATION
 #include "adaptation/AccessCheck.h"
 #include "adaptation/Answer.h"
 #include "adaptation/Iterator.h"
 #include "base/AsyncCall.h"
 #endif
 
 // implemented in client_side_reply.cc until sides have a common parent
 extern void purgeEntriesByUrl(HttpRequest * req, const char *url);
 
 
 ServerStateData::ServerStateData(FwdState *theFwdState): AsyncJob("ServerStateData"),
         requestSender(NULL),
 #if USE_ADAPTATION
         adaptedHeadSource(NULL),
         adaptationAccessCheckPending(false),
         startedAdaptation(false),
 #endif
@@ -348,41 +349,41 @@
     if (requestSender != NULL)
         debugs(9,3, HERE << "fyi: request body aborted while we were sending");
 
     fwd->dontRetry(true); // the problem is not with the server
     stopConsumingFrom(requestBodySource); // requestSender, if any, will notice
 
     // kids extend this
 }
 
 // called when we wrote request headers(!) or a part of the body
 void
 ServerStateData::sentRequestBody(const CommIoCbParams &io)
 {
     debugs(11, 5, "sentRequestBody: FD " << io.fd << ": size " << io.size << ": errflag " << io.flag << ".");
     debugs(32,3,HERE << "sentRequestBody called");
 
     requestSender = NULL;
 
     if (io.size > 0) {
         fd_bytes(io.fd, io.size, FD_WRITE);
-        kb_incr(&statCounter.server.all.kbytes_out, io.size);
+        kb_incr(&(statCounter.server.all.kbytes_out), io.size);
         // kids should increment their counters
     }
 
     if (io.flag == COMM_ERR_CLOSING)
         return;
 
     if (!requestBodySource) {
         debugs(9,3, HERE << "detected while-we-were-sending abort");
         return; // do nothing;
     }
 
     if (io.flag) {
         debugs(11, 1, "sentRequestBody error: FD " << io.fd << ": " << xstrerr(io.xerrno));
         ErrorState *err;
         err = new ErrorState(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY, fwd->request);
         err->xerrno = io.xerrno;
         fwd->fail(err);
         abortTransaction("I/O error while sending request body");
         return;
     }

=== added file 'src/StatCounters.cc'
--- src/StatCounters.cc	1970-01-01 00:00:00 +0000
+++ src/StatCounters.cc	2011-12-10 16:49:40 +0000
@@ -0,0 +1,35 @@
+/*
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; 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.
+ *
+ *  AUTHOR: Francesco Chemolli (Harvest-derived)
+ *
+ */
+
+#include "config.h"
+#include "StatCounters.h"
+
+StatCounters statCounter;

=== added file 'src/StatCounters.h'
--- src/StatCounters.h	1970-01-01 00:00:00 +0000
+++ src/StatCounters.h	2011-12-15 21:17:34 +0000
@@ -0,0 +1,186 @@
+/*
+ * AUTHOR: Francesco Chemolli (Harvest-derived)
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; 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.
+ *
+ *
+ */
+#ifndef STATCOUNTERS_H_
+#define STATCOUNTERS_H_
+
+#include "StatHist.h"
+
+#if USE_CACHE_DIGESTS
+/** statistics for cache digests and other hit "predictors" */
+class CacheDigestGuessStats {
+public:
+    int trueHits;
+    int falseHits;
+    int trueMisses;
+    int falseMisses;
+    int closeHits;     /// \todo: temporary remove it later
+};
+#endif
+
+
+/** General collection of process-wide statistics.
+ *
+ * \note if you add a field to StatCounters,
+ * you MUST sync statCountersInitSpecial, statCountersClean, and statCountersCopy
+ */
+class StatCounters {
+public:
+    struct {
+        int clients;
+        int requests;
+        int hits;
+        int mem_hits;
+        int disk_hits;
+        int errors;
+        kb_t kbytes_in;
+        kb_t kbytes_out;
+        kb_t hit_kbytes_out;
+        StatHist missSvcTime;
+        StatHist nearMissSvcTime;
+        StatHist nearHitSvcTime;
+        StatHist hitSvcTime;
+        StatHist allSvcTime;
+    } client_http;
+
+    struct {
+
+        struct {
+            int requests;
+            int errors;
+            kb_t kbytes_in;
+            kb_t kbytes_out;
+        } all , http, ftp, other;
+    } server;
+
+    struct {
+        int pkts_sent;
+        int queries_sent;
+        int replies_sent;
+        int pkts_recv;
+        int queries_recv;
+        int replies_recv;
+        int hits_sent;
+        int hits_recv;
+        int replies_queued;
+        int replies_dropped;
+        kb_t kbytes_sent;
+        kb_t q_kbytes_sent;
+        kb_t r_kbytes_sent;
+        kb_t kbytes_recv;
+        kb_t q_kbytes_recv;
+        kb_t r_kbytes_recv;
+        StatHist querySvcTime;
+        StatHist replySvcTime;
+        int query_timeouts;
+        int times_used;
+    } icp;
+
+    struct {
+        int pkts_sent;
+        int pkts_recv;
+    } htcp;
+
+    struct {
+        int requests;
+    } unlink;
+
+    struct {
+        StatHist svcTime;
+    } dns;
+
+    struct {
+        int times_used;
+        kb_t kbytes_sent;
+        kb_t kbytes_recv;
+        kb_t memory;
+        int msgs_sent;
+        int msgs_recv;
+#if USE_CACHE_DIGESTS
+
+        CacheDigestGuessStats guess;
+#endif
+
+        StatHist on_xition_count;
+    } cd;
+
+    struct {
+        int times_used;
+    } netdb;
+    int page_faults;
+    unsigned long int select_loops;
+    int select_fds;
+    double select_time;
+    double cputime;
+
+    struct timeval timestamp;
+    StatHist comm_icp_incoming;
+    StatHist comm_dns_incoming;
+    StatHist comm_http_incoming;
+    StatHist select_fds_hist;
+
+    struct {
+        struct {
+            int opens;
+            int closes;
+            int reads;
+            int writes;
+            int seeks;
+            int unlinks;
+        } disk;
+
+        struct {
+            int accepts;
+            int sockets;
+            int connects;
+            int binds;
+            int closes;
+            int reads;
+            int writes;
+            int recvfroms;
+            int sendtos;
+        } sock;
+        int selects;
+    } syscalls;
+    int aborted_requests;
+
+    struct {
+        int files_cleaned;
+        int outs;
+        int ins;
+    } swap;
+
+private:
+};
+
+extern StatCounters statCounter;
+
+#endif /* STATCOUNTERS_H_ */

=== modified file 'src/StatHist.cc'
--- src/StatHist.cc	2010-12-16 02:25:55 +0000
+++ src/StatHist.cc	2011-12-15 23:07:34 +0000
@@ -1,327 +1,287 @@
 
 /*
- * $Id$
- *
  * DEBUG: section 62    Generic Histogram
  * AUTHOR: Duane Wessels
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
  * ----------------------------------------------------------
  *
  *  Squid is the result of efforts by numerous individuals from
  *  the Internet community; see the CONTRIBUTORS file for full
  *  details.   Many organizations have provided support for Squid's
  *  development; see the SPONSORS file for full details.  Squid is
  *  Copyrighted (C) 2001 by the Regents of the University of
  *  California; see the COPYRIGHT file for full details.  Squid
  *  incorporates software developed and/or copyrighted by other
  *  sources; 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.
  *
  */
 
-/*
- * Important restrictions on val_in and val_out functions:
- *
- *   - val_in:  ascending, defined on [0, oo), val_in(0) == 0;
- *   - val_out: x == val_out(val_in(x)) where val_in(x) is defined
- *
- *  In practice, the requirements are less strict,
- *  but then it gets hard to define them without math notation.
- *  val_in is applied after offseting the value but before scaling
- *  See log and linear based histograms for examples
- */
-
-#include "squid.h"
-#include "Store.h"
+#include "config.h"
+#include "StatHist.h"
 
 /* Local functions */
-static void statHistInit(StatHist * H, int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max);
-static int statHistBin(const StatHist * H, double v);
-static double statHistVal(const StatHist * H, int bin);
 static StatHistBinDumper statHistBinDumper;
 
 namespace Math
 {
 hbase_f Log;
 hbase_f Exp;
 hbase_f Null;
 };
 
 /* low level init, higher level functions has less params */
-static void
-statHistInit(StatHist * H, int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max)
+void
+StatHist::init(int capacity_, hbase_f * val_in_, hbase_f * val_out_, double min_, double max_)
 {
-    assert(H);
-    assert(capacity > 0);
-    assert(val_in && val_out);
+    assert(capacity_ > 0);
+    assert(val_in_ && val_out_);
     /* check before we divide to get scale */
-    assert(val_in(max - min) > 0);
-    H->bins = (int *)xcalloc(capacity, sizeof(int));
-    H->min = min;
-    H->max = max;
-    H->capacity = capacity;
-    H->scale = capacity / val_in(max - min);
-    H->val_in = val_in;
-    H->val_out = val_out;
-
-    /* HPUX users: If you get one of the assertions below, please send
-     * [at least] the values of all variables involved in the assertions
-     * when reporting a bug!
-     */
+    assert(val_in_(max_ - min_) > 0);
+    min = min_;
+    max = max_;
+    capacity = capacity_;
+    val_in = val_in_;
+    val_out = val_out_;
+    bins = static_cast<int *>(xcalloc(capacity, sizeof(int)));
+    scale = capacity / val_in(max - min);
 
     /* check that functions are valid */
     /* a min value should go into bin[0] */
-    assert(statHistBin(H, min) == 0);
+    assert(findBin(min) == 0);
     /* a max value should go into the last bin */
-    assert(statHistBin(H, max) == H->capacity - 1);
+    assert(findBin(max) == capacity - 1);
     /* it is hard to test val_out, here is a crude test */
-    assert(((int) floor(0.99 + statHistVal(H, 0) - min)) == 0);
+    assert(((int) floor(0.99 + val(0) - min)) == 0);
 }
 
 void
-statHistClean(StatHist * H)
+StatHist::clear()
 {
-    xfree(H->bins);
-    H->bins = NULL;
+    for(int i=0;i<capacity;++i)
+        bins[i]=0;
 }
 
-/* assumes that somebody already called init for Dest */
-void
-statHistCopy(StatHist * Dest, const StatHist * Orig)
+StatHist::~StatHist()
 {
-    assert(Dest);
-    assert(Orig);
-    debugs(62, 3, "statHistCopy: Dest=" << Dest << ", Orig=" << Orig);
-    assert(Dest->bins);
-    /* better be safe than sorry */
-    debugs(62, 3, "statHistCopy: capacity " << Dest->capacity << " " << Orig->capacity);
-    assert(Dest->capacity == Orig->capacity);
-    debugs(62, 3, "statHistCopy: min " << Dest->min << " " << Orig->min  );
-    assert(Dest->min == Orig->min);
-    debugs(62, 3, "statHistCopy: max " << Dest->max << " " << Orig->max  );
-    assert(Dest->max == Orig->max);
-    debugs(62, 3, "statHistCopy: scale " << Dest->scale << " " << Orig->scale  );
-    assert(fabs(Dest->scale - Orig->scale) < 0.0000001);
-    assert(Dest->val_in == Orig->val_in);
-    assert(Dest->val_out == Orig->val_out);
-    /* actual copy */
-    debugs(62, 3, "statHistCopy: copying " <<
-           (long int) (Dest->capacity * sizeof(*Dest->bins)) << " bytes to " <<
-           Dest->bins << " from " << Orig->bins);
-
-    memcpy(Dest->bins, Orig->bins, Dest->capacity * sizeof(*Dest->bins));
+    if (bins != NULL) {
+        xfree(bins);
+        bins = NULL;
+    }
 }
 
-/*
- * same as statHistCopy but will do nothing if capacities do not match; the
- * latter happens, for example, when #peers changes during reconfiguration;
- * if it happens too often we should think about more general solution..
- */
-void
-statHistSafeCopy(StatHist * Dest, const StatHist * Orig)
+StatHist&
+StatHist::operator =(const StatHist & src)
 {
-    assert(Dest && Orig);
-    assert(Dest->bins);
+    assert(src.bins != NULL); // TODO: remove after initializing bins at construction time
+    if (capacity != src.capacity) {
+        // need to resize.
+        xfree(bins);
+        bins = static_cast<int *>(xcalloc(src.capacity, sizeof(int)));
+        capacity=src.capacity;
 
-    if (Dest->capacity == Orig->capacity)
-        statHistCopy(Dest, Orig);
+    }
+    min=src.min;
+    max=src.max;
+    scale=src.scale;
+    val_in=src.val_in;
+    val_out=src.val_out;
+    memcpy(bins,src.bins,capacity*sizeof(*bins));
+    return *this;
 }
 
 void
-statHistCount(StatHist * H, double val)
+StatHist::count(double val)
 {
-    const int bin = statHistBin(H, val);
-    assert(H->bins);		/* make sure it got initialized */
-    assert(0 <= bin && bin < H->capacity);
-    H->bins[bin]++;
+    const int bin = findBin(val);
+    assert(bins);		/* make sure it got initialized */
+    assert(0 <= bin && bin < capacity);
+    ++bins[bin];
 }
 
-static int
-statHistBin(const StatHist * H, double v)
+int
+StatHist::findBin(double v)
 {
     int bin;
-#if BROKEN_STAT_HIST_BIN
-
-    return 0;
-    /* NOTREACHED */
-#endif
 
-    v -= H->min;		/* offset */
+    v -= min;		/* offset */
 
     if (v <= 0.0)		/* too small */
         return 0;
 
-    bin = (int) floor(H->scale * H->val_in(v) + 0.5);
+    bin = (int) floor(scale * val_in(v) + 0.5);
 
     if (bin < 0)		/* should not happen */
-        bin = 0;
+        return 0;
 
-    if (bin >= H->capacity)	/* too big */
-        bin = H->capacity - 1;
+    if (bin >= capacity)	/* too big */
+        bin = capacity - 1;
 
     return bin;
 }
 
-static double
-statHistVal(const StatHist * H, int bin)
+double
+StatHist::val(int bin) const
 {
-    return H->val_out((double) bin / H->scale) + H->min;
+    return val_out((double) bin / scale) + min;
 }
 
 double
-statHistDeltaMedian(const StatHist * A, const StatHist * B)
+statHistDeltaMedian(const StatHist & A, const StatHist & B)
 {
     return statHistDeltaPctile(A, B, 0.5);
 }
 
 double
-statHistDeltaPctile(const StatHist * A, const StatHist * B, double pctile)
+statHistDeltaPctile(const StatHist & A, const StatHist & B, double pctile)
+{
+    return A.deltaPctile(B, pctile);
+}
+
+double
+StatHist::deltaPctile(const StatHist & B, double pctile) const
 {
     int i;
     int s1 = 0;
     int h = 0;
     int a = 0;
     int b = 0;
     int I = 0;
-    int J = A->capacity;
+    int J = capacity;
     int K;
     double f;
-    int *D = (int *)xcalloc(A->capacity, sizeof(int));
-    assert(A->capacity == B->capacity);
 
-    for (i = 0; i < A->capacity; i++) {
-        D[i] = B->bins[i] - A->bins[i];
+    assert(capacity == B.capacity);
+
+    int *D = static_cast<int *>(xcalloc(capacity, sizeof(int)));
+
+    for (i = 0; i < capacity; ++i) {
+        D[i] = B.bins[i] - bins[i];
         assert(D[i] >= 0);
     }
 
-    for (i = 0; i < A->capacity; i++)
+    for (i = 0; i < capacity; ++i)
         s1 += D[i];
 
     h = int(s1 * pctile);
 
-    for (i = 0; i < A->capacity; i++) {
+    for (i = 0; i < capacity; ++i) {
         J = i;
         b += D[J];
 
         if (a <= h && h <= b)
             break;
 
         I = i;
 
         a += D[I];
     }
 
     xfree(D);
 
     if (s1 == 0)
         return 0.0;
 
     if (a > h)
         return 0.0;
 
     if (a >= b)
         return 0.0;
 
     if (I >= J)
         return 0.0;
 
     f = (h - a) / (b - a);
 
     K = (int) floor(f * (double) (J - I) + I);
 
-    return statHistVal(A, K);
+    return val(K);
 }
 
 static void
 statHistBinDumper(StoreEntry * sentry, int idx, double val, double size, int count)
 {
     if (count)
         storeAppendPrintf(sentry, "\t%3d/%f\t%d\t%f\n",
                           idx, val, count, count / size);
 }
 
 void
-statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd)
+StatHist::dump(StoreEntry * sentry, StatHistBinDumper * bd) const
 {
     int i;
-    double left_border = H->min;
+    double left_border = min;
 
     if (!bd)
         bd = statHistBinDumper;
 
-    for (i = 0; i < H->capacity; i++) {
-        const double right_border = statHistVal(H, i + 1);
+    for (i = 0; i < capacity; ++i) {
+        const double right_border = val(i + 1);
         assert(right_border - left_border > 0.0);
-        bd(sentry, i, left_border, right_border - left_border, H->bins[i]);
+        bd(sentry, i, left_border, right_border - left_border, bins[i]);
         left_border = right_border;
     }
 }
 
 /* log based histogram */
 double
 Math::Log(double x)
 {
     assert((x + 1.0) >= 0.0);
     return log(x + 1.0);
 }
 
 double
 Math::Exp(double x)
 {
     return exp(x) - 1.0;
 }
 
 void
-statHistLogInit(StatHist * H, int capacity, double min, double max)
+StatHist::logInit(int capacity, double min, double max)
 {
-    statHistInit(H, capacity, Math::Log, Math::Exp, min, max);
+    init(capacity, Math::Log, Math::Exp, min, max);
 }
 
 /* linear histogram for enums */
 /* we want to be have [-1,last_enum+1] range to track out of range enums */
 double
 Math::Null(double x)
 {
     return x;
 }
 
 void
-statHistEnumInit(StatHist * H, int last_enum)
+StatHist::enumInit(int last_enum)
 {
-    statHistInit(H, last_enum + 3, Math::Null, Math::Null, (double) -1, (double) (last_enum + 1 + 1));
+    init(last_enum + 3, Math::Null, Math::Null, -1.0, (2.0 + last_enum));
 }
 
 void
 statHistEnumDumper(StoreEntry * sentry, int idx, double val, double size, int count)
 {
     if (count)
         storeAppendPrintf(sentry, "%2d\t %5d\t %5d\n",
                           idx, (int) val, count);
 }
 
 void
-statHistIntInit(StatHist * H, int n)
-{
-    statHistInit(H, n, Math::Null, Math::Null, (double) 0, (double) n - 1);
-}
-
-void
 statHistIntDumper(StoreEntry * sentry, int idx, double val, double size, int count)
 {
     if (count)
         storeAppendPrintf(sentry, "%9d\t%9d\n", (int) val, count);
 }

=== added file 'src/StatHist.h'
--- src/StatHist.h	1970-01-01 00:00:00 +0000
+++ src/StatHist.h	2011-12-15 23:06:11 +0000
@@ -0,0 +1,127 @@
+/*
+ * AUTHOR: Francesco Chemolli
+ *
+ * SQUID Web Proxy Cache          http://www.squid-cache.org/
+ * ----------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from
+ *  the Internet community; see the CONTRIBUTORS file for full
+ *  details.   Many organizations have provided support for Squid's
+ *  development; see the SPONSORS file for full details.  Squid is
+ *  Copyrighted (C) 2001 by the Regents of the University of
+ *  California; see the COPYRIGHT file for full details.  Squid
+ *  incorporates software developed and/or copyrighted by other
+ *  sources; 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.
+ */
+
+#ifndef STATHIST_H_
+#define STATHIST_H_
+
+/* for StoreEntry */
+#include "Store.h"
+
+
+/// function signature for in/out StatHist adaptation
+typedef double hbase_f(double);
+
+/// function signature for StatHist dumping functions
+typedef void StatHistBinDumper(StoreEntry *, int idx, double val, double size, int count);
+
+/** Generic histogram class
+ *
+ * see important comments on hbase_f restrictions in StatHist.cc
+ */
+class StatHist {
+public:
+    /**
+     * \note the default constructor doesn't fully initialize.
+     *       you have to call one of the *init functions to specialize the
+     *       histogram
+     * \todo merge functionality from the *init functions to the constructor and
+     *       drop these
+     * \todo specialize the class in a small hierarchy so that all
+     *       relevant initializations are done at build-time
+     */
+    StatHist() : scale(1.0) {};
+    StatHist(const StatHist&);
+    StatHist &operator=(const StatHist &);
+    virtual ~StatHist();
+    /** clear the contents of the histograms
+     *
+     * \todo remove: this function has been replaced in its purpose
+     *       by the destructor
+     */
+    void clear();
+
+    /** Calculate the percentile for value pctile for the difference between
+     *  this and the supplied histogram.
+     */
+    double deltaPctile(const StatHist &B, double pctile) const;
+    /** obtain the output-transformed value from the specified bin
+     *
+     */
+    double val(int bin) const;
+    /** increment the counter for the histogram entry
+     * associated to the supplied value
+     */
+    void count(double val);
+    /** iterate the supplied bd function over the histogram values
+     */
+    void dump(StoreEntry *sentry, StatHistBinDumper * bd) const;
+    /** Initialize the Histogram using a logarithmic values distribution
+     *
+     */
+    void logInit(int capacity, double min, double max);
+    /** initialize the histogram to count occurrences in an enum-represented set
+     *
+     */
+    void enumInit(int last_enum);
+protected:
+    /** low-level initialize function. called by *Init high-level functions
+     * \note Important restrictions on val_in and val_out functions:
+     *
+     *   - val_in:  ascending, defined on [0, oo), val_in(0) == 0;
+     *   - val_out: x == val_out(val_in(x)) where val_in(x) is defined
+     *
+     *  In practice, the requirements are less strict,
+     *  but then it gets hard to define them without math notation.
+     *  val_in is applied after offseting the value but before scaling
+     *  See log and linear based histograms for examples
+     */
+    void init(int capacity, hbase_f * val_in, hbase_f * val_out, double min, double max);
+    /// find what entry in the histogram corresponds to v, by applying
+    /// the preset input transformation function
+    int findBin(double v);
+    /// the histogram counters
+    int *bins;
+    int capacity;
+    /// minimum value to be stored, corresponding to the first bin
+    double min;
+    /// value of the maximum counter in the histogram
+    double max;
+    /// scaling factor when looking for a bin
+    double scale;
+    hbase_f *val_in;        /* e.g., log() for log-based histogram */
+    hbase_f *val_out;       /* e.g., exp() for log based histogram */
+};
+
+double statHistDeltaMedian(const StatHist & A, const StatHist & B);
+double statHistDeltaPctile(const StatHist & A, const StatHist & B, double pctile);
+StatHistBinDumper statHistEnumDumper;
+StatHistBinDumper statHistIntDumper;
+
+#endif /* STATHIST_H_ */

=== modified file 'src/client_db.cc'
--- src/client_db.cc	2011-11-18 07:48:25 +0000
+++ src/client_db.cc	2011-12-10 15:26:57 +0000
@@ -23,40 +23,41 @@
  *
  *  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 "squid.h"
 #include "event.h"
 #include "format/Token.h"
 #include "ClientInfo.h"
 #include "ip/Address.h"
 #include "mgr/Registration.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 
 
 static hash_table *client_table = NULL;
 
 static ClientInfo *clientdbAdd(const Ip::Address &addr);
 static FREE clientdbFreeItem;
 static void clientdbStartGC(void);
 static void clientdbScheduledGC(void *);
 
 #if USE_DELAY_POOLS
 static int max_clients = 32768;
 #else
 static int max_clients = 32;
 #endif
 
 static int cleanup_running = 0;
 static int cleanup_scheduled = 0;
 static int cleanup_removed;
 
@@ -75,41 +76,41 @@
     c = (ClientInfo *)memAllocate(MEM_CLIENT_INFO);
     c->hash.key = addr.NtoA(buf,MAX_IPSTRLEN);
     c->addr = addr;
 #if USE_DELAY_POOLS
     /* setup default values for client write limiter */
     c->writeLimitingActive=false;
     c->writeSpeedLimit=0;
     c->bucketSize = 0;
     c->firstTimeConnection=true;
     c->quotaQueue = NULL;
     c->rationedQuota = 0;
     c->rationedCount = 0;
     c->selectWaiting = false;
     c->eventWaiting = false;
 
     /* get current time */
     getCurrentTime();
     c->prevTime=current_dtime;/* put current time to have something sensible here */
 #endif
     hash_join(client_table, &c->hash);
-    statCounter.client_http.clients++;
+    ++statCounter.client_http.clients;
 
     if ((statCounter.client_http.clients > max_clients) && !cleanup_running && cleanup_scheduled < 2) {
         cleanup_scheduled++;
         eventAdd("client_db garbage collector", clientdbScheduledGC, NULL, 90, 0);
     }
 
     return c;
 }
 
 static void
 clientdbRegisterWithCacheManager(void)
 {
     Mgr::RegisterAction("client_list", "Cache Client List", clientdbDump, 0, 1);
 }
 
 void
 clientdbInit(void)
 {
     clientdbRegisterWithCacheManager();
 
@@ -387,41 +388,41 @@
 
         if (c->n_established)
             continue;
 
         if (age < 24 * 3600 && c->Http.n_requests > 100)
             continue;
 
         if (age < 4 * 3600 && (c->Http.n_requests > 10 || c->Icp.n_requests > 10))
             continue;
 
         if (age < 5 * 60 && (c->Http.n_requests > 1 || c->Icp.n_requests > 1))
             continue;
 
         if (age < 60)
             continue;
 
         hash_remove_link(client_table, &c->hash);
 
         clientdbFreeItem(c);
 
-        statCounter.client_http.clients--;
+        --statCounter.client_http.clients;
 
         cleanup_removed++;
     }
 
     if (bucket < CLIENT_DB_HASH_SIZE)
         eventAdd("client_db garbage collector", clientdbGC, NULL, 0.15, 0);
     else {
         bucket = 0;
         cleanup_running = 0;
         max_clients = statCounter.client_http.clients * 3 / 2;
 
         if (!cleanup_scheduled) {
             cleanup_scheduled = 1;
             eventAdd("client_db garbage collector", clientdbScheduledGC, NULL, 6 * 3600, 0);
         }
 
         debugs(49, 2, "clientdbGC: Removed " << cleanup_removed << " entries");
     }
 }
 

=== modified file 'src/client_side.cc'
--- src/client_side.cc	2011-12-06 14:06:38 +0000
+++ src/client_side.cc	2011-12-15 21:17:34 +0000
@@ -100,40 +100,42 @@
 #include "clientStream.h"
 #include "comm.h"
 #include "comm/Connection.h"
 #include "CommCalls.h"
 #include "comm/Loops.h"
 #include "comm/Write.h"
 #include "comm/TcpAcceptor.h"
 #include "eui/Config.h"
 #include "fde.h"
 #include "HttpHdrContRange.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "ident/Config.h"
 #include "ident/Ident.h"
 #include "ipc/FdNotes.h"
 #include "ipc/StartListening.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "ProtoPort.h"
 #include "rfc1738.h"
+#include "StatCounters.h"
+#include "StatHist.h"
 #include "SquidTime.h"
 #if USE_SSL
 #include "ssl/context_storage.h"
 #include "ssl/helper.h"
 #include "ssl/support.h"
 #include "ssl/gadgets.h"
 #endif
 #if USE_SSL_CRTD
 #include "ssl/crtd_message.h"
 #include "ssl/certificate_db.h"
 #endif
 #include "Store.h"
 #include "TimeOrTag.h"
 
 #if HAVE_LIMITS
 #include <limits>
 #endif
 
 #if LINGERING_CLOSE
 #define comm_close comm_lingering_close
@@ -408,84 +410,84 @@
 /// wroteControlMsg() wrapper: ClientSocketContext is not an AsyncJob
 void
 ClientSocketContext::WroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, comm_err_t errflag, int xerrno, void *data)
 {
     ClientSocketContext *context = static_cast<ClientSocketContext*>(data);
     context->wroteControlMsg(conn, bufnotused, size, errflag, xerrno);
 }
 
 #if USE_IDENT
 static void
 clientIdentDone(const char *ident, void *data)
 {
     ConnStateData *conn = (ConnStateData *)data;
     xstrncpy(conn->clientConnection->rfc931, ident ? ident : dash_str, USER_IDENT_SZ);
 }
 #endif
 
 void
 clientUpdateStatCounters(log_type logType)
 {
-    statCounter.client_http.requests++;
+    ++statCounter.client_http.requests;
 
     if (logTypeIsATcpHit(logType))
-        statCounter.client_http.hits++;
+        ++statCounter.client_http.hits;
 
     if (logType == LOG_TCP_HIT)
-        statCounter.client_http.disk_hits++;
+        ++statCounter.client_http.disk_hits;
     else if (logType == LOG_TCP_MEM_HIT)
-        statCounter.client_http.mem_hits++;
+        ++statCounter.client_http.mem_hits;
 }
 
 void
 clientUpdateStatHistCounters(log_type logType, int svc_time)
 {
-    statHistCount(&statCounter.client_http.all_svc_time, svc_time);
+    statCounter.client_http.allSvcTime.count(svc_time);
     /**
      * The idea here is not to be complete, but to get service times
      * for only well-defined types.  For example, we don't include
      * LOG_TCP_REFRESH_FAIL because its not really a cache hit
      * (we *tried* to validate it, but failed).
      */
 
     switch (logType) {
 
     case LOG_TCP_REFRESH_UNMODIFIED:
-        statHistCount(&statCounter.client_http.nh_svc_time, svc_time);
+        statCounter.client_http.nearHitSvcTime.count(svc_time);
         break;
 
     case LOG_TCP_IMS_HIT:
-        statHistCount(&statCounter.client_http.nm_svc_time, svc_time);
+        statCounter.client_http.nearMissSvcTime.count(svc_time);
         break;
 
     case LOG_TCP_HIT:
 
     case LOG_TCP_MEM_HIT:
 
     case LOG_TCP_OFFLINE_HIT:
-        statHistCount(&statCounter.client_http.hit_svc_time, svc_time);
+        statCounter.client_http.hitSvcTime.count(svc_time);
         break;
 
     case LOG_TCP_MISS:
 
     case LOG_TCP_CLIENT_REFRESH_MISS:
-        statHistCount(&statCounter.client_http.miss_svc_time, svc_time);
+        statCounter.client_http.missSvcTime.count(svc_time);
         break;
 
     default:
         /* make compiler warnings go away */
         break;
     }
 }
 
 bool
 clientPingHasFinished(ping_data const *aPing)
 {
     if (0 != aPing->stop.tv_sec && 0 != aPing->start.tv_sec)
         return true;
 
     return false;
 }
 
 void
 clientUpdateHierCounters(HierarchyLogEntry * someEntry)
 {
@@ -495,42 +497,41 @@
 #if USE_CACHE_DIGESTS
 
     case CD_PARENT_HIT:
 
     case CD_SIBLING_HIT:
         statCounter.cd.times_used++;
         break;
 #endif
 
     case SIBLING_HIT:
 
     case PARENT_HIT:
 
     case FIRST_PARENT_MISS:
 
     case CLOSEST_PARENT_MISS:
         statCounter.icp.times_used++;
         i = &someEntry->ping;
 
         if (clientPingHasFinished(i))
-            statHistCount(&statCounter.icp.query_svc_time,
-                          tvSubUsec(i->start, i->stop));
+            statCounter.icp.querySvcTime.count(tvSubUsec(i->start, i->stop));
 
         if (i->timeout)
             statCounter.icp.query_timeouts++;
 
         break;
 
     case CLOSEST_PARENT:
 
     case CLOSEST_DIRECT:
         statCounter.netdb.times_used++;
 
         break;
 
     default:
         break;
     }
 }
 
 void
 ClientHttpRequest::updateCounters()
@@ -2816,41 +2817,41 @@
     }
 
     assert(Comm::IsConnOpen(clientConnection));
     assert(io.conn->fd == clientConnection->fd);
 
     /*
      * Don't reset the timeout value here.  The timeout value will be
      * set to Config.Timeout.request by httpAccept() and
      * clientWriteComplete(), and should apply to the request as a
      * whole, not individual read() calls.  Plus, it breaks our
      * lame half-close detection
      */
     if (connReadWasError(io.flag, io.size, io.xerrno)) {
         notifyAllContexts(io.xerrno);
         io.conn->close();
         return;
     }
 
     if (io.flag == COMM_OK) {
         if (io.size > 0) {
-            kb_incr(&statCounter.client_http.kbytes_in, io.size);
+            kb_incr(&(statCounter.client_http.kbytes_in), io.size);
 
             // may comm_close or setReplyToError
             if (!handleReadData(io.buf, io.size))
                 return;
 
         } else if (io.size == 0) {
             debugs(33, 5, HERE << io.conn << " closed?");
 
             if (connFinishedWithConn(io.size)) {
                 clientConnection->close();
                 return;
             }
 
             /* It might be half-closed, we can't tell */
             fd_table[io.conn->fd].flags.socket_eof = 1;
 
             commMarkHalfClosed(io.conn->fd);
 
             fd_note(io.conn->fd, "half-closed");
 

=== modified file 'src/comm.cc'
--- src/comm.cc	2011-12-04 05:43:42 +0000
+++ src/comm.cc	2011-12-10 15:30:14 +0000
@@ -41,40 +41,41 @@
 #include "comm/AcceptLimiter.h"
 #include "comm/comm_internal.h"
 #include "comm/Connection.h"
 #include "comm/IoCallback.h"
 #include "comm/Loops.h"
 #include "comm/Write.h"
 #include "comm/TcpAcceptor.h"
 #include "CommIO.h"
 #include "CommRead.h"
 #include "MemBuf.h"
 #include "pconn.h"
 #include "SquidTime.h"
 #include "CommCalls.h"
 #include "DescriptorSet.h"
 #include "icmp/net_db.h"
 #include "ip/Address.h"
 #include "ip/Intercept.h"
 #include "ip/QosConfig.h"
 #include "ip/tools.h"
 #include "ClientInfo.h"
+#include "StatCounters.h"
 #if USE_SSL
 #include "ssl/support.h"
 #endif
 
 #include "cbdata.h"
 #if _SQUID_CYGWIN_
 #include <sys/ioctl.h>
 #endif
 #ifdef HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
 #endif
 
 /*
  * New C-like simple comm code. This stuff is a mess and doesn't really buy us anything.
  */
 
 static void commStopHalfClosedMonitor(int fd);
 static IOCB commHalfClosedReader;
 static void comm_init_opened(const Comm::ConnectionPointer &conn, tos_t tos, nfmark_t nfmark, const char *note, struct addrinfo *AI);
 static int comm_apply_flags(int new_socket, Ip::Address &addr, int flags, struct addrinfo *AI);

=== modified file 'src/comm/ModDevPoll.cc'
--- src/comm/ModDevPoll.cc	2011-09-02 12:35:57 +0000
+++ src/comm/ModDevPoll.cc	2011-12-10 17:06:28 +0000
@@ -42,40 +42,42 @@
  * on August 11, 2010 at 3pm (GMT+0100 Europe/London).
  *
  * Last modified 2010-10-08
  */
 
 /*
  * There are several poll types in Squid, ALL of which are compiled and linked
  * in. Thus conditional compile-time flags are used to prevent the different
  * modules from creating several versions of the same function simultaneously.
  */
 
 #include "config.h"
 
 #if USE_DEVPOLL
 
 #include "squid.h"
 #include "comm/Loops.h"
 #include "fde.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
+#include "StatHist.h"
 #include "Store.h"
 
 #if HAVE_SYS_DEVPOLL_H
 /* Solaris /dev/poll support, see "man -s 7D poll" */
 #include <sys/devpoll.h>
 #endif
 
 #define DEBUG_DEVPOLL 0
 
 /* OPEN_MAX is defined in <limits.h>, presumably included by sys/devpoll.h */
 #define	DEVPOLL_UPDATESIZE	OPEN_MAX
 #define	DEVPOLL_QUERYSIZE	OPEN_MAX
 
 /* TYPEDEFS */
 typedef short pollfd_events_t; /* type of pollfd.events from sys/poll.h */
 
 /* STRUCTURES */
 /** \brief Current state */
 struct _devpoll_state {
     pollfd_events_t state; /**< current known state of file handle */
@@ -155,44 +157,43 @@
     debugs(
         5,
         DEBUG_DEVPOLL ? 0 : 8,
         HERE << "FD " << fd << ", events=" << events
     );
 
     /* Is the array already full and in need of flushing? */
     if (devpoll_update.cur != -1 && (devpoll_update.cur == devpoll_update.size))
         comm_flush_updates();
 
     /* Push new event onto array */
     devpoll_update.cur++;
     devpoll_update.pfds[devpoll_update.cur].fd = fd;
     devpoll_update.pfds[devpoll_update.cur].events = events;
     devpoll_update.pfds[devpoll_update.cur].revents = 0;
 }
 
 
 static void commIncomingStats(StoreEntry *sentry)
 {
-    StatCounters *f = &statCounter;
     storeAppendPrintf(sentry, "Total number of devpoll loops: %ld\n", statCounter.select_loops);
     storeAppendPrintf(sentry, "Histogram of returned filedescriptors\n");
-    statHistDump(&f->select_fds_hist, sentry, statHistIntDumper);
+    statCounter.select_fds_hist.dump(sentry, statHistIntDumper);
 }
 
 
 static void
 commDevPollRegisterWithCacheManager(void)
 {
     Mgr::RegisterAction(
         "comm_devpoll_incoming",
         "comm_incoming() stats",
         commIncomingStats,
         0,
         1
     );
 }
 
 
 /* PUBLIC FUNCTIONS */
 
 /** \brief Initialise /dev/poll support
  *
@@ -360,41 +361,41 @@
         comm_flush_updates(); /* ensure latest changes are sent to /dev/poll */
 
         num = ioctl(devpoll_fd, DP_POLL, &do_poll);
         ++statCounter.select_loops;
 
         if (num >= 0)
             break; /* no error, skip out of loop */
 
         if (ignoreErrno(errno))
             break; /* error is one we may ignore, skip out of loop */
 
         /* error during poll */
         getCurrentTime();
         PROF_stop(comm_check_incoming);
         return COMM_ERROR;
     }
 
     PROF_stop(comm_check_incoming);
     getCurrentTime();
 
-    statHistCount(&statCounter.select_fds_hist, num);
+    statCounter.select_fds_hist.count(num);
 
     if (num == 0)
         return COMM_TIMEOUT; /* no error */
 
     PROF_start(comm_handle_ready_fd);
 
     for (i = 0; i < num; i++) {
         int fd = (int)do_poll.dp_fds[i].fd;
         F = &fd_table[fd];
         debugs(
             5,
             DEBUG_DEVPOLL ? 0 : 8,
             HERE << "got FD " << fd
             << ",events=" << std::hex << do_poll.dp_fds[i].revents
             << ",monitoring=" << devpoll_state[fd].state
             << ",F->read_handler=" << F->read_handler
             << ",F->write_handler=" << F->write_handler
         );
 
         /* handle errors */

=== modified file 'src/comm/ModEpoll.cc'
--- src/comm/ModEpoll.cc	2011-09-02 12:35:57 +0000
+++ src/comm/ModEpoll.cc	2011-12-09 17:31:19 +0000
@@ -43,40 +43,42 @@
  * -- David Nicklay <dnicklay@web.turner.com>
  */
 
 /*
  * XXX Currently not implemented / supported by this module XXX
  *
  * - delay pools
  * - deferred reads
  *
  */
 
 #include "config.h"
 
 #if USE_EPOLL
 
 #include "squid.h"
 #include "comm/Loops.h"
 #include "fde.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
+#include "StatHist.h"
 #include "Store.h"
 
 #define DEBUG_EPOLL 0
 
 #if HAVE_SYS_EPOLL_H
 #include <sys/epoll.h>
 #endif
 
 static int kdpfd;
 static int max_poll_time = 1000;
 
 static struct epoll_event *pevents;
 
 static void commEPollRegisterWithCacheManager(void);
 
 
 /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
 /* Public functions */
 
 
@@ -210,41 +212,41 @@
     SetSelect(fd, 0, NULL, NULL, 0);
 }
 
 
 static void commIncomingStats(StoreEntry * sentry);
 
 static void
 commEPollRegisterWithCacheManager(void)
 {
     Mgr::RegisterAction("comm_epoll_incoming",
                         "comm_incoming() stats",
                         commIncomingStats, 0, 1);
 }
 
 static void
 commIncomingStats(StoreEntry * sentry)
 {
     StatCounters *f = &statCounter;
     storeAppendPrintf(sentry, "Total number of epoll(2) loops: %ld\n", statCounter.select_loops);
     storeAppendPrintf(sentry, "Histogram of returned filedescriptors\n");
-    statHistDump(&f->select_fds_hist, sentry, statHistIntDumper);
+    f->select_fds_hist.dump(sentry, statHistIntDumper);
 }
 
 /**
  * Check all connections for new connections and input data that is to be
  * processed. Also check for connections with data queued and whether we can
  * write it out.
  *
  * Called to do the new-style IO, courtesy of of squid (like most of this
  * new IO code). This routine handles the stuff we've hidden in
  * comm_setselect and fd_table[] and calls callbacks for IO ready
  * events.
  */
 comm_err_t
 Comm::DoSelect(int msec)
 {
     int num, i,fd;
     fde *F;
     PF *hdl;
 
     struct epoll_event *cevents;
@@ -257,41 +259,41 @@
     for (;;) {
         num = epoll_wait(kdpfd, pevents, SQUID_MAXFD, msec);
         ++statCounter.select_loops;
 
         if (num >= 0)
             break;
 
         if (ignoreErrno(errno))
             break;
 
         getCurrentTime();
 
         PROF_stop(comm_check_incoming);
 
         return COMM_ERROR;
     }
 
     PROF_stop(comm_check_incoming);
     getCurrentTime();
 
-    statHistCount(&statCounter.select_fds_hist, num);
+    statCounter.select_fds_hist.count(num);
 
     if (num == 0)
         return COMM_TIMEOUT;		/* No error.. */
 
     PROF_start(comm_handle_ready_fd);
 
     for (i = 0, cevents = pevents; i < num; i++, cevents++) {
         fd = cevents->data.fd;
         F = &fd_table[fd];
         debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "got FD " << fd << " events=" <<
                std::hex << cevents->events << " monitoring=" << F->epoll_state <<
                " F->read_handler=" << F->read_handler << " F->write_handler=" << F->write_handler);
 
         // TODO: add EPOLLPRI??
 
         if (cevents->events & (EPOLLIN|EPOLLHUP|EPOLLERR) || F->flags.read_pending) {
             if ((hdl = F->read_handler) != NULL) {
                 debugs(5, DEBUG_EPOLL ? 0 : 8, HERE << "Calling read handler on FD " << fd);
                 PROF_start(comm_write_handler);
                 F->flags.read_pending = 0;

=== modified file 'src/comm/ModPoll.cc'
--- src/comm/ModPoll.cc	2011-09-02 12:35:57 +0000
+++ src/comm/ModPoll.cc	2011-12-10 20:40:11 +0000
@@ -24,40 +24,41 @@
  *  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 USE_POLL
 
 #include "squid.h"
 #include "comm/Connection.h"
 #include "comm/Loops.h"
 #include "fde.h"
 #include "ICP.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 
 #if HAVE_POLL_H
 #include <poll.h>
 #endif
 
 /* Needed for poll() on Linux at least */
 #if USE_POLL
 #ifndef POLLRDNORM
 #define POLLRDNORM POLLIN
 #endif
 #ifndef POLLWRNORM
 #define POLLWRNORM POLLOUT
 #endif
 #endif
 
 static int MAX_POLL_TIME = 1000;	/* see also Comm::QuickPollRequired() */
 
 #ifndef        howmany
 #define howmany(x, y)   (((x)+((y)-1))/(y))
@@ -288,75 +289,75 @@
 
     if (icpIncomingConn != icpOutgoingConn && Comm::IsConnOpen(icpOutgoingConn))
         fds[nfds++] = icpOutgoingConn->fd;
 
     if (nfds == 0)
         return;
 
     nevents = comm_check_incoming_poll_handlers(nfds, fds);
 
     incoming_icp_interval += Config.comm_incoming.icp_average - nevents;
 
     if (incoming_icp_interval < Config.comm_incoming.icp_min_poll)
         incoming_icp_interval = Config.comm_incoming.icp_min_poll;
 
     if (incoming_icp_interval > MAX_INCOMING_INTERVAL)
         incoming_icp_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_ICP_MAX)
         nevents = INCOMING_ICP_MAX;
 
-    statHistCount(&statCounter.comm_icp_incoming, nevents);
+    statCounter.comm_icp_incoming.count(nevents);
 }
 
 static void
 comm_poll_http_incoming(void)
 {
     int nfds = 0;
     int fds[MAXHTTPPORTS];
     int j;
     int nevents;
     http_io_events = 0;
 
     /* only poll sockets that won't be deferred */
 
     for (j = 0; j < NHttpSockets; j++) {
         if (HttpSockets[j] < 0)
             continue;
 
         fds[nfds++] = HttpSockets[j];
     }
 
     nevents = comm_check_incoming_poll_handlers(nfds, fds);
     incoming_http_interval = incoming_http_interval
                              + Config.comm_incoming.http_average - nevents;
 
     if (incoming_http_interval < Config.comm_incoming.http_min_poll)
         incoming_http_interval = Config.comm_incoming.http_min_poll;
 
     if (incoming_http_interval > MAX_INCOMING_INTERVAL)
         incoming_http_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_HTTP_MAX)
         nevents = INCOMING_HTTP_MAX;
 
-    statHistCount(&statCounter.comm_http_incoming, nevents);
+    statCounter.comm_http_incoming.count(nevents);
 }
 
 /* poll all sockets; call handlers for those that are ready. */
 comm_err_t
 Comm::DoSelect(int msec)
 {
     struct pollfd pfds[SQUID_MAXFD];
 
     PF *hdl = NULL;
     int fd;
     int maxfd;
     unsigned long nfds;
     unsigned long npending;
     int num;
     int callicp = 0, callhttp = 0;
     int calldns = 0;
     double timeout = current_dtime + (msec / 1000.0);
 
     do {
         double start;
@@ -432,41 +433,41 @@
             PROF_stop(comm_poll_normal);
 
             if (num >= 0 || npending > 0)
                 break;
 
             if (ignoreErrno(errno))
                 continue;
 
             debugs(5, 0, "comm_poll: poll failure: " << xstrerror());
 
             assert(errno != EINVAL);
 
             return COMM_ERROR;
 
             /* NOTREACHED */
         }
 
         getCurrentTime();
 
         debugs(5, num ? 5 : 8, "comm_poll: " << num << "+" << npending << " FDs ready");
-        statHistCount(&statCounter.select_fds_hist, num);
+        statCounter.select_fds_hist.count(num);
 
         if (num == 0 && npending == 0)
             continue;
 
         /* scan each socket but the accept socket. Poll this
          * more frequently to minimize losses due to the 5 connect
          * limit in SunOS */
         PROF_start(comm_handle_ready_fd);
 
         for (size_t loopIndex = 0; loopIndex < nfds; loopIndex++) {
             fde *F;
             int revents = pfds[loopIndex].revents;
             fd = pfds[loopIndex].fd;
 
             if (fd == -1)
                 continue;
 
             if (fd_table[fd].flags.read_pending)
                 revents |= POLLIN;
 
@@ -603,66 +604,65 @@
 
     if (DnsSocketB >= 0)
         fds[nfds++] = DnsSocketB;
 
     nevents = comm_check_incoming_poll_handlers(nfds, fds);
 
     if (nevents < 0)
         return;
 
     incoming_dns_interval += Config.comm_incoming.dns_average - nevents;
 
     if (incoming_dns_interval < Config.comm_incoming.dns_min_poll)
         incoming_dns_interval = Config.comm_incoming.dns_min_poll;
 
     if (incoming_dns_interval > MAX_INCOMING_INTERVAL)
         incoming_dns_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_DNS_MAX)
         nevents = INCOMING_DNS_MAX;
 
-    statHistCount(&statCounter.comm_dns_incoming, nevents);
+    statCounter.comm_dns_incoming.count(nevents);
 }
 
 
 static void
 commPollRegisterWithCacheManager(void)
 {
     Mgr::RegisterAction("comm_poll_incoming",
                         "comm_incoming() stats",
                         commIncomingStats, 0, 1);
 }
 
 void
 Comm::SelectLoopInit(void)
 {
     commPollRegisterWithCacheManager();
 }
 
 static void
 commIncomingStats(StoreEntry * sentry)
 {
-    StatCounters *f = &statCounter;
     storeAppendPrintf(sentry, "Current incoming_icp_interval: %d\n",
                       incoming_icp_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "Current incoming_dns_interval: %d\n",
                       incoming_dns_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "Current incoming_http_interval: %d\n",
                       incoming_http_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "Histogram of events per incoming socket type\n");
     storeAppendPrintf(sentry, "ICP Messages handled per comm_poll_icp_incoming() call:\n");
-    statHistDump(&f->comm_icp_incoming, sentry, statHistIntDumper);
+    statCounter.comm_icp_incoming.dump(sentry, statHistIntDumper);
     storeAppendPrintf(sentry, "DNS Messages handled per comm_poll_dns_incoming() call:\n");
-    statHistDump(&f->comm_dns_incoming, sentry, statHistIntDumper);
+    statCounter.comm_dns_incoming.dump(sentry, statHistIntDumper);
     storeAppendPrintf(sentry, "HTTP Messages handled per comm_poll_http_incoming() call:\n");
-    statHistDump(&f->comm_http_incoming, sentry, statHistIntDumper);
+    statCounter.comm_http_incoming.dump(sentry, statHistIntDumper);
 }
 
 /* Called by async-io or diskd to speed up the polling */
 void
 Comm::QuickPollRequired(void)
 {
     MAX_POLL_TIME = 10;
 }
 
 #endif /* USE_POLL */

=== modified file 'src/comm/ModSelect.cc'
--- src/comm/ModSelect.cc	2011-09-02 12:35:57 +0000
+++ src/comm/ModSelect.cc	2011-12-10 17:18:35 +0000
@@ -23,40 +23,42 @@
  *  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 USE_SELECT
 
 #include "squid.h"
 #include "comm/Connection.h"
 #include "comm/Loops.h"
 #include "ICP.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
+#include "StatHist.h"
 #include "Store.h"
 #include "fde.h"
 
 static int MAX_POLL_TIME = 1000;	/* see also Comm::QuickPollRequired() */
 
 #ifndef        howmany
 #define howmany(x, y)   (((x)+((y)-1))/(y))
 #endif
 #ifndef        NBBY
 #define        NBBY    8
 #endif
 #define FD_MASK_BYTES sizeof(fd_mask)
 #define FD_MASK_BITS (FD_MASK_BYTES*NBBY)
 
 /* STATIC */
 static int examine_select(fd_set *, fd_set *);
 static int fdIsHttp(int fd);
 static int fdIsIcp(int fd);
 static int fdIsDns(int fd);
 static OBJH commIncomingStats;
@@ -282,72 +284,72 @@
 
     if (Comm::IsConnOpen(icpOutgoingConn) && icpIncomingConn != icpOutgoingConn)
         fds[nfds++] = icpOutgoingConn->fd;
 
     if (nfds == 0)
         return;
 
     nevents = comm_check_incoming_select_handlers(nfds, fds);
 
     incoming_icp_interval += Config.comm_incoming.icp_average - nevents;
 
     if (incoming_icp_interval < 0)
         incoming_icp_interval = 0;
 
     if (incoming_icp_interval > MAX_INCOMING_INTERVAL)
         incoming_icp_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_ICP_MAX)
         nevents = INCOMING_ICP_MAX;
 
-    statHistCount(&statCounter.comm_icp_incoming, nevents);
+    statCounter.comm_icp_incoming.count(nevents);
 }
 
 static void
 comm_select_http_incoming(void)
 {
     int nfds = 0;
     int fds[MAXHTTPPORTS];
     int j;
     int nevents;
     http_io_events = 0;
 
     for (j = 0; j < NHttpSockets; j++) {
         if (HttpSockets[j] < 0)
             continue;
 
         fds[nfds++] = HttpSockets[j];
     }
 
     nevents = comm_check_incoming_select_handlers(nfds, fds);
     incoming_http_interval += Config.comm_incoming.http_average - nevents;
 
     if (incoming_http_interval < 0)
         incoming_http_interval = 0;
 
     if (incoming_http_interval > MAX_INCOMING_INTERVAL)
         incoming_http_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_HTTP_MAX)
         nevents = INCOMING_HTTP_MAX;
 
-    statHistCount(&statCounter.comm_http_incoming, nevents);
+    statCounter.comm_http_incoming.count(nevents);
 }
 
 #define DEBUG_FDBITS 0
 /* Select on all sockets; call handlers for those that are ready. */
 comm_err_t
 Comm::DoSelect(int msec)
 {
     fd_set readfds;
     fd_set pendingfds;
     fd_set writefds;
 
     PF *hdl = NULL;
     int fd;
     int maxfd;
     int num;
     int pending;
     int callicp = 0, callhttp = 0;
     int calldns = 0;
     int maxindex;
     unsigned int k;
@@ -453,41 +455,41 @@
 
             if (ignoreErrno(errno))
                 break;
 
             debugs(5, 0, "comm_select: select failure: " << xstrerror());
 
             examine_select(&readfds, &writefds);
 
             return COMM_ERROR;
 
             /* NOTREACHED */
         }
 
         if (num < 0 && !pending)
             continue;
 
         getCurrentTime();
 
         debugs(5, num ? 5 : 8, "comm_select: " << num << "+" << pending << " FDs ready");
 
-        statHistCount(&statCounter.select_fds_hist, num);
+        statCounter.select_fds_hist.count(num);
 
         if (num == 0 && pending == 0)
             continue;
 
         /* Scan return fd masks for ready descriptors */
         fdsp = (fd_mask *) & readfds;
 
         pfdsp = (fd_mask *) & pendingfds;
 
         maxindex = howmany(maxfd, FD_MASK_BITS);
 
         for (j = 0; j < maxindex; j++) {
             if ((tmask = (fdsp[j] | pfdsp[j])) == 0)
                 continue;	/* no bits here */
 
             for (k = 0; k < FD_MASK_BITS; k++) {
                 if (tmask == 0)
                     break;	/* no more bits left */
 
                 if (!EBIT_TEST(tmask, k))
@@ -643,41 +645,41 @@
 
     if (DnsSocketB >= 0)
         fds[nfds++] = DnsSocketB;
 
     nevents = comm_check_incoming_select_handlers(nfds, fds);
 
     if (nevents < 0)
         return;
 
     incoming_dns_interval += Config.comm_incoming.dns_average - nevents;
 
     if (incoming_dns_interval < Config.comm_incoming.dns_min_poll)
         incoming_dns_interval = Config.comm_incoming.dns_min_poll;
 
     if (incoming_dns_interval > MAX_INCOMING_INTERVAL)
         incoming_dns_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_DNS_MAX)
         nevents = INCOMING_DNS_MAX;
 
-    statHistCount(&statCounter.comm_dns_incoming, nevents);
+    statCounter.comm_dns_incoming.count(nevents);
 }
 
 void
 Comm::SelectLoopInit(void)
 {
     zero_tv.tv_sec = 0;
     zero_tv.tv_usec = 0;
     FD_ZERO(&global_readfds);
     FD_ZERO(&global_writefds);
     nreadfds = nwritefds = 0;
 
     Mgr::RegisterAction("comm_select_incoming",
                         "comm_incoming() stats",
                         commIncomingStats, 0, 1);
 }
 
 /*
  * examine_select - debug routine.
  *
  * I spend the day chasing this core dump that occurs when both the client
@@ -735,55 +737,54 @@
         } else if (F->timeoutHandler != NULL) {
             debugs(5, 0, "examine_select: Calling Timeout Handler");
             ScheduleCallHere(F->timeoutHandler);
         }
 
         F->closeHandler = NULL;
         F->timeoutHandler = NULL;
         F->read_handler = NULL;
         F->write_handler = NULL;
         FD_CLR(fd, readfds);
         FD_CLR(fd, writefds);
     }
 
     return 0;
 }
 
 
 static void
 commIncomingStats(StoreEntry * sentry)
 {
-    StatCounters *f = &statCounter;
     storeAppendPrintf(sentry, "Current incoming_icp_interval: %d\n",
                       incoming_icp_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "Current incoming_dns_interval: %d\n",
                       incoming_dns_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "Current incoming_http_interval: %d\n",
                       incoming_http_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "Histogram of events per incoming socket type\n");
     storeAppendPrintf(sentry, "ICP Messages handled per comm_select_icp_incoming() call:\n");
-    statHistDump(&f->comm_icp_incoming, sentry, statHistIntDumper);
+    statCounter.comm_icp_incoming.dump(sentry, statHistIntDumper);
     storeAppendPrintf(sentry, "DNS Messages handled per comm_select_dns_incoming() call:\n");
-    statHistDump(&f->comm_dns_incoming, sentry, statHistIntDumper);
+    statCounter.comm_dns_incoming.dump(sentry, statHistIntDumper);
     storeAppendPrintf(sentry, "HTTP Messages handled per comm_select_http_incoming() call:\n");
-    statHistDump(&f->comm_http_incoming, sentry, statHistIntDumper);
+    statCounter.comm_http_incoming.dump(sentry, statHistIntDumper);
 }
 
 void
 commUpdateReadBits(int fd, PF * handler)
 {
     if (handler && !FD_ISSET(fd, &global_readfds)) {
         FD_SET(fd, &global_readfds);
         nreadfds++;
     } else if (!handler && FD_ISSET(fd, &global_readfds)) {
         FD_CLR(fd, &global_readfds);
         nreadfds--;
     }
 }
 
 void
 commUpdateWriteBits(int fd, PF * handler)
 {
     if (handler && !FD_ISSET(fd, &global_writefds)) {
         FD_SET(fd, &global_writefds);
         nwritefds++;

=== modified file 'src/comm/ModSelectWin32.cc'
--- src/comm/ModSelectWin32.cc	2011-09-02 12:35:57 +0000
+++ src/comm/ModSelectWin32.cc	2011-12-10 17:07:16 +0000
@@ -23,40 +23,42 @@
  *  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 USE_SELECT_WIN32
 
 #include "squid.h"
 #include "comm/Loops.h"
 #include "fde.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
+#include "StatHist.h"
 #include "Store.h"
 
 static int MAX_POLL_TIME = 1000;	/* see also Comm::QuickPollRequired() */
 
 #ifndef        howmany
 #define howmany(x, y)   (((x)+((y)-1))/(y))
 #endif
 #ifndef        NBBY
 #define        NBBY    8
 #endif
 #define FD_MASK_BYTES sizeof(fd_mask)
 #define FD_MASK_BITS (FD_MASK_BYTES*NBBY)
 
 /* STATIC */
 static int examine_select(fd_set *, fd_set *);
 static int fdIsHttp(int fd);
 static int fdIsIcp(int fd);
 static int fdIsDns(int fd);
 static OBJH commIncomingStats;
 static int comm_check_incoming_select_handlers(int nfds, int *fds);
@@ -285,72 +287,72 @@
     if (theInIcpConnection != theOutIcpConnection)
         if (theOutIcpConnection >= 0)
             fds[nfds++] = theOutIcpConnection;
 
     if (nfds == 0)
         return;
 
     nevents = comm_check_incoming_select_handlers(nfds, fds);
 
     incoming_icp_interval += Config.comm_incoming.icp_average - nevents;
 
     if (incoming_icp_interval < 0)
         incoming_icp_interval = 0;
 
     if (incoming_icp_interval > MAX_INCOMING_INTERVAL)
         incoming_icp_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_ICP_MAX)
         nevents = INCOMING_ICP_MAX;
 
-    statHistCount(&statCounter.comm_icp_incoming, nevents);
+    statCounter.comm_icp_incoming.count(nevents);
 }
 
 static void
 comm_select_http_incoming(void)
 {
     int nfds = 0;
     int fds[MAXHTTPPORTS];
     int j;
     int nevents;
     http_io_events = 0;
 
     for (j = 0; j < NHttpSockets; j++) {
         if (HttpSockets[j] < 0)
             continue;
 
         fds[nfds++] = HttpSockets[j];
     }
 
     nevents = comm_check_incoming_select_handlers(nfds, fds);
     incoming_http_interval += Config.comm_incoming.http_average - nevents;
 
     if (incoming_http_interval < 0)
         incoming_http_interval = 0;
 
     if (incoming_http_interval > MAX_INCOMING_INTERVAL)
         incoming_http_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_HTTP_MAX)
         nevents = INCOMING_HTTP_MAX;
 
-    statHistCount(&statCounter.comm_http_incoming, nevents);
+    statCounter.comm_http_incoming.count(nevents);
 }
 
 #define DEBUG_FDBITS 0
 /* Select on all sockets; call handlers for those that are ready. */
 comm_err_t
 Comm::DoSelect(int msec)
 {
     fd_set readfds;
     fd_set pendingfds;
     fd_set writefds;
 
     PF *hdl = NULL;
     int fd;
     int maxfd;
     int num;
     int pending;
     int callicp = 0, callhttp = 0;
     int calldns = 0;
     int j;
 #if DEBUG_FDBITS
@@ -453,41 +455,41 @@
 
             if (ignoreErrno(errno))
                 break;
 
             debugs(5, 0, "comm_select: select failure: " << xstrerror());
 
             examine_select(&readfds, &writefds);
 
             return COMM_ERROR;
 
             /* NOTREACHED */
         }
 
         if (num < 0 && !pending)
             continue;
 
         getCurrentTime();
 
         debugs(5, num ? 5 : 8, "comm_select: " << num << "+" << pending << " FDs ready");
 
-        statHistCount(&statCounter.select_fds_hist, num);
+        statCounter.select_fds_hist.count(num);
 
         if (num == 0 && pending == 0)
             continue;
 
         /* Scan return fd masks for ready descriptors */
         assert(readfds.fd_count <= (unsigned int) Biggest_FD);
         assert(pendingfds.fd_count <= (unsigned int) Biggest_FD);
 
         for (j = 0; j < (int) readfds.fd_count; j++) {
             register int readfds_handle = readfds.fd_array[j];
             register int pendingfds_handle = pendingfds.fd_array[j];
             register int osfhandle;
             no_bits = 1;
 
             for ( fd = Biggest_FD; fd; fd-- ) {
                 osfhandle = fd_table[fd].win32.handle;
 
                 if (( osfhandle == readfds_handle ) ||
                         ( osfhandle == pendingfds_handle )) {
                     if (fd_table[fd].flags.open) {
@@ -665,41 +667,41 @@
 
     if (DnsSocketB >= 0)
         fds[nfds++] = DnsSocketB;
 
     nevents = comm_check_incoming_select_handlers(nfds, fds);
 
     if (nevents < 0)
         return;
 
     incoming_dns_interval += Config.comm_incoming.dns_average - nevents;
 
     if (incoming_dns_interval < Config.comm_incoming.dns_min_poll)
         incoming_dns_interval = Config.comm_incoming.dns_min_poll;
 
     if (incoming_dns_interval > MAX_INCOMING_INTERVAL)
         incoming_dns_interval = MAX_INCOMING_INTERVAL;
 
     if (nevents > INCOMING_DNS_MAX)
         nevents = INCOMING_DNS_MAX;
 
-    statHistCount(&statCounter.comm_dns_incoming, nevents);
+    statCounter.comm_dns_incoming.count(nevents);
 }
 
 void
 Comm::SelectLoopInit(void)
 {
     zero_tv.tv_sec = 0;
     zero_tv.tv_usec = 0;
     FD_ZERO(&global_readfds);
     FD_ZERO(&global_writefds);
     nreadfds = nwritefds = 0;
 
     Mgr::RegisterAction("comm_select_incoming",
                         "comm_incoming() stats",
                         commIncomingStats, 0, 1);
 }
 
 /*
  * examine_select - debug routine.
  *
  * I spend the day chasing this core dump that occurs when both the client
@@ -757,55 +759,54 @@
         } else if (F->timeoutHandler != NULL) {
             debugs(5, 0, "examine_select: Calling Timeout Handler");
             ScheduleCallHere(F->timeoutHandler);
         }
 
         F->closeHandler = NULL;
         F->timeoutHandler = NULL;
         F->read_handler = NULL;
         F->write_handler = NULL;
         FD_CLR(fd, readfds);
         FD_CLR(fd, writefds);
     }
 
     return 0;
 }
 
 
 static void
 commIncomingStats(StoreEntry * sentry)
 {
-    StatCounters *f = &statCounter;
     storeAppendPrintf(sentry, "Current incoming_icp_interval: %d\n",
                       incoming_icp_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "Current incoming_dns_interval: %d\n",
                       incoming_dns_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "Current incoming_http_interval: %d\n",
                       incoming_http_interval >> INCOMING_FACTOR);
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "Histogram of events per incoming socket type\n");
     storeAppendPrintf(sentry, "ICP Messages handled per comm_select_icp_incoming() call:\n");
-    statHistDump(&f->comm_icp_incoming, sentry, statHistIntDumper);
+    statCounter.comm_icp_incoming.dump(sentry, statHistIntDumper);
     storeAppendPrintf(sentry, "DNS Messages handled per comm_select_dns_incoming() call:\n");
-    statHistDump(&f->comm_dns_incoming, sentry, statHistIntDumper);
+    statCounter.comm_dns_incoming.dump(sentry, statHistIntDumper);
     storeAppendPrintf(sentry, "HTTP Messages handled per comm_select_http_incoming() call:\n");
-    statHistDump(&f->comm_http_incoming, sentry, statHistIntDumper);
+    statCounter.comm_http_incoming.dump(sentry, statHistIntDumper);
 }
 
 void
 commUpdateReadBits(int fd, PF * handler)
 {
     if (handler && !__WSAFDIsSet(fd_table[fd].win32.handle, &global_readfds)) {
         FD_SET(fd, &global_readfds);
         nreadfds++;
     } else if (!handler && __WSAFDIsSet(fd_table[fd].win32.handle, &global_readfds)) {
         FD_CLR(fd, &global_readfds);
         nreadfds--;
     }
 }
 
 void
 commUpdateWriteBits(int fd, PF * handler)
 {
     if (handler && !__WSAFDIsSet(fd_table[fd].win32.handle, &global_writefds)) {
         FD_SET(fd, &global_writefds);
         nwritefds++;

=== modified file 'src/comm/TcpAcceptor.cc'
--- src/comm/TcpAcceptor.cc	2011-02-25 03:38:04 +0000
+++ src/comm/TcpAcceptor.cc	2011-12-10 15:21:36 +0000
@@ -27,40 +27,41 @@
  *  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.
  *
  *
  * Copyright (c) 2003, Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "base/TextException.h"
 #include "CommCalls.h"
 #include "comm/AcceptLimiter.h"
 #include "comm/comm_internal.h"
 #include "comm/Connection.h"
 #include "comm/Loops.h"
 #include "comm/TcpAcceptor.h"
 #include "fde.h"
 #include "ip/Intercept.h"
 #include "protos.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 
 namespace Comm
 {
 CBDATA_CLASS_INIT(TcpAcceptor);
 };
 
 Comm::TcpAcceptor::TcpAcceptor(const Comm::ConnectionPointer &newConn, const char *note, const Subscription::Pointer &aSub) :
         AsyncJob("Comm::TcpAcceptor"),
         errcode(0),
         isLimited(0),
         theCallSub(aSub),
         conn(newConn)
 {}
 
 void
 Comm::TcpAcceptor::subscribe(const Subscription::Pointer &aSub)
 {
     debugs(5, 5, HERE << status() << " AsyncCall Subscription: " << aSub);
     unsubscribe("subscription change");
     theCallSub = aSub;
@@ -279,41 +280,41 @@
         params.conn = newConnDetails;
         params.flag = flag;
         params.xerrno = errcode;
         ScheduleCallHere(call);
     }
 }
 
 /**
  * accept() and process
  * Wait for an incoming connection on our listener socket.
  *
  * \retval COMM_OK         success. details parameter filled.
  * \retval COMM_NOMESSAGE  attempted accept() but nothing useful came in.
  * \retval COMM_ERROR      an outright failure occured.
  *                         Or if this client has too many connections already.
  */
 comm_err_t
 Comm::TcpAcceptor::oldAccept(Comm::ConnectionPointer &details)
 {
     PROF_start(comm_accept);
-    statCounter.syscalls.sock.accepts++;
+    ++statCounter.syscalls.sock.accepts;
     int sock;
     struct addrinfo *gai = NULL;
     details->local.InitAddrInfo(gai);
 
     errcode = 0; // reset local errno copy.
     if ((sock = accept(conn->fd, gai->ai_addr, &gai->ai_addrlen)) < 0) {
         errcode = errno; // store last accept errno locally.
 
         details->local.FreeAddrInfo(gai);
 
         PROF_stop(comm_accept);
 
         if (ignoreErrno(errno)) {
             debugs(50, 5, HERE << status() << ": " << xstrerror());
             return COMM_NOMESSAGE;
         } else if (ENFILE == errno || EMFILE == errno) {
             debugs(50, 3, HERE << status() << ": " << xstrerror());
             return COMM_ERROR;
         } else {
             debugs(50, 1, HERE << status() << ": " << xstrerror());

=== modified file 'src/comm/Write.cc'
--- src/comm/Write.cc	2010-12-03 00:18:43 +0000
+++ src/comm/Write.cc	2011-12-10 15:21:36 +0000
@@ -1,28 +1,29 @@
 #include "config.h"
 #if USE_DELAY_POOLS
 #include "ClientInfo.h"
 #endif
 #include "comm/Connection.h"
 #include "comm/IoCallback.h"
 #include "comm/Write.h"
 #include "fde.h"
+#include "StatCounters.h"
 #include "SquidTime.h"
 #include "MemBuf.h"
 
 void
 Comm::Write(const Comm::ConnectionPointer &conn, MemBuf *mb, AsyncCall::Pointer &callback)
 {
     Comm::Write(conn, mb->buf, mb->size, callback, mb->freeFunc());
 }
 
 void
 Comm::Write(const Comm::ConnectionPointer &conn, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
 {
     debugs(5, 5, HERE << conn << ": sz " << size << ": asynCall " << callback);
 
     /* Make sure we are open, not closing, and not writing */
     assert(fd_table[conn->fd].flags.open);
     assert(!fd_table[conn->fd].closing());
     Comm::IoCallback *ccb = COMMIO_FD_WRITECB(conn->fd);
     assert(!ccb->active());
 
@@ -91,41 +92,41 @@
     len = FD_WRITE_METHOD(fd, state->buf + state->offset, nleft);
     debugs(5, 5, HERE << "write() returns " << len);
 
 #if USE_DELAY_POOLS
     if (clientInfo) {
         if (len > 0) {
             /* we wrote data - drain them from bucket */
             clientInfo->bucketSize -= len;
             if (clientInfo->bucketSize < 0.0) {
                 debugs(5,1, HERE << "drained too much"); // should not happen
                 clientInfo->bucketSize = 0;
             }
         }
 
         // even if we wrote nothing, we were served; give others a chance
         clientInfo->kickQuotaQueue();
     }
 #endif /* USE_DELAY_POOLS */
 
     fd_bytes(fd, len, FD_WRITE);
-    statCounter.syscalls.sock.writes++;
+    ++statCounter.syscalls.sock.writes;
     // After each successful partial write,
     // reset fde::writeStart to the current time.
     fd_table[fd].writeStart = squid_curtime;
 
     if (len == 0) {
         /* Note we even call write if nleft == 0 */
         /* We're done */
         if (nleft != 0)
             debugs(5, DBG_IMPORTANT, "FD " << fd << " write failure: connection closed with " << nleft << " bytes remaining.");
 
         state->finish(nleft ? COMM_ERROR : COMM_OK, errno);
     } else if (len < 0) {
         /* An error */
         if (fd_table[fd].flags.socket_eof) {
             debugs(50, 2, HERE << "FD " << fd << " write failure: " << xstrerror() << ".");
             state->finish(nleft ? COMM_ERROR : COMM_OK, errno);
         } else if (ignoreErrno(errno)) {
             debugs(50, 9, HERE << "FD " << fd << " write failure: " << xstrerror() << ".");
             state->selectOrQueueWrite();
         } else {

=== modified file 'src/disk.cc'
--- src/disk.cc	2011-04-14 16:58:28 +0000
+++ src/disk.cc	2011-12-10 15:30:14 +0000
@@ -19,40 +19,41 @@
  *  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 "squid.h"
 #include "comm/Loops.h"
 #include "fde.h"
 #include "MemBuf.h"
+#include "StatCounters.h"
 
 static PF diskHandleRead;
 static PF diskHandleWrite;
 
 #if _SQUID_WINDOWS_ || _SQUID_OS2_
 static int
 diskWriteIsComplete(int fd)
 {
     return fd_table[fd].disk.write_q ? 0 : 1;
 }
 
 #endif
 
 void
 disk_init(void)
 {
     (void) 0;
 }
 
 /* hack needed on SunStudio to avoid linkage convention mismatch */
@@ -425,41 +426,41 @@
     int rc = DISK_OK;
     /*
      * FD < 0 indicates premature close; we just have to free
      * the state data.
      */
 
     if (fd < 0) {
         memFree(ctrl_dat, MEM_DREAD_CTRL);
         return;
     }
 
     PROF_start(diskHandleRead);
 
 #if WRITES_MAINTAIN_DISK_OFFSET
     if (F->disk.offset != ctrl_dat->offset) {
 #else
     {
 #endif
         debugs(6, 3, "diskHandleRead: FD " << fd << " seeking to offset " << ctrl_dat->offset);
         lseek(fd, ctrl_dat->offset, SEEK_SET);	/* XXX ignore return? */
-        statCounter.syscalls.disk.seeks++;
+        ++statCounter.syscalls.disk.seeks;
         F->disk.offset = ctrl_dat->offset;
     }
 
     errno = 0;
     len = FD_READ_METHOD(fd, ctrl_dat->buf, ctrl_dat->req_len);
 
     if (len > 0)
         F->disk.offset += len;
 
     statCounter.syscalls.disk.reads++;
 
     fd_bytes(fd, len, FD_READ);
 
     if (len < 0) {
         if (ignoreErrno(errno)) {
             Comm::SetSelect(fd, COMM_SELECT_READ, diskHandleRead, ctrl_dat, 0);
             PROF_stop(diskHandleRead);
             return;
         }
 

=== modified file 'src/fqdncache.cc'
--- src/fqdncache.cc	2011-08-10 15:54:51 +0000
+++ src/fqdncache.cc	2011-12-15 21:17:34 +0000
@@ -21,40 +21,41 @@
  *  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 "squid.h"
 #include "cbdata.h"
 #include "DnsLookupDetails.h"
 #include "event.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 #include "wordlist.h"
 
 /**
  \defgroup FQDNCacheAPI FQDN Cache API
  \ingroup Components
  \section Introduction Introduction
  \par
  *  The FQDN cache is a built-in component of squid providing
  *  Hostname to IP-Number translation functionality and managing
  *  the involved data-structures. Efficiency concerns require
  *  mechanisms that allow non-blocking access to these mappings.
  *  The FQDN cache usually doesn't block on a request except for
  *  special cases where this is desired (see below).
  *
  \todo FQDN Cache should have its own API *.h file.
  */
 
 /**
  \defgroup FQDNCacheInternal FQDN Cache Internals
@@ -484,41 +485,41 @@
 
 #endif
 
 
 /**
  \ingroup FQDNCacheAPI
  *
  * Callback for handling DNS results.
  */
 static void
 #if USE_DNSSERVERS
 fqdncacheHandleReply(void *data, char *reply)
 #else
 fqdncacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_message)
 #endif
 {
     fqdncache_entry *f;
     static_cast<generic_cbdata *>(data)->unwrap(&f);
     ++FqdncacheStats.replies;
     const int age = f->age();
-    statHistCount(&statCounter.dns.svc_time, age);
+    statCounter.dns.svcTime.count(age);
 #if USE_DNSSERVERS
 
     fqdncacheParse(f, reply);
 #else
 
     fqdncacheParse(f, answers, na, error_message);
 #endif
 
     fqdncacheAddEntry(f);
 
     fqdncacheCallback(f, age);
 }
 
 /**
  \ingroup FQDNCacheAPI
  *
  \param addr		IP address of domain to resolve.
  \param handler		A pointer to the function to be called when
  *			the reply from the FQDN cache
  * 			(or the DNS if the FQDN cache misses)

=== modified file 'src/fs/ufs/store_dir_ufs.cc'
--- src/fs/ufs/store_dir_ufs.cc	2011-12-07 18:56:59 +0000
+++ src/fs/ufs/store_dir_ufs.cc	2011-12-13 17:33:34 +0000
@@ -28,40 +28,41 @@
  *  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 "squid.h"
 #include "Store.h"
 #include "fde.h"
 #include "ufscommon.h"
 #include "StoreSwapLogData.h"
 #include "ConfigOption.h"
 #include "DiskIO/DiskIOStrategy.h"
 #include "DiskIO/DiskIOModule.h"
 #include "FileMap.h"
 #include "Parsing.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "SwapDir.h"
 #include "swap_log_op.h"
 
 int UFSSwapDir::NumberOfUFSDirs = 0;
 int *UFSSwapDir::UFSDirToGlobalDirMapping = NULL;
 
 /*
  * storeUfsDirCheckObj
  *
  * This routine is called by storeDirSelectSwapDir to see if the given
  * object is able to be stored on this filesystem. UFS filesystems will
  * happily store anything as long as the LRU time isn't too small.
  */
 bool
 UFSSwapDir::canStore(const StoreEntry &e, int64_t diskSpaceNeeded, int &load) const
 {
     if (!SwapDir::canStore(e, diskSpaceNeeded, load))
         return false;
 
     if (IO->shedLoad())
@@ -1128,41 +1129,41 @@
                 if (UFSSwapDir::FilenoBelongsHere(fn, D0, D1, D2))
                     continue;
 
         files[k++] = swapfileno;
     }
 
     closedir(dir_pointer);
 
     if (k == 0)
         return 0;
 
     qsort(files, k, sizeof(int), rev_int_sort);
 
     if (k > 10)
         k = 10;
 
     for (n = 0; n < k; n++) {
         debugs(36, 3, "storeDirClean: Cleaning file "<< std::setfill('0') << std::hex << std::uppercase << std::setw(8) << files[n]);
         snprintf(p2, MAXPATHLEN + 1, "%s/%08X", p1, files[n]);
         safeunlink(p2, 0);
-        statCounter.swap.files_cleaned++;
+        ++statCounter.swap.files_cleaned;
     }
 
     debugs(36, 3, "Cleaned " << k << " unused files from " << p1);
     return k;
 }
 
 void
 UFSSwapDir::CleanEvent(void *unused)
 {
     static int swap_index = 0;
     int i;
     int j = 0;
     int n = 0;
     /*
      * Assert that there are UFS cache_dirs configured, otherwise
      * we should never be called.
      */
     assert(NumberOfUFSDirs);
 
     if (NULL == UFSDirToGlobalDirMapping) {

=== modified file 'src/ftp.cc'
--- src/ftp.cc	2011-11-28 02:22:22 +0000
+++ src/ftp.cc	2011-12-10 15:30:15 +0000
@@ -37,40 +37,41 @@
 #include "comm/ConnOpener.h"
 #include "CommCalls.h"
 #include "comm/TcpAcceptor.h"
 #include "comm/Write.h"
 #include "compat/strtoll.h"
 #include "errorpage.h"
 #include "fde.h"
 #include "forward.h"
 #include "html_quote.h"
 #include "HttpHdrContRange.h"
 #include "HttpHeaderRange.h"
 #include "HttpHeader.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "ip/tools.h"
 #include "MemBuf.h"
 #include "rfc1738.h"
 #include "Server.h"
 #include "SquidString.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 #include "URLScheme.h"
 #include "wordlist.h"
 
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #include "MemObject.h"
 #endif
 
 /**
  \defgroup ServerProtocolFTPInternal Server-Side FTP Internals
  \ingroup ServerProtocolFTPAPI
  */
 
 /// \ingroup ServerProtocolFTPInternal
 static const char *const crlf = "\r\n";
 
 #define CTRL_BUFLEN 1024
 /// \ingroup ServerProtocolFTPInternal
 static char cbuf[CTRL_BUFLEN];
@@ -1240,42 +1241,42 @@
     commSetConnTimeout(data.conn, Config.Timeout.read, timeoutCall);
 
     debugs(9,5,HERE << "queueing read on FD " << data.conn->fd);
 
     typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
     entry->delayAwareRead(data.conn, data.readBuf->space(), read_sz,
                           JobCallback(9, 5, Dialer, this, FtpStateData::dataRead));
 }
 
 void
 FtpStateData::dataRead(const CommIoCbParams &io)
 {
     int j;
     int bin;
 
     data.read_pending = false;
 
     debugs(9, 3, HERE << "ftpDataRead: FD " << io.fd << " Read " << io.size << " bytes");
 
     if (io.size > 0) {
-        kb_incr(&statCounter.server.all.kbytes_in, io.size);
-        kb_incr(&statCounter.server.ftp.kbytes_in, io.size);
+        kb_incr(&(statCounter.server.all.kbytes_in), io.size);
+        kb_incr(&(statCounter.server.ftp.kbytes_in), io.size);
     }
 
     if (io.flag == COMM_ERR_CLOSING)
         return;
 
     assert(io.fd == data.conn->fd);
 
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
         abortTransaction("entry aborted during dataRead");
         return;
     }
 
     if (io.flag == COMM_OK && io.size > 0) {
         debugs(9,5,HERE << "appended " << io.size << " bytes to readBuf");
         data.readBuf->appended(io.size);
 #if USE_DELAY_POOLS
         DelayId delayId = entry->mem_obj->mostBytesAllowed();
         delayId.bytesIn(io.size);
 #endif
         IOStats.Ftp.reads++;
@@ -1596,42 +1597,42 @@
         debugs(9, 2, HERE << "cannot send to closing ctrl " << ctrl.conn);
         // TODO: assert(ctrl.closer != NULL);
         return;
     }
 
     typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
     AsyncCall::Pointer call = JobCallback(9, 5, Dialer, this, FtpStateData::ftpWriteCommandCallback);
     Comm::Write(ctrl.conn, ctrl.last_command, strlen(ctrl.last_command), call, NULL);
 
     scheduleReadControlReply(0);
 }
 
 void
 FtpStateData::ftpWriteCommandCallback(const CommIoCbParams &io)
 {
 
     debugs(9, 5, "ftpWriteCommandCallback: wrote " << io.size << " bytes");
 
     if (io.size > 0) {
         fd_bytes(io.fd, io.size, FD_WRITE);
-        kb_incr(&statCounter.server.all.kbytes_out, io.size);
-        kb_incr(&statCounter.server.ftp.kbytes_out, io.size);
+        kb_incr(&(statCounter.server.all.kbytes_out), io.size);
+        kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
     }
 
     if (io.flag == COMM_ERR_CLOSING)
         return;
 
     if (io.flag) {
         debugs(9, DBG_IMPORTANT, "ftpWriteCommandCallback: " << io.conn << ": " << xstrerr(io.xerrno));
         failed(ERR_WRITE_ERROR, io.xerrno);
         /* failed closes ctrl.conn and frees ftpState */
         return;
     }
 }
 
 wordlist *
 FtpStateData::ftpParseControlReply(char *buf, size_t len, int *codep, size_t *used)
 {
     char *s;
     char *sbuf;
     char *end;
     int usable;
@@ -1737,42 +1738,42 @@
          */
         if (Comm::IsConnOpen(data.conn)) {
             commUnsetConnTimeout(data.conn);
         }
 
         typedef CommCbMemFunT<FtpStateData, CommTimeoutCbParams> TimeoutDialer;
         AsyncCall::Pointer timeoutCall = JobCallback(9, 5, TimeoutDialer, this, FtpStateData::ftpTimeout);
         commSetConnTimeout(ctrl.conn, Config.Timeout.read, timeoutCall);
 
         typedef CommCbMemFunT<FtpStateData, CommIoCbParams> Dialer;
         AsyncCall::Pointer reader = JobCallback(9, 5, Dialer, this, FtpStateData::ftpReadControlReply);
         comm_read(ctrl.conn, ctrl.buf + ctrl.offset, ctrl.size - ctrl.offset, reader);
     }
 }
 
 void FtpStateData::ftpReadControlReply(const CommIoCbParams &io)
 {
     debugs(9, 3, "ftpReadControlReply: FD " << io.fd << ", Read " << io.size << " bytes");
 
     if (io.size > 0) {
-        kb_incr(&statCounter.server.all.kbytes_in, io.size);
-        kb_incr(&statCounter.server.ftp.kbytes_in, io.size);
+        kb_incr(&(statCounter.server.all.kbytes_in), io.size);
+        kb_incr(&(statCounter.server.ftp.kbytes_in), io.size);
     }
 
     if (io.flag == COMM_ERR_CLOSING)
         return;
 
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
         abortTransaction("entry aborted during control reply read");
         return;
     }
 
     assert(ctrl.offset < ctrl.size);
 
     if (io.flag == COMM_OK && io.size > 0) {
         fd_bytes(io.fd, io.size, FD_READ);
     }
 
     if (io.flag != COMM_OK) {
         debugs(50, ignoreErrno(io.xerrno) ? 3 : DBG_IMPORTANT,
                "ftpReadControlReply: read error: " << xstrerr(io.xerrno));
 
@@ -3300,41 +3301,41 @@
         return;
     }
 }
 
 // premature end of the request body
 void
 FtpStateData::handleRequestBodyProducerAborted()
 {
     ServerStateData::handleRequestBodyProducerAborted();
     debugs(9, 3, HERE << "ftpState=" << this);
     failed(ERR_READ_ERROR, 0);
 }
 
 /**
  * This will be called when the put write is completed
  */
 void
 FtpStateData::sentRequestBody(const CommIoCbParams &io)
 {
     if (io.size > 0)
-        kb_incr(&statCounter.server.ftp.kbytes_out, io.size);
+        kb_incr(&(statCounter.server.ftp.kbytes_out), io.size);
     ServerStateData::sentRequestBody(io);
 }
 
 /// \ingroup ServerProtocolFTPInternal
 static void
 ftpWriteTransferDone(FtpStateData * ftpState)
 {
     int code = ftpState->ctrl.replycode;
     debugs(9, 3, HERE);
 
     if (!(code == 226 || code == 250)) {
         debugs(9, DBG_IMPORTANT, HERE << "Got code " << code << " after sending data");
         ftpState->failed(ERR_FTP_PUT_ERROR, 0);
         return;
     }
 
     ftpState->entry->timestampsSet();	/* XXX Is this needed? */
     ftpSendReply(ftpState);
 }
 

=== modified file 'src/globals.h'
--- src/globals.h	2011-08-10 15:54:51 +0000
+++ src/globals.h	2011-12-10 07:08:39 +0000
@@ -24,41 +24,41 @@
  *  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.
  *
  */
 #ifndef SQUID_GLOBALS_H
 #define SQUID_GLOBALS_H
 
 #if HAVE_STDIO_H
 #include <stdio.h>
 #endif
 
 #include "rfc2181.h"
 
 /* for ERROR_BUF_SZ, BUFSIZ, MAXHTTPPORTS */
 #include "defines.h"
 
-/* for iostats, StatCounters */
+/* for iostats */
 #include "structs.h"
 
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 //MOVED:Debug.h    extern FILE *debug_log;		/* NULL */
 //MOVED:structs.h    extern SquidConfig Config;
 //MOVED:structs.h    extern SquidConfig2 Config2;
     extern char *ConfigFile;	/* NULL */
     extern char *IcpOpcodeStr[];
     extern char tmp_error_buf[ERROR_BUF_SZ];
     extern char ThisCache[RFC2181_MAXHOSTNAMELEN << 1];
     extern char ThisCache2[RFC2181_MAXHOSTNAMELEN << 1];
     extern char config_input_line[BUFSIZ];
     extern const char *DefaultConfigFile;	/* DEFAULT_CONFIG_FILE */
     extern const char *cfg_filename;	/* NULL */
 //MOVED:version.h:APP_SHORTNAME    extern const char *const appname;	/* "squid" */
     extern const char *const dash_str;	/* "-" */
@@ -92,41 +92,40 @@
     extern int opt_foreground_rebuild;	/* 0 */
     extern char *opt_forwarded_for;	/* NULL */
     extern int opt_reload_hit_only;	/* 0 */
 
     extern int opt_udp_hit_obj;	/* 0 */
     extern int opt_create_swap_dirs;	/* 0 */
     extern int opt_store_doublecheck;	/* 0 */
     extern int syslog_enable;	/* 0 */
     extern int DnsSocketA;		/* -1 */
     extern int DnsSocketB;		/* -1 */
     extern int n_disk_objects;	/* 0 */
     extern iostats IOStats;
 
     extern struct acl_deny_info_list *DenyInfoList;	/* NULL */
 
     extern struct timeval squid_start;
     extern int starting_up;	/* 1 */
     extern int shutting_down;	/* 0 */
     extern int reconfiguring;	/* 0 */
     extern time_t hit_only_mode_until;	/* 0 */
-    extern StatCounters statCounter;
     extern double request_failure_ratio;	/* 0.0 */
     extern int store_hash_buckets;	/* 0 */
     extern hash_table *store_table;	/* NULL */
 //MOVED:dlink.h    extern dlink_list ClientActiveRequests;
     extern int hot_obj_count;	/* 0 */
     extern const int CacheDigestHashFuncCount;	/* 4 */
     extern CacheDigest *store_digest;	/* NULL */
     extern const char *StoreDigestFileName;		/* "store_digest" */
     extern const char *StoreDigestMimeStr;	/* "application/cache-digest" */
 
     extern const char *MultipartMsgBoundaryStr;	/* "Unique-Squid-Separator" */
 #if USE_HTTP_VIOLATIONS
 
     extern int refresh_nocache_hack;	/* 0 */
 #endif
 
     extern int store_open_disk_fd;	/* 0 */
     extern const char *SwapDirType[];
     extern int store_swap_low;	/* 0 */
     extern int store_swap_high;	/* 0 */

=== modified file 'src/gopher.cc'
--- src/gopher.cc	2011-11-27 12:37:35 +0000
+++ src/gopher.cc	2011-12-10 15:30:15 +0000
@@ -31,40 +31,41 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 #include "squid.h"
 #include "comm/Write.h"
 #include "errorpage.h"
 #include "Store.h"
 #include "html_quote.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
 #include "comm.h"
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #include "MemObject.h"
 #endif
 #include "MemBuf.h"
 #include "forward.h"
 #include "rfc1738.h"
+#include "StatCounters.h"
 #include "SquidTime.h"
 
 /**
  \defgroup ServerProtocolGopherInternal Server-Side Gopher Internals
  \ingroup ServerProtocolGopherAPI
  * Gopher is somewhat complex and gross because it must convert from
  * the Gopher protocol to HTTP.
  */
 
 /* gopher type code from rfc. Anawat. */
 /// \ingroup ServerProtocolGopherInternal
 #define GOPHER_FILE         '0'
 /// \ingroup ServerProtocolGopherInternal
 #define GOPHER_DIRECTORY    '1'
 /// \ingroup ServerProtocolGopherInternal
 #define GOPHER_CSO          '2'
 /// \ingroup ServerProtocolGopherInternal
 #define GOPHER_ERROR        '3'
 /// \ingroup ServerProtocolGopherInternal
 #define GOPHER_MACBINHEX    '4'
@@ -752,42 +753,42 @@
 
     assert(buf == gopherState->replybuf);
 
     if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
         gopherState->serverConn->close();
         return;
     }
 
     errno = 0;
 #if USE_DELAY_POOLS
     read_sz = delayId.bytesWanted(1, read_sz);
 #endif
 
     /* leave one space for \0 in gopherToHTML */
 
     if (flag == COMM_OK && len > 0) {
 #if USE_DELAY_POOLS
         delayId.bytesIn(len);
 #endif
 
-        kb_incr(&statCounter.server.all.kbytes_in, len);
-        kb_incr(&statCounter.server.other.kbytes_in, len);
+        kb_incr(&(statCounter.server.all.kbytes_in), len);
+        kb_incr(&(statCounter.server.other.kbytes_in), len);
     }
 
     debugs(10, 5, HERE << conn << " read len=" << len);
 
     if (flag == COMM_OK && len > 0) {
         AsyncCall::Pointer nil;
         commSetConnTimeout(conn, Config.Timeout.read, nil);
         IOStats.Gopher.reads++;
 
         for (clen = len - 1, bin = 0; clen; bin++)
             clen >>= 1;
 
         IOStats.Gopher.read_hist[bin]++;
 
         HttpRequest *req = gopherState->fwd->request;
         if (req->hier.bodyBytesRead < 0)
             req->hier.bodyBytesRead = 0;
 
         req->hier.bodyBytesRead += len;
     }
@@ -827,42 +828,42 @@
         }
         AsyncCall::Pointer call = commCbCall(5,4, "gopherReadReply",
                                              CommIoCbPtrFun(gopherReadReply, gopherState));
         comm_read(conn, buf, read_sz, call);
     }
 }
 
 /**
  \ingroup ServerProtocolGopherInternal
  * This will be called when request write is complete. Schedule read of reply.
  */
 static void
 gopherSendComplete(const Comm::ConnectionPointer &conn, char *buf, size_t size, comm_err_t errflag, int xerrno, void *data)
 {
     GopherStateData *gopherState = (GopherStateData *) data;
     StoreEntry *entry = gopherState->entry;
     debugs(10, 5, HERE << conn << " size: " << size << " errflag: " << errflag);
 
     if (size > 0) {
         fd_bytes(conn->fd, size, FD_WRITE);
-        kb_incr(&statCounter.server.all.kbytes_out, size);
-        kb_incr(&statCounter.server.other.kbytes_out, size);
+        kb_incr(&(statCounter.server.all.kbytes_out), size);
+        kb_incr(&(statCounter.server.other.kbytes_out), size);
     }
 
     if (errflag) {
         ErrorState *err;
         err = new ErrorState(ERR_WRITE_ERROR, HTTP_SERVICE_UNAVAILABLE, gopherState->fwd->request);
         err->xerrno = errno;
         err->port = gopherState->fwd->request->port;
         err->url = xstrdup(entry->url());
         gopherState->fwd->fail(err);
         gopherState->serverConn->close();
 
         if (buf)
             memFree(buf, MEM_4K_BUF);	/* Allocated by gopherSendRequest. */
 
         return;
     }
 
     /*
      * OK. We successfully reach remote site.  Start MIME typing
      * stuff.  Do it anyway even though request is not HTML type.

=== modified file 'src/htcp.cc'
--- src/htcp.cc	2011-12-03 12:40:23 +0000
+++ src/htcp.cc	2011-12-10 15:30:16 +0000
@@ -30,40 +30,41 @@
  *  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 "squid.h"
 #include "AccessLogEntry.h"
 #include "acl/FilledChecklist.h"
 #include "acl/Acl.h"
 #include "comm.h"
 #include "comm/Loops.h"
 #include "htcp.h"
 #include "http.h"
 #include "HttpRequest.h"
 #include "icmp/net_db.h"
 #include "ipc/StartListening.h"
 #include "ip/tools.h"
 #include "MemBuf.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 #include "StoreClient.h"
 #include "compat/xalloc.h"
 
 /// dials htcpIncomingConnectionOpened call
 class HtcpListeningStartedDialer: public CallDialer,
         public Ipc::StartListeningCb
 {
 public:
     typedef void (*Handler)(int errNo);
     HtcpListeningStartedDialer(Handler aHandler): handler(aHandler) {}
 
     virtual void print(std::ostream &os) const { startPrint(os) << ')'; }
     virtual bool canDial(AsyncCall &) const { return true; }
     virtual void dial(AsyncCall &) { (handler)(errNo); }
 
 public:
     Handler handler;
 };
 

=== modified file 'src/http.cc'
--- src/http.cc	2011-12-03 12:40:23 +0000
+++ src/http.cc	2011-12-10 15:30:17 +0000
@@ -51,40 +51,41 @@
 #include "comm/Write.h"
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
 #include "err_detail_type.h"
 #include "errorpage.h"
 #include "fde.h"
 #include "http.h"
 #include "HttpControlMsg.h"
 #include "HttpHdrContRange.h"
 #include "HttpHdrCc.h"
 #include "HttpHdrSc.h"
 #include "HttpHdrScTarget.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "MemBuf.h"
 #include "MemObject.h"
 #include "protos.h"
 #include "rfc1738.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 
 
 #define SQUID_ENTER_THROWING_CODE() try {
 #define SQUID_EXIT_THROWING_CODE(status) \
   	status = true; \
     } \
     catch (const std::exception &e) { \
 	debugs (11, 1, "Exception error:" << e.what()); \
 	status = false; \
     }
 
 CBDATA_CLASS_INIT(HttpStateData);
 
 static const char *const crlf = "\r\n";
 
 static void httpMaybeRemovePublic(StoreEntry *, http_status);
 static void copyOneHeaderFromClientsideRequestToUpstreamRequest(const HttpHeaderEntry *e, const String strConnection, const HttpRequest * request,
         HttpHeader * hdr_out, const int we_do_ranges, const http_state_flags);
 
@@ -1078,42 +1079,42 @@
         } else {
             ErrorState *err = new ErrorState(ERR_READ_ERROR, HTTP_BAD_GATEWAY, fwd->request);
             err->xerrno = io.xerrno;
             fwd->fail(err);
             flags.do_next_read = 0;
             serverConnection->close();
         }
 
         return;
     }
 
     // update I/O stats
     if (len > 0) {
         readBuf->appended(len);
         reply_bytes_read += len;
 #if USE_DELAY_POOLS
         DelayId delayId = entry->mem_obj->mostBytesAllowed();
         delayId.bytesIn(len);
 #endif
 
-        kb_incr(&statCounter.server.all.kbytes_in, len);
-        kb_incr(&statCounter.server.http.kbytes_in, len);
+        kb_incr(&(statCounter.server.all.kbytes_in), len);
+        kb_incr(&(statCounter.server.http.kbytes_in), len);
         IOStats.Http.reads++;
 
         for (clen = len - 1, bin = 0; clen; bin++)
             clen >>= 1;
 
         IOStats.Http.read_hist[bin]++;
 
         // update peer response time stats (%<pt)
         const timeval &sent = request->hier.peer_http_request_sent;
         request->hier.peer_response_time =
             sent.tv_sec ? tvSubMsec(sent, current_time) : -1;
     }
 
     /** \par
      * Here the RFC says we should ignore whitespace between replies, but we can't as
      * doing so breaks HTTP/0.9 replies beginning with witespace, and in addition
      * the response splitting countermeasures is extremely likely to trigger on this,
      * not allowing connection reuse in the first place.
      */
 #if DONT_DO_THIS
@@ -1448,42 +1449,42 @@
     if (flags.do_next_read) {
         flags.do_next_read = 0;
         typedef CommCbMemFunT<HttpStateData, CommIoCbParams> Dialer;
         entry->delayAwareRead(serverConnection, readBuf->space(read_size), read_size,
                               JobCallback(11, 5, Dialer, this,  HttpStateData::readReply));
     }
 }
 
 /// called after writing the very last request byte (body, last-chunk, etc)
 void
 HttpStateData::wroteLast(const CommIoCbParams &io)
 {
     debugs(11, 5, HERE << serverConnection << ": size " << io.size << ": errflag " << io.flag << ".");
 #if URL_CHECKSUM_DEBUG
 
     entry->mem_obj->checkUrlChecksum();
 #endif
 
     if (io.size > 0) {
         fd_bytes(io.fd, io.size, FD_WRITE);
-        kb_incr(&statCounter.server.all.kbytes_out, io.size);
-        kb_incr(&statCounter.server.http.kbytes_out, io.size);
+        kb_incr(&(statCounter.server.all.kbytes_out), io.size);
+        kb_incr(&(statCounter.server.http.kbytes_out), io.size);
     }
 
     if (io.flag == COMM_ERR_CLOSING)
         return;
 
     if (io.flag) {
         ErrorState *err = new ErrorState(ERR_WRITE_ERROR, HTTP_BAD_GATEWAY, fwd->request);
         err->xerrno = io.xerrno;
         fwd->fail(err);
         serverConnection->close();
         return;
     }
 
     sendComplete();
 }
 
 /// successfully wrote the entire request (including body, last-chunk, etc.)
 void
 HttpStateData::sendComplete()
 {

=== modified file 'src/icp_v2.cc'
--- src/icp_v2.cc	2011-07-27 13:38:06 +0000
+++ src/icp_v2.cc	2011-12-15 21:17:34 +0000
@@ -29,40 +29,41 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  *
  */
 
 /**
  \defgroup ServerProtocolICPInternal2 ICPv2 Internals
  \ingroup ServerProtocolICPAPI
  */
 
 #include "squid.h"
 #include "Store.h"
 #include "comm.h"
 #include "comm/Loops.h"
 #include "ICP.h"
 #include "comm/Connection.h"
 #include "HttpRequest.h"
 #include "acl/FilledChecklist.h"
 #include "acl/Acl.h"
 #include "AccessLogEntry.h"
 #include "wordlist.h"
+#include "StatCounters.h"
 #include "SquidTime.h"
 #include "SwapDir.h"
 #include "icmp/net_db.h"
 #include "ip/Address.h"
 #include "ip/tools.h"
 #include "ipc/StartListening.h"
 #include "ipcache.h"
 #include "rfc1738.h"
 
 /// dials icpIncomingConnectionOpened call
 class IcpListeningStartedDialer: public CallDialer,
         public Ipc::StartListeningCb
 {
 public:
     typedef void (*Handler)(int errNo);
     IcpListeningStartedDialer(Handler aHandler):
             handler(aHandler) {}
 
     virtual void print(std::ostream &os) const { startPrint(os) << ')'; }
     virtual bool canDial(AsyncCall &) const { return true; }
@@ -793,56 +794,56 @@
 
 static void
 icpCount(void *buf, int which, size_t len, int delay)
 {
     icp_common_t *icp = (icp_common_t *) buf;
 
     if (len < sizeof(*icp))
         return;
 
     if (SENT == which) {
         statCounter.icp.pkts_sent++;
         kb_incr(&statCounter.icp.kbytes_sent, len);
 
         if (ICP_QUERY == icp->opcode) {
             statCounter.icp.queries_sent++;
             kb_incr(&statCounter.icp.q_kbytes_sent, len);
         } else {
             statCounter.icp.replies_sent++;
             kb_incr(&statCounter.icp.r_kbytes_sent, len);
             /* this is the sent-reply service time */
-            statHistCount(&statCounter.icp.reply_svc_time, delay);
+            statCounter.icp.replySvcTime.count(delay);
         }
 
         if (ICP_HIT == icp->opcode)
             statCounter.icp.hits_sent++;
     } else if (RECV == which) {
         statCounter.icp.pkts_recv++;
         kb_incr(&statCounter.icp.kbytes_recv, len);
 
         if (ICP_QUERY == icp->opcode) {
             statCounter.icp.queries_recv++;
             kb_incr(&statCounter.icp.q_kbytes_recv, len);
         } else {
             statCounter.icp.replies_recv++;
             kb_incr(&statCounter.icp.r_kbytes_recv, len);
-            /* statCounter.icp.query_svc_time set in clientUpdateCounters */
+            /* statCounter.icp.querySvcTime set in clientUpdateCounters */
         }
 
         if (ICP_HIT == icp->opcode)
             statCounter.icp.hits_recv++;
     }
 }
 
 #define N_QUERIED_KEYS 8192
 #define N_QUERIED_KEYS_MASK 8191
 static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH];
 
 int
 icpSetCacheKey(const cache_key * key)
 {
     static int reqnum = 0;
 
     if (++reqnum < 0)
         reqnum = 1;
 
     storeKeyCopy(queried_keys[reqnum & N_QUERIED_KEYS_MASK], key);

=== modified file 'src/ipcache.cc'
--- src/ipcache.cc	2011-09-04 18:28:39 +0000
+++ src/ipcache.cc	2011-12-15 21:17:34 +0000
@@ -23,40 +23,41 @@
  *  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 "squid.h"
 #include "cbdata.h"
 #include "CacheManager.h"
 #include "DnsLookupDetails.h"
 #include "event.h"
 #include "ip/Address.h"
 #include "ip/tools.h"
 #include "ipcache.h"
 #include "mgr/Registration.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "Store.h"
 #include "wordlist.h"
 
 /**
  \defgroup IPCacheAPI IP Cache API
  \ingroup Components
  \section Introduction Introduction
  \par
  *  The IP cache is a built-in component of squid providing
  *  Hostname to IP-Number translation functionality and managing
  *  the involved data-structures. Efficiency concerns require
  *  mechanisms that allow non-blocking access to these mappings.
  *  The IP cache usually doesn't block on a request except for
  *  special cases where this is desired (see below).
  *
  \todo IP Cache should have its own API *.h header file.
  */
 
 /**
  \defgroup IPCacheInternal IP Cache Internals
@@ -580,41 +581,41 @@
 
     i->flags.negcached = 0;
 
     return i->addrs.count;
 }
 
 #endif
 
 /// \ingroup IPCacheInternal
 static void
 #if USE_DNSSERVERS
 ipcacheHandleReply(void *data, char *reply)
 #else
 ipcacheHandleReply(void *data, rfc1035_rr * answers, int na, const char *error_message)
 #endif
 {
     ipcache_entry *i;
     static_cast<generic_cbdata *>(data)->unwrap(&i);
     IpcacheStats.replies++;
     const int age = i->age();
-    statHistCount(&statCounter.dns.svc_time, age);
+    statCounter.dns.svcTime.count(age);
 
 #if USE_DNSSERVERS
     ipcacheParse(i, reply);
 #else
 
     int done = ipcacheParse(i, answers, na, error_message);
 
     /* If we have not produced either IPs or Error immediately, wait for recursion to finish. */
     if (done != 0 || error_message != NULL)
 #endif
 
     {
         ipcacheAddEntry(i);
         ipcacheCallback(i, age);
     }
 }
 
 /**
  \ingroup IPCacheAPI
  *

=== modified file 'src/main.cc'
--- src/main.cc	2011-11-18 07:48:25 +0000
+++ src/main.cc	2011-12-10 15:30:19 +0000
@@ -65,40 +65,41 @@
 #include "ExternalACL.h"
 #include "format/Token.h"
 #include "fs/Module.h"
 #include "PeerSelectState.h"
 #include "Store.h"
 #include "ICP.h"
 #include "ident/Ident.h"
 #include "HttpReply.h"
 #include "pconn.h"
 #include "Mem.h"
 #include "acl/Asn.h"
 #include "acl/Acl.h"
 #include "htcp.h"
 #include "StoreFileSystem.h"
 #include "DiskIO/DiskIOModule.h"
 #include "ipc/Kids.h"
 #include "ipc/Coordinator.h"
 #include "ipc/Strand.h"
 #include "ip/tools.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "SwapDir.h"
 #include "forward.h"
 #include "MemPool.h"
 #include "icmp/IcmpSquid.h"
 #include "icmp/net_db.h"
 
 #if USE_LOADABLE_MODULES
 #include "LoadableModules.h"
 #endif
 
 #if USE_SSL_CRTD
 #include "ssl/helper.h"
 #include "ssl/certificate_db.h"
 #endif
 
 #if USE_SSL
 #include "ssl/context_storage.h"
 #endif
 
 #if ICAP_CLIENT

=== modified file 'src/protos.h'
--- src/protos.h	2011-12-07 18:56:59 +0000
+++ src/protos.h	2011-12-15 21:17:34 +0000
@@ -194,40 +194,42 @@
 
 /// \ingroup ServerProtocolWhoisAPI
 SQUIDCEXTERN void whoisStart(FwdState *);
 
 
 /* http.c */
 /* for http_hdr_type field */
 #include "HttpHeader.h"
 SQUIDCEXTERN int httpCachable(const HttpRequestMethod&);
 SQUIDCEXTERN void httpStart(FwdState *);
 SQUIDCEXTERN mb_size_t httpBuildRequestPrefix(HttpRequest * request,
         HttpRequest * orig_request,
         StoreEntry * entry,
         MemBuf * mb,
         http_state_flags);
 SQUIDCEXTERN const char *httpMakeVaryMark(HttpRequest * request, HttpReply const * reply);
 
 #include "HttpStatusCode.h"
 SQUIDCEXTERN const char *httpStatusString(http_status status);
 
+class StatHist;
+
 /* Http Cache Control Header Field */
 SQUIDCEXTERN void httpHdrCcInitModule(void);
 SQUIDCEXTERN void httpHdrCcCleanModule(void);
 SQUIDCEXTERN void httpHdrCcUpdateStats(const HttpHdrCc * cc, StatHist * hist);
 void httpHdrCcStatDumper(StoreEntry * sentry, int idx, double val, double size, int count);
 
 /* Http Header Tools */
 class HttpHeaderFieldInfo;
 SQUIDCEXTERN HttpHeaderFieldInfo *httpHeaderBuildFieldsInfo(const HttpHeaderFieldAttrs * attrs, int count);
 SQUIDCEXTERN void httpHeaderDestroyFieldsInfo(HttpHeaderFieldInfo * info, int count);
 SQUIDCEXTERN http_hdr_type httpHeaderIdByName(const char *name, size_t name_len, const HttpHeaderFieldInfo * attrs, int end);
 SQUIDCEXTERN http_hdr_type httpHeaderIdByNameDef(const char *name, int name_len);
 SQUIDCEXTERN const char *httpHeaderNameById(int id);
 SQUIDCEXTERN int httpHeaderHasConnDir(const HttpHeader * hdr, const char *directive);
 SQUIDCEXTERN void strListAdd(String * str, const char *item, char del);
 SQUIDCEXTERN int strListIsMember(const String * str, const char *item, char del);
 SQUIDCEXTERN int strListIsSubstr(const String * list, const char *s, char del);
 SQUIDCEXTERN int strListGetItem(const String * str, char del, const char **item, int *ilen, const char **pos);
 SQUIDCEXTERN const char *getStringPrefix(const char *str, const char *end);
 SQUIDCEXTERN int httpHeaderParseInt(const char *start, int *val);
@@ -372,55 +374,40 @@
 
 extern void shut_down(int);
 extern void rotate_logs(int);
 extern void reconfigure(int);
 
 
 extern void start_announce(void *unused);
 extern void waisStart(FwdState *);
 
 SQUIDCEXTERN void statInit(void);
 SQUIDCEXTERN void statFreeMemory(void);
 SQUIDCEXTERN double median_svc_get(int, int);
 SQUIDCEXTERN void pconnHistCount(int, int);
 SQUIDCEXTERN int stat5minClientRequests(void);
 SQUIDCEXTERN double stat5minCPUUsage(void);
 SQUIDCEXTERN double statRequestHitRatio(int minutes);
 SQUIDCEXTERN double statRequestHitMemoryRatio(int minutes);
 SQUIDCEXTERN double statRequestHitDiskRatio(int minutes);
 SQUIDCEXTERN double statByteHitRatio(int minutes);
 
-/* StatHist */
-SQUIDCEXTERN void statHistClean(StatHist * H);
-SQUIDCEXTERN void statHistCount(StatHist * H, double val);
-SQUIDCEXTERN void statHistCopy(StatHist * Dest, const StatHist * Orig);
-SQUIDCEXTERN void statHistSafeCopy(StatHist * Dest, const StatHist * Orig);
-SQUIDCEXTERN double statHistDeltaMedian(const StatHist * A, const StatHist * B);
-SQUIDCEXTERN double statHistDeltaPctile(const StatHist * A, const StatHist * B, double pctile);
-SQUIDCEXTERN void statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd);
-SQUIDCEXTERN void statHistLogInit(StatHist * H, int capacity, double min, double max);
-SQUIDCEXTERN void statHistEnumInit(StatHist * H, int last_enum);
-SQUIDCEXTERN void statHistIntInit(StatHist * H, int n);
-SQUIDCEXTERN StatHistBinDumper statHistEnumDumper;
-SQUIDCEXTERN StatHistBinDumper statHistIntDumper;
-
-
 /* mem */
 SQUIDCEXTERN void memClean(void);
 SQUIDCEXTERN void memInitModule(void);
 SQUIDCEXTERN void memCleanModule(void);
 SQUIDCEXTERN void memConfigure(void);
 SQUIDCEXTERN void *memAllocate(mem_type);
 SQUIDCEXTERN void *memAllocString(size_t net_size, size_t * gross_size);
 SQUIDCEXTERN void *memAllocBuf(size_t net_size, size_t * gross_size);
 SQUIDCEXTERN void *memReallocBuf(void *buf, size_t net_size, size_t * gross_size);
 SQUIDCEXTERN void memFree(void *, int type);
 void memFree2K(void *);
 void memFree4K(void *);
 void memFree8K(void *);
 void memFree16K(void *);
 void memFree32K(void *);
 void memFree64K(void *);
 SQUIDCEXTERN void memFreeString(size_t size, void *);
 SQUIDCEXTERN void memFreeBuf(size_t size, void *);
 SQUIDCEXTERN FREE *memFreeBufFunc(size_t size);
 SQUIDCEXTERN int memInUse(mem_type);
@@ -610,54 +597,54 @@
 SQUIDCEXTERN void parseEtcHosts(void);
 SQUIDCEXTERN int getMyPort(void);
 SQUIDCEXTERN void setUmask(mode_t mask);
 
 SQUIDCEXTERN char *strwordtok(char *buf, char **t);
 SQUIDCEXTERN void strwordquote(MemBuf * mb, const char *str);
 
 
 /*
  * ipc.c
  */
 SQUIDCEXTERN pid_t ipcCreate(int type,
                              const char *prog,
                              const char *const args[],
                              const char *name,
                              Ip::Address &local_addr,
                              int *rfd,
                              int *wfd,
                              void **hIpc);
 
-
+class CacheDigestGuessStats;
 /* CacheDigest */
 SQUIDCEXTERN CacheDigest *cacheDigestCreate(int capacity, int bpe);
 SQUIDCEXTERN void cacheDigestDestroy(CacheDigest * cd);
 SQUIDCEXTERN CacheDigest *cacheDigestClone(const CacheDigest * cd);
 SQUIDCEXTERN void cacheDigestClear(CacheDigest * cd);
 SQUIDCEXTERN void cacheDigestChangeCap(CacheDigest * cd, int new_cap);
 SQUIDCEXTERN int cacheDigestTest(const CacheDigest * cd, const cache_key * key);
 SQUIDCEXTERN void cacheDigestAdd(CacheDigest * cd, const cache_key * key);
 SQUIDCEXTERN void cacheDigestDel(CacheDigest * cd, const cache_key * key);
 SQUIDCEXTERN size_t cacheDigestCalcMaskSize(int cap, int bpe);
 SQUIDCEXTERN int cacheDigestBitUtil(const CacheDigest * cd);
-SQUIDCEXTERN void cacheDigestGuessStatsUpdate(cd_guess_stats * stats, int real_hit, int guess_hit);
-SQUIDCEXTERN void cacheDigestGuessStatsReport(const cd_guess_stats * stats, StoreEntry * sentry, const char *label);
+SQUIDCEXTERN void cacheDigestGuessStatsUpdate(CacheDigestGuessStats * stats, int real_hit, int guess_hit);
+SQUIDCEXTERN void cacheDigestGuessStatsReport(const CacheDigestGuessStats * stats, StoreEntry * sentry, const char *label);
 SQUIDCEXTERN void cacheDigestReport(CacheDigest * cd, const char *label, StoreEntry * e);
 
 SQUIDCEXTERN void internalStart(const Comm::ConnectionPointer &clientConn, HttpRequest *, StoreEntry *);
 SQUIDCEXTERN int internalCheck(const char *urlpath);
 SQUIDCEXTERN int internalStaticCheck(const char *urlpath);
 SQUIDCEXTERN char *internalLocalUri(const char *dir, const char *name);
 SQUIDCEXTERN char *internalRemoteUri(const char *, unsigned short, const char *, const char *);
 SQUIDCEXTERN const char *internalHostname(void);
 SQUIDCEXTERN int internalHostnameIs(const char *);
 
 SQUIDCEXTERN void carpInit(void);
 SQUIDCEXTERN peer *carpSelectParent(HttpRequest *);
 
 SQUIDCEXTERN void peerUserHashInit(void);
 SQUIDCEXTERN peer * peerUserHashSelectParent(HttpRequest * request);
 
 SQUIDCEXTERN void peerSourceHashInit(void);
 SQUIDCEXTERN peer * peerSourceHashSelectParent(HttpRequest * request);
 
 #if USE_LEAKFINDER
@@ -667,40 +654,41 @@
 SQUIDCEXTERN void *leakFreeFL(void *, const char *, int);
 #endif
 
 /*
  * prototypes for system functions missing from system includes
  */
 
 #if _SQUID_SOLARIS_
 
 SQUIDCEXTERN int getrusage(int, struct rusage *);
 SQUIDCEXTERN int getpagesize(void);
 #if !defined(_XPG4_2) && !(defined(__EXTENSIONS__) || \
 (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)))
 SQUIDCEXTERN int gethostname(char *, int);
 #endif
 #endif
 
 /*
  * hack to allow snmp access to the statistics counters
  */
+class StatCounters;
 SQUIDCEXTERN StatCounters *snmpStatGet(int);
 
 /* Vary support functions */
 SQUIDCEXTERN int varyEvaluateMatch(StoreEntry * entry, HttpRequest * req);
 
 /* CygWin & Windows NT Port */
 /* win32.c */
 #if _SQUID_WINDOWS_
 SQUIDCEXTERN int WIN32_Subsystem_Init(int *, char ***);
 SQUIDCEXTERN void WIN32_sendSignal(int);
 SQUIDCEXTERN void WIN32_Abort(int);
 SQUIDCEXTERN void WIN32_Exit(void);
 SQUIDCEXTERN void WIN32_SetServiceCommandLine(void);
 SQUIDCEXTERN void WIN32_InstallService(void);
 SQUIDCEXTERN void WIN32_RemoveService(void);
 SQUIDCEXTERN int SquidMain(int, char **);
 #endif /* _SQUID_WINDOWS_ */
 #if _SQUID_MSWIN_
 
 SQUIDCEXTERN int WIN32_pipe(int[2]);

=== modified file 'src/snmp_agent.cc'
--- src/snmp_agent.cc	2011-04-27 23:34:13 +0000
+++ src/snmp_agent.cc	2011-12-15 21:17:34 +0000
@@ -19,40 +19,42 @@
  *  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 "squid.h"
 #include "cache_snmp.h"
 #include "Store.h"
 #include "mem_node.h"
+#include "StatCounters.h"
+#include "StatHist.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
 
 /************************************************************************
 
  SQUID MIB Implementation
 
  ************************************************************************/
 
 /*
  * cacheSystem group
  */
 
 variable_list *
 snmp_sysFn(variable_list * Var, snint * ErrP)
 {
     variable_list *Answer = NULL;
     MemBuf tmp;
     debugs(49, 5, "snmp_sysFn: Processing request:" << snmpDebugOid(Var->name, Var->name_length, tmp));
     *ErrP = SNMP_ERR_NOERROR;
@@ -555,77 +557,77 @@
         else
             break;
 
         if ((minutes < 1) || (minutes > 60))
             break;
 
         f = snmpStatGet(0);
 
         l = snmpStatGet(minutes);
 
         debugs(49, 8, "median: min= " << minutes << ", " << Var->name[LEN_SQ_PRF + 3] << " l= " << l << " , f = " << f);
         debugs(49, 8, "median: l= " << l << " , f = " << f);
 
         switch (Var->name[LEN_SQ_PRF + 3]) {
 
         case PERF_MEDIAN_TIME:
             x = minutes;
             break;
 
         case PERF_MEDIAN_HTTP_ALL:
-            x = statHistDeltaMedian(&l->client_http.all_svc_time,
-                                    &f->client_http.all_svc_time);
+            x = statHistDeltaMedian(l->client_http.allSvcTime,
+                                    f->client_http.allSvcTime);
             break;
 
         case PERF_MEDIAN_HTTP_MISS:
-            x = statHistDeltaMedian(&l->client_http.miss_svc_time,
-                                    &f->client_http.miss_svc_time);
+            x = statHistDeltaMedian(l->client_http.missSvcTime,
+                                    f->client_http.missSvcTime);
             break;
 
         case PERF_MEDIAN_HTTP_NM:
-            x = statHistDeltaMedian(&l->client_http.nm_svc_time,
-                                    &f->client_http.nm_svc_time);
+            x = statHistDeltaMedian(l->client_http.nearMissSvcTime,
+                                    f->client_http.nearMissSvcTime);
             break;
 
         case PERF_MEDIAN_HTTP_HIT:
-            x = statHistDeltaMedian(&l->client_http.hit_svc_time,
-                                    &f->client_http.hit_svc_time);
+            x = statHistDeltaMedian(l->client_http.hitSvcTime,
+                                    f->client_http.hitSvcTime);
             break;
 
         case PERF_MEDIAN_ICP_QUERY:
-            x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
+            x = statHistDeltaMedian(l->icp.querySvcTime, f->icp.querySvcTime);
             break;
 
         case PERF_MEDIAN_ICP_REPLY:
-            x = statHistDeltaMedian(&l->icp.reply_svc_time, &f->icp.reply_svc_time);
+            x = statHistDeltaMedian(l->icp.replySvcTime, f->icp.replySvcTime);
             break;
 
         case PERF_MEDIAN_DNS:
-            x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
+            x = statHistDeltaMedian(l->dns.svcTime, f->dns.svcTime);
             break;
 
         case PERF_MEDIAN_RHR:
             x = statRequestHitRatio(minutes);
             break;
 
         case PERF_MEDIAN_BHR:
             x = statByteHitRatio(minutes);
             break;
 
         case PERF_MEDIAN_HTTP_NH:
-            x = statHistDeltaMedian(&l->client_http.nh_svc_time,
-                                    &f->client_http.nh_svc_time);
+            x = statHistDeltaMedian(l->client_http.nearHitSvcTime,
+                                    f->client_http.nearHitSvcTime);
             break;
 
         default:
             *ErrP = SNMP_ERR_NOSUCHNAME;
             return NULL;
         }
 
         return snmp_var_new_integer(Var->name, Var->name_length,
                                     (snint) x,
                                     SMI_INTEGER);
     }
 
     *ErrP = SNMP_ERR_NOSUCHNAME;
     return NULL;
 }

=== modified file 'src/stat.cc'
--- src/stat.cc	2011-11-18 07:48:25 +0000
+++ src/stat.cc	2011-12-15 21:17:34 +0000
@@ -37,40 +37,41 @@
 #include "format/Token.h"
 #include "StoreClient.h"
 #if USE_AUTH
 #include "auth/UserRequest.h"
 #endif
 #include "comm/Connection.h"
 #include "mgr/Registration.h"
 #include "Store.h"
 #include "HttpRequest.h"
 #include "MemObject.h"
 #include "fde.h"
 #include "mem_node.h"
 #if USE_DELAY_POOLS
 #include "DelayId.h"
 #endif
 #include "client_side_request.h"
 #include "client_side.h"
 #include "MemBuf.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "mgr/CountersAction.h"
 #include "mgr/FunAction.h"
 #include "mgr/InfoAction.h"
 #include "mgr/IntervalAction.h"
 #include "mgr/IoAction.h"
 #include "mgr/ServiceTimesAction.h"
 #if USE_SSL
 #include "ssl/support.h"
 #endif
 
 /* these are included because they expose stats calls */
 /* TODO: provide a self registration mechanism for those classes
  * to use during static construction
  */
 #include "comm.h"
 #include "StoreSearch.h"
 
 #define DEBUG_OPENFD 1
 
 typedef int STOBJFLT(const StoreEntry *);
@@ -1073,101 +1074,101 @@
             hours = N_COUNT_HOUR_HIST - 1;
 
         l = &CountHourHist[hours];
     } else {
         debugs(18, 1, "statAvgDump: Invalid args, minutes=" << minutes << ", hours=" << hours);
         return;
     }
 
     dt = tvSubDsec(l->timestamp, f->timestamp);
     ct = f->cputime - l->cputime;
 
     stats.sample_start_time = l->timestamp;
     stats.sample_end_time = f->timestamp;
 
     stats.client_http_requests = XAVG(client_http.requests);
     stats.client_http_hits = XAVG(client_http.hits);
     stats.client_http_errors = XAVG(client_http.errors);
     stats.client_http_kbytes_in = XAVG(client_http.kbytes_in.kb);
     stats.client_http_kbytes_out = XAVG(client_http.kbytes_out.kb);
 
-    stats.client_http_all_median_svc_time = statHistDeltaMedian(&l->client_http.all_svc_time,
-                                            &f->client_http.all_svc_time) / 1000.0;
-    stats.client_http_miss_median_svc_time = statHistDeltaMedian(&l->client_http.miss_svc_time,
-            &f->client_http.miss_svc_time) / 1000.0;
-    stats.client_http_nm_median_svc_time = statHistDeltaMedian(&l->client_http.nm_svc_time,
-                                           &f->client_http.nm_svc_time) / 1000.0;
-    stats.client_http_nh_median_svc_time = statHistDeltaMedian(&l->client_http.nh_svc_time,
-                                           &f->client_http.nh_svc_time) / 1000.0;
-    stats.client_http_hit_median_svc_time = statHistDeltaMedian(&l->client_http.hit_svc_time,
-                                            &f->client_http.hit_svc_time) / 1000.0;
+    stats.client_http_all_median_svc_time = statHistDeltaMedian(l->client_http.allSvcTime,
+                                            f->client_http.allSvcTime) / 1000.0;
+    stats.client_http_miss_median_svc_time = statHistDeltaMedian(l->client_http.missSvcTime,
+            f->client_http.missSvcTime) / 1000.0;
+    stats.client_http_nm_median_svc_time = statHistDeltaMedian(l->client_http.nearMissSvcTime,
+                                           f->client_http.nearMissSvcTime) / 1000.0;
+    stats.client_http_nh_median_svc_time = statHistDeltaMedian(l->client_http.nearHitSvcTime,
+                                           f->client_http.nearHitSvcTime) / 1000.0;
+    stats.client_http_hit_median_svc_time = statHistDeltaMedian(l->client_http.hitSvcTime,
+                                            f->client_http.hitSvcTime) / 1000.0;
 
     stats.server_all_requests = XAVG(server.all.requests);
     stats.server_all_errors = XAVG(server.all.errors);
     stats.server_all_kbytes_in = XAVG(server.all.kbytes_in.kb);
     stats.server_all_kbytes_out = XAVG(server.all.kbytes_out.kb);
 
     stats.server_http_requests = XAVG(server.http.requests);
     stats.server_http_errors = XAVG(server.http.errors);
     stats.server_http_kbytes_in = XAVG(server.http.kbytes_in.kb);
     stats.server_http_kbytes_out = XAVG(server.http.kbytes_out.kb);
 
     stats.server_ftp_requests = XAVG(server.ftp.requests);
     stats.server_ftp_errors = XAVG(server.ftp.errors);
     stats.server_ftp_kbytes_in = XAVG(server.ftp.kbytes_in.kb);
     stats.server_ftp_kbytes_out = XAVG(server.ftp.kbytes_out.kb);
 
     stats.server_other_requests = XAVG(server.other.requests);
     stats.server_other_errors = XAVG(server.other.errors);
     stats.server_other_kbytes_in = XAVG(server.other.kbytes_in.kb);
     stats.server_other_kbytes_out = XAVG(server.other.kbytes_out.kb);
 
     stats.icp_pkts_sent = XAVG(icp.pkts_sent);
     stats.icp_pkts_recv = XAVG(icp.pkts_recv);
     stats.icp_queries_sent = XAVG(icp.queries_sent);
     stats.icp_replies_sent = XAVG(icp.replies_sent);
     stats.icp_queries_recv = XAVG(icp.queries_recv);
     stats.icp_replies_recv = XAVG(icp.replies_recv);
     stats.icp_replies_queued = XAVG(icp.replies_queued);
     stats.icp_query_timeouts = XAVG(icp.query_timeouts);
     stats.icp_kbytes_sent = XAVG(icp.kbytes_sent.kb);
     stats.icp_kbytes_recv = XAVG(icp.kbytes_recv.kb);
     stats.icp_q_kbytes_sent = XAVG(icp.q_kbytes_sent.kb);
     stats.icp_r_kbytes_sent = XAVG(icp.r_kbytes_sent.kb);
     stats.icp_q_kbytes_recv = XAVG(icp.q_kbytes_recv.kb);
     stats.icp_r_kbytes_recv = XAVG(icp.r_kbytes_recv.kb);
 
-    stats.icp_query_median_svc_time = statHistDeltaMedian(&l->icp.query_svc_time,
-                                      &f->icp.query_svc_time) / 1000000.0;
-    stats.icp_reply_median_svc_time = statHistDeltaMedian(&l->icp.reply_svc_time,
-                                      &f->icp.reply_svc_time) / 1000000.0;
-    stats.dns_median_svc_time = statHistDeltaMedian(&l->dns.svc_time,
-                                &f->dns.svc_time) / 1000.0;
+    stats.icp_query_median_svc_time = statHistDeltaMedian(l->icp.querySvcTime,
+                                      f->icp.querySvcTime) / 1000000.0;
+    stats.icp_reply_median_svc_time = statHistDeltaMedian(l->icp.replySvcTime,
+                                      f->icp.replySvcTime) / 1000000.0;
+    stats.dns_median_svc_time = statHistDeltaMedian(l->dns.svcTime,
+                                f->dns.svcTime) / 1000.0;
 
     stats.unlink_requests = XAVG(unlink.requests);
     stats.page_faults = XAVG(page_faults);
     stats.select_loops = XAVG(select_loops);
     stats.select_fds = XAVG(select_fds);
     stats.average_select_fd_period = f->select_fds > l->select_fds ?
                                      (f->select_time - l->select_time) / (f->select_fds - l->select_fds) : 0.0;
 
-    stats.median_select_fds = statHistDeltaMedian(&l->select_fds_hist, &f->select_fds_hist);
+    stats.median_select_fds = statHistDeltaMedian(l->select_fds_hist, f->select_fds_hist);
     stats.swap_outs = XAVG(swap.outs);
     stats.swap_ins = XAVG(swap.ins);
     stats.swap_files_cleaned = XAVG(swap.files_cleaned);
     stats.aborted_requests = XAVG(aborted_requests);
 
     stats.syscalls_disk_opens = XAVG(syscalls.disk.opens);
     stats.syscalls_disk_closes = XAVG(syscalls.disk.closes);
     stats.syscalls_disk_reads = XAVG(syscalls.disk.reads);
     stats.syscalls_disk_writes = XAVG(syscalls.disk.writes);
     stats.syscalls_disk_seeks = XAVG(syscalls.disk.seeks);
     stats.syscalls_disk_unlinks = XAVG(syscalls.disk.unlinks);
     stats.syscalls_sock_accepts = XAVG(syscalls.sock.accepts);
     stats.syscalls_sock_sockets = XAVG(syscalls.sock.sockets);
     stats.syscalls_sock_connects = XAVG(syscalls.sock.connects);
     stats.syscalls_sock_binds = XAVG(syscalls.sock.binds);
     stats.syscalls_sock_closes = XAVG(syscalls.sock.closes);
     stats.syscalls_sock_reads = XAVG(syscalls.sock.reads);
     stats.syscalls_sock_writes = XAVG(syscalls.sock.writes);
     stats.syscalls_sock_recvfroms = XAVG(syscalls.sock.recvfroms);
     stats.syscalls_sock_sendtos = XAVG(syscalls.sock.sendtos);
@@ -1468,131 +1469,131 @@
             debugs(18, 0, "WARNING: Memory usage at " << ((unsigned long int)(i >> 20)) << " MB");
     }
 }
 
 static void
 statCountersInit(StatCounters * C)
 {
     assert(C);
     memset(C, 0, sizeof(*C));
     C->timestamp = current_time;
     statCountersInitSpecial(C);
 }
 
 /* add special cases here as they arrive */
 static void
 statCountersInitSpecial(StatCounters * C)
 {
     /*
      * HTTP svc_time hist is kept in milli-seconds; max of 3 hours.
      */
-    statHistLogInit(&C->client_http.all_svc_time, 300, 0.0, 3600000.0 * 3.0);
-    statHistLogInit(&C->client_http.miss_svc_time, 300, 0.0, 3600000.0 * 3.0);
-    statHistLogInit(&C->client_http.nm_svc_time, 300, 0.0, 3600000.0 * 3.0);
-    statHistLogInit(&C->client_http.nh_svc_time, 300, 0.0, 3600000.0 * 3.0);
-    statHistLogInit(&C->client_http.hit_svc_time, 300, 0.0, 3600000.0 * 3.0);
+    C->client_http.allSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
+    C->client_http.missSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
+    C->client_http.nearMissSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
+    C->client_http.nearHitSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
+    C->client_http.hitSvcTime.logInit(300, 0.0, 3600000.0 * 3.0);
     /*
      * ICP svc_time hist is kept in micro-seconds; max of 1 minute.
      */
-    statHistLogInit(&C->icp.query_svc_time, 300, 0.0, 1000000.0 * 60.0);
-    statHistLogInit(&C->icp.reply_svc_time, 300, 0.0, 1000000.0 * 60.0);
+    C->icp.querySvcTime.logInit(300, 0.0, 1000000.0 * 60.0);
+    C->icp.replySvcTime.logInit(300, 0.0, 1000000.0 * 60.0);
     /*
      * DNS svc_time hist is kept in milli-seconds; max of 10 minutes.
      */
-    statHistLogInit(&C->dns.svc_time, 300, 0.0, 60000.0 * 10.0);
+    C->dns.svcTime.logInit(300, 0.0, 60000.0 * 10.0);
     /*
      * Cache Digest Stuff
      */
-    statHistEnumInit(&C->cd.on_xition_count, CacheDigestHashFuncCount);
-    statHistEnumInit(&C->comm_icp_incoming, INCOMING_ICP_MAX);
-    statHistEnumInit(&C->comm_dns_incoming, INCOMING_DNS_MAX);
-    statHistEnumInit(&C->comm_http_incoming, INCOMING_HTTP_MAX);
-    statHistIntInit(&C->select_fds_hist, 256);	/* was SQUID_MAXFD, but it is way too much. It is OK to crop this statistics */
+    C->cd.on_xition_count.enumInit(CacheDigestHashFuncCount);
+    C->comm_icp_incoming.enumInit(INCOMING_ICP_MAX);
+    C->comm_dns_incoming.enumInit(INCOMING_DNS_MAX);
+    C->comm_http_incoming.enumInit(INCOMING_HTTP_MAX);
+    C->select_fds_hist.enumInit(256);	/* was SQUID_MAXFD, but it is way too much. It is OK to crop this statistics */
 }
 
 /* add special cases here as they arrive */
 static void
 statCountersClean(StatCounters * C)
 {
     assert(C);
-    statHistClean(&C->client_http.all_svc_time);
-    statHistClean(&C->client_http.miss_svc_time);
-    statHistClean(&C->client_http.nm_svc_time);
-    statHistClean(&C->client_http.nh_svc_time);
-    statHistClean(&C->client_http.hit_svc_time);
-    statHistClean(&C->icp.query_svc_time);
-    statHistClean(&C->icp.reply_svc_time);
-    statHistClean(&C->dns.svc_time);
-    statHistClean(&C->cd.on_xition_count);
-    statHistClean(&C->comm_icp_incoming);
-    statHistClean(&C->comm_dns_incoming);
-    statHistClean(&C->comm_http_incoming);
-    statHistClean(&C->select_fds_hist);
+    C->client_http.allSvcTime.clear();
+    C->client_http.missSvcTime.clear();
+    C->client_http.nearMissSvcTime.clear();
+    C->client_http.nearHitSvcTime.clear();
+    C->client_http.hitSvcTime.clear();
+    C->icp.querySvcTime.clear();
+    C->icp.replySvcTime.clear();
+    C->dns.svcTime.clear();
+    C->cd.on_xition_count.clear();
+    C->comm_icp_incoming.clear();
+    C->comm_dns_incoming.clear();
+    C->comm_http_incoming.clear();
+    C->select_fds_hist.clear();
 }
 
 /* add special cases here as they arrive */
 static void
 statCountersCopy(StatCounters * dest, const StatCounters * orig)
 {
     assert(dest && orig);
     /* this should take care of all the fields, but "special" ones */
     memcpy(dest, orig, sizeof(*dest));
     /* prepare space where to copy special entries */
     statCountersInitSpecial(dest);
     /* now handle special cases */
     /* note: we assert that histogram capacities do not change */
-    statHistCopy(&dest->client_http.all_svc_time, &orig->client_http.all_svc_time);
-    statHistCopy(&dest->client_http.miss_svc_time, &orig->client_http.miss_svc_time);
-    statHistCopy(&dest->client_http.nm_svc_time, &orig->client_http.nm_svc_time);
-    statHistCopy(&dest->client_http.nh_svc_time, &orig->client_http.nh_svc_time);
-    statHistCopy(&dest->client_http.hit_svc_time, &orig->client_http.hit_svc_time);
-    statHistCopy(&dest->icp.query_svc_time, &orig->icp.query_svc_time);
-    statHistCopy(&dest->icp.reply_svc_time, &orig->icp.reply_svc_time);
-    statHistCopy(&dest->dns.svc_time, &orig->dns.svc_time);
-    statHistCopy(&dest->cd.on_xition_count, &orig->cd.on_xition_count);
-    statHistCopy(&dest->comm_icp_incoming, &orig->comm_icp_incoming);
-    statHistCopy(&dest->comm_http_incoming, &orig->comm_http_incoming);
-    statHistCopy(&dest->select_fds_hist, &orig->select_fds_hist);
+    dest->client_http.allSvcTime=orig->client_http.allSvcTime;
+    dest->client_http.missSvcTime=orig->client_http.missSvcTime;
+    dest->client_http.nearMissSvcTime=orig->client_http.nearMissSvcTime;
+    dest->client_http.nearHitSvcTime=orig->client_http.nearHitSvcTime;
+
+    dest->client_http.hitSvcTime=orig->client_http.hitSvcTime;
+    dest->icp.querySvcTime=orig->icp.querySvcTime;
+    dest->icp.replySvcTime=orig->icp.replySvcTime;
+    dest->dns.svcTime=orig->dns.svcTime;
+    dest->cd.on_xition_count=orig->cd.on_xition_count;
+    dest->comm_icp_incoming=orig->comm_icp_incoming;
+    dest->comm_http_incoming=orig->comm_http_incoming;
+    dest->select_fds_hist=orig->select_fds_hist;
 }
 
 static void
 statCountersHistograms(StoreEntry * sentry)
 {
-    StatCounters *f = &statCounter;
-    storeAppendPrintf(sentry, "client_http.all_svc_time histogram:\n");
-    statHistDump(&f->client_http.all_svc_time, sentry, NULL);
-    storeAppendPrintf(sentry, "client_http.miss_svc_time histogram:\n");
-    statHistDump(&f->client_http.miss_svc_time, sentry, NULL);
-    storeAppendPrintf(sentry, "client_http.nm_svc_time histogram:\n");
-    statHistDump(&f->client_http.nm_svc_time, sentry, NULL);
-    storeAppendPrintf(sentry, "client_http.nh_svc_time histogram:\n");
-    statHistDump(&f->client_http.nh_svc_time, sentry, NULL);
-    storeAppendPrintf(sentry, "client_http.hit_svc_time histogram:\n");
-    statHistDump(&f->client_http.hit_svc_time, sentry, NULL);
-    storeAppendPrintf(sentry, "icp.query_svc_time histogram:\n");
-    statHistDump(&f->icp.query_svc_time, sentry, NULL);
-    storeAppendPrintf(sentry, "icp.reply_svc_time histogram:\n");
-    statHistDump(&f->icp.reply_svc_time, sentry, NULL);
+    storeAppendPrintf(sentry, "client_http.allSvcTime histogram:\n");
+    statCounter.client_http.allSvcTime.dump(sentry, NULL);
+    storeAppendPrintf(sentry, "client_http.missSvcTime histogram:\n");
+    statCounter.client_http.missSvcTime.dump(sentry, NULL);
+    storeAppendPrintf(sentry, "client_http.nearMissSvcTime histogram:\n");
+    statCounter.client_http.nearMissSvcTime.dump(sentry, NULL);
+    storeAppendPrintf(sentry, "client_http.nearHitSvcTime histogram:\n");
+    statCounter.client_http.nearHitSvcTime.dump(sentry, NULL);
+    storeAppendPrintf(sentry, "client_http.hitSvcTime histogram:\n");
+    statCounter.client_http.hitSvcTime.dump(sentry, NULL);
+    storeAppendPrintf(sentry, "icp.querySvcTime histogram:\n");
+    statCounter.icp.querySvcTime.dump(sentry, NULL);
+    storeAppendPrintf(sentry, "icp.replySvcTime histogram:\n");
+    statCounter.icp.replySvcTime.dump(sentry, NULL);
     storeAppendPrintf(sentry, "dns.svc_time histogram:\n");
-    statHistDump(&f->dns.svc_time, sentry, NULL);
+    statCounter.dns.svcTime.dump(sentry, NULL);
     storeAppendPrintf(sentry, "select_fds_hist histogram:\n");
-    statHistDump(&f->select_fds_hist, sentry, NULL);
+    statCounter.select_fds_hist.dump(sentry, NULL);
 }
 
 static void
 statCountersDump(StoreEntry * sentry)
 {
     Mgr::CountersActionData stats;
     GetCountersStats(stats);
     DumpCountersStats(stats, sentry);
 }
 
 void
 GetCountersStats(Mgr::CountersActionData& stats)
 {
     StatCounters *f = &statCounter;
 
     struct rusage rusage;
     squid_getrusage(&rusage);
     f->page_faults = rusage_pagefaults(&rusage);
     f->cputime = rusage_cputime(&rusage);
 
@@ -1854,65 +1855,65 @@
 {
     StatCounters *f;
     StatCounters *l;
     double x;
     assert(interval > 0);
 
     if (interval > N_COUNT_HIST - 1)
         interval = N_COUNT_HIST - 1;
 
     f = &CountHist[0];
 
     l = &CountHist[interval];
 
     assert(f);
 
     assert(l);
 
     switch (which) {
 
     case PCTILE_HTTP:
-        x = statHistDeltaPctile(&l->client_http.all_svc_time, &f->client_http.all_svc_time, pctile);
+        x = statHistDeltaPctile(l->client_http.allSvcTime,f->client_http.allSvcTime, pctile);
         break;
 
     case PCTILE_HIT:
-        x = statHistDeltaPctile(&l->client_http.hit_svc_time, &f->client_http.hit_svc_time, pctile);
+        x = statHistDeltaPctile(l->client_http.hitSvcTime,f->client_http.hitSvcTime, pctile);
         break;
 
     case PCTILE_MISS:
-        x = statHistDeltaPctile(&l->client_http.miss_svc_time, &f->client_http.miss_svc_time, pctile);
+        x = statHistDeltaPctile(l->client_http.missSvcTime,f->client_http.missSvcTime, pctile);
         break;
 
     case PCTILE_NM:
-        x = statHistDeltaPctile(&l->client_http.nm_svc_time, &f->client_http.nm_svc_time, pctile);
+        x = statHistDeltaPctile(l->client_http.nearMissSvcTime,f->client_http.nearMissSvcTime, pctile);
         break;
 
     case PCTILE_NH:
-        x = statHistDeltaPctile(&l->client_http.nh_svc_time, &f->client_http.nh_svc_time, pctile);
+        x = statHistDeltaPctile(l->client_http.nearHitSvcTime,f->client_http.nearHitSvcTime, pctile);
         break;
 
     case PCTILE_ICP_QUERY:
-        x = statHistDeltaPctile(&l->icp.query_svc_time, &f->icp.query_svc_time, pctile);
+        x = statHistDeltaPctile(l->icp.querySvcTime,f->icp.querySvcTime, pctile);
         break;
 
     case PCTILE_DNS:
-        x = statHistDeltaPctile(&l->dns.svc_time, &f->dns.svc_time, pctile);
+        x = statHistDeltaPctile(l->dns.svcTime,f->dns.svcTime, pctile);
         break;
 
     default:
         debugs(49, 5, "statPctileSvc: unknown type.");
         x = 0;
     }
 
     return x;
 }
 
 StatCounters *
 snmpStatGet(int minutes)
 {
     return &CountHist[minutes];
 }
 
 int
 stat5minClientRequests(void)
 {
     assert(N_COUNT_HIST > 5);

=== modified file 'src/store.cc'
--- src/store.cc	2011-12-04 13:52:07 +0000
+++ src/store.cc	2011-12-10 15:30:20 +0000
@@ -30,40 +30,41 @@
  *  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 "squid.h"
 #include "CacheManager.h"
 #include "comm/Connection.h"
 #include "ETag.h"
 #include "event.h"
 #include "fde.h"
 #include "Store.h"
 #include "mgr/Registration.h"
 #include "StoreClient.h"
 #include "stmem.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "MemObject.h"
 #include "mem_node.h"
+#include "StatCounters.h"
 #include "StoreMeta.h"
 #include "SwapDir.h"
 #include "StoreIOState.h"
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
 #include "Stack.h"
 #include "SquidTime.h"
 #include "swap_log_op.h"
 #include "mgr/StoreIoAction.h"
 
 static STMCB storeWriteComplete;
 
 #define REBUILD_TIMESTAMP_DELTA_MAX 2
 
 #define STORE_IN_MEM_BUCKETS            (229)
 
 
 /** \todo Convert these string constants to enum string-arrays generated */
 

=== modified file 'src/store_client.cc'
--- src/store_client.cc	2011-11-18 16:53:45 +0000
+++ src/store_client.cc	2011-12-10 15:30:19 +0000
@@ -23,40 +23,41 @@
  *  (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.
  *
  * Portions copyright (c) 2003 Robert Collins <robertc@squid-cache.org>
  */
 
 #include "squid.h"
 #include "event.h"
 #include "StoreClient.h"
 #include "Store.h"
 #include "HttpReply.h"
 #include "MemObject.h"
+#include "StatCounters.h"
 #include "StoreMeta.h"
 #include "StoreMetaUnpacker.h"
 #if USE_DELAY_POOLS
 #include "DelayPools.h"
 #endif
 #include "HttpRequest.h"
 #include "MemBuf.h"
 
 /*
  * NOTE: 'Header' refers to the swapfile metadata header.
  * 	 'OBJHeader' refers to the object header, with cannonical
  *	 processed object headers (which may derive from FTP/HTTP etc
  *	 upstream protocols
  *       'Body' refers to the swapfile body, which is the full
  *        HTTP reply (including HTTP headers and body).
  */
 static StoreIOState::STRCB storeClientReadBody;
 static StoreIOState::STRCB storeClientReadHeader;
 static void storeClientCopy2(StoreEntry * e, store_client * sc);
 static EVH storeClientCopyEvent;

=== modified file 'src/store_rebuild.cc'
--- src/store_rebuild.cc	2011-09-06 22:32:30 +0000
+++ src/store_rebuild.cc	2011-12-10 15:30:19 +0000
@@ -18,40 +18,41 @@
  *  sources; 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 "squid.h"
 #include "event.h"
+#include "StatCounters.h"
 #include "Store.h"
 #include "SwapDir.h"
 #include "StoreSearch.h"
 #include "SquidTime.h"
 
 static struct _store_rebuild_data counts;
 
 static struct timeval rebuild_start;
 static void storeCleanup(void *);
 
 typedef struct {
     /* total number of "swap.state" entries that will be read */
     int total;
     /* number of entries read so far */
     int scanned;
 } store_rebuild_progress;
 
 static store_rebuild_progress *RebuildProgress = NULL;
 
 static int

=== modified file 'src/store_swapin.cc'
--- src/store_swapin.cc	2011-02-04 22:18:41 +0000
+++ src/store_swapin.cc	2011-12-10 15:30:19 +0000
@@ -17,40 +17,41 @@
  *  incorporates software developed and/or copyrighted by other
  *  sources; 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 "squid.h"
+#include "StatCounters.h"
 #include "StoreClient.h"
 #include "Store.h"
 
 static StoreIOState::STIOCB storeSwapInFileClosed;
 static StoreIOState::STFNCB storeSwapInFileNotify;
 
 void
 storeSwapInStart(store_client * sc)
 {
     StoreEntry *e = sc->entry;
 
     if (!EBIT_TEST(e->flags, ENTRY_VALIDATED)) {
         /* We're still reloading and haven't validated this entry yet */
         return;
     }
 
     if (e->mem_status != NOT_IN_MEMORY)
         debugs(20, 3, HERE << "already IN_MEMORY");
 
     debugs(20, 3, "storeSwapInStart: called for : " << e->swap_dirn << " " <<
@@ -67,37 +68,37 @@
         return;
     }
 
     assert(e->mem_obj != NULL);
     debugs(20, 3, "storeSwapInStart: Opening fileno " << std::hex << std::setw(8) << std::setfill('0') << std::uppercase << e->swap_filen);
     sc->swapin_sio = storeOpen(e, storeSwapInFileNotify, storeSwapInFileClosed, sc);
 }
 
 static void
 storeSwapInFileClosed(void *data, int errflag, StoreIOState::Pointer self)
 {
     store_client *sc = (store_client *)data;
     debugs(20, 3, "storeSwapInFileClosed: sio=" << sc->swapin_sio.getRaw() << ", errflag=" << errflag);
     sc->swapin_sio = NULL;
 
     if (sc->_callback.pending()) {
         assert (errflag <= 0);
         sc->callback(0, errflag ? true : false);
     }
 
-    statCounter.swap.ins++;
+    ++statCounter.swap.ins;
 }
 
 static void
 storeSwapInFileNotify(void *data, int errflag, StoreIOState::Pointer self)
 {
     store_client *sc = (store_client *)data;
     StoreEntry *e = sc->entry;
 
     debugs(1, 3, "storeSwapInFileNotify: changing " << e->swap_filen << "/" <<
            e->swap_dirn << " to " << sc->swapin_sio->swap_filen << "/" <<
            sc->swapin_sio->swap_dirn);
 
     assert(e->swap_filen < 0); // if this fails, call SwapDir::disconnect(e)
     e->swap_filen = sc->swapin_sio->swap_filen;
     e->swap_dirn = sc->swapin_sio->swap_dirn;
 }

=== modified file 'src/store_swapout.cc'
--- src/store_swapout.cc	2011-09-06 22:32:30 +0000
+++ src/store_swapout.cc	2011-12-10 15:30:20 +0000
@@ -24,40 +24,41 @@
  *
  *  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 "squid.h"
 #include "cbdata.h"
 #include "StoreClient.h"
 #include "Store.h"
 /* FIXME: Abstract the use of this more */
 #include "mem_node.h"
 #include "MemObject.h"
 #include "SwapDir.h"
+#include "StatCounters.h"
 #include "swap_log_op.h"
 
 static void storeSwapOutStart(StoreEntry * e);
 static StoreIOState::STIOCB storeSwapOutFileClosed;
 static StoreIOState::STFNCB storeSwapOutFileNotify;
 
 // wrapper to cross C/C++ ABI boundary. xfree is extern "C" for libraries.
 static void xfree_cppwrapper(void *x)
 {
     xfree(x);
 }
 
 /* start swapping object to disk */
 static void
 storeSwapOutStart(StoreEntry * e)
 {
     MemObject *mem = e->mem_obj;
     StoreIOState::Pointer sio;
     assert(mem);
     /* Build the swap metadata, so the filesystem will know how much
@@ -348,41 +349,41 @@
         /* swapping complete */
         debugs(20, 3, "storeSwapOutFileClosed: SwapOut complete: '" << e->url() << "' to " <<
                e->swap_dirn  << ", " << std::hex << std::setw(8) << std::setfill('0') <<
                std::uppercase << e->swap_filen);
         debugs(20, 5, HERE << "swap_file_sz = " <<
                e->objectLen() << " + " << mem->swap_hdr_sz);
 
         e->swap_file_sz = e->objectLen() + mem->swap_hdr_sz;
         e->swap_status = SWAPOUT_DONE;
         e->store()->swappedOut(*e);
 
         // XXX: For some Stores, it is pointless to re-check cachability here
         // and it leads to double counts in store_check_cachable_hist. We need
         // another way to signal a completed but failed swapout. Or, better,
         // each Store should handle its own logging and LOG state setting.
         if (e->checkCachable()) {
             storeLog(STORE_LOG_SWAPOUT, e);
             storeDirSwapLog(e, SWAP_LOG_ADD);
         }
 
-        statCounter.swap.outs++;
+        ++statCounter.swap.outs;
     }
 
     debugs(20, 3, "storeSwapOutFileClosed: " << __FILE__ << ":" << __LINE__);
     mem->swapout.sio = NULL;
     e->unlock();
 }
 
 /*
  * Is this entry a candidate for writing to disk?
  */
 bool
 StoreEntry::swapOutAble() const
 {
     dlink_node *node;
 
     if (mem_obj->swapout.sio != NULL)
         return true;
 
     if (mem_obj->inmem_lo > 0)
         return false;

=== modified file 'src/structs.h'
--- src/structs.h	2011-12-08 21:58:09 +0000
+++ src/structs.h	2011-12-13 17:33:34 +0000
@@ -740,55 +740,40 @@
     unsigned int request_sent:1;
     unsigned int do_next_read:1;
     unsigned int consume_body_data:1;
     unsigned int chunked:1; ///< reading a chunked response; TODO: rename
     unsigned int chunked_request:1; ///< writing a chunked request
     unsigned int sentLastChunk:1; ///< do not try to write last-chunk again
 };
 
 struct _domain_ping {
     char *domain;
     int do_ping;		/* boolean */
     domain_ping *next;
 };
 
 struct _domain_type {
     char *domain;
     peer_t type;
     domain_type *next;
 };
 
-#if USE_CACHE_DIGESTS
-
-/* statistics for cache digests and other hit "predictors" */
-
-struct _cd_guess_stats {
-    /* public, read-only */
-    int true_hits;
-    int false_hits;
-    int true_misses;
-    int false_misses;
-    int close_hits;		/* tmp, remove it later */
-};
-
-#endif
-
 class PeerDigest;
 
 struct peer {
     u_int index;
     char *name;
     char *host;
     peer_t type;
 
     Ip::Address in_addr;
 
     struct {
         int pings_sent;
         int pings_acked;
         int fetches;
         int rtt;
         int ignored_replies;
         int n_keepalives_sent;
         int n_keepalives_recv;
         time_t probe_start;
         time_t last_query;
@@ -1067,205 +1052,40 @@
 
     struct {
         unsigned int icase:1;
         unsigned int refresh_ims:1;
         unsigned int store_stale:1;
 #if USE_HTTP_VIOLATIONS
         unsigned int override_expire:1;
         unsigned int override_lastmod:1;
         unsigned int reload_into_ims:1;
         unsigned int ignore_reload:1;
         unsigned int ignore_no_cache:1;
         unsigned int ignore_no_store:1;
         unsigned int ignore_must_revalidate:1;
         unsigned int ignore_private:1;
         unsigned int ignore_auth:1;
 #endif
     } flags;
     int max_stale;
 };
 
-/*
- * "very generic" histogram;
- * see important comments on hbase_f restrictions in StatHist.c
- */
-
-struct _StatHist {
-    int *bins;
-    int capacity;
-    double min;
-    double max;
-    double scale;
-    hbase_f *val_in;		/* e.g., log() for log-based histogram */
-    hbase_f *val_out;		/* e.g., exp() for log based histogram */
-};
-
-/*
- * if you add a field to StatCounters,
- * you MUST sync statCountersInitSpecial, statCountersClean, and statCountersCopy
- */
-
-struct _StatCounters {
-
-    struct {
-        int clients;
-        int requests;
-        int hits;
-        int mem_hits;
-        int disk_hits;
-        int errors;
-        kb_t kbytes_in;
-        kb_t kbytes_out;
-        kb_t hit_kbytes_out;
-        StatHist miss_svc_time;
-        StatHist nm_svc_time;
-        StatHist nh_svc_time;
-        StatHist hit_svc_time;
-        StatHist all_svc_time;
-    } client_http;
-
-    struct {
-
-        struct {
-            int requests;
-            int errors;
-            kb_t kbytes_in;
-            kb_t kbytes_out;
-        } all , http, ftp, other;
-    } server;
-
-    struct {
-        int pkts_sent;
-        int queries_sent;
-        int replies_sent;
-        int pkts_recv;
-        int queries_recv;
-        int replies_recv;
-        int hits_sent;
-        int hits_recv;
-        int replies_queued;
-        int replies_dropped;
-        kb_t kbytes_sent;
-        kb_t q_kbytes_sent;
-        kb_t r_kbytes_sent;
-        kb_t kbytes_recv;
-        kb_t q_kbytes_recv;
-        kb_t r_kbytes_recv;
-        StatHist query_svc_time;
-        StatHist reply_svc_time;
-        int query_timeouts;
-        int times_used;
-    } icp;
-
-    struct {
-        int pkts_sent;
-        int pkts_recv;
-    } htcp;
-
-    struct {
-        int requests;
-    } unlink;
-
-    struct {
-        StatHist svc_time;
-    } dns;
-
-    struct {
-        int times_used;
-        kb_t kbytes_sent;
-        kb_t kbytes_recv;
-        kb_t memory;
-        int msgs_sent;
-        int msgs_recv;
-#if USE_CACHE_DIGESTS
-
-        cd_guess_stats guess;
-#endif
-
-        StatHist on_xition_count;
-    } cd;
-
-    struct {
-        int times_used;
-    } netdb;
-    int page_faults;
-    unsigned long int select_loops;
-    int select_fds;
-    double select_time;
-    double cputime;
-
-    struct timeval timestamp;
-    StatHist comm_icp_incoming;
-    StatHist comm_dns_incoming;
-    StatHist comm_http_incoming;
-    StatHist select_fds_hist;
-
-    struct {
-        struct {
-            int opens;
-            int closes;
-            int reads;
-            int writes;
-            int seeks;
-            int unlinks;
-        } disk;
-
-        struct {
-            int accepts;
-            int sockets;
-            int connects;
-            int binds;
-            int closes;
-            int reads;
-            int writes;
-            int recvfroms;
-            int sendtos;
-        } sock;
-        int selects;
-    } syscalls;
-    int aborted_requests;
-
-    struct {
-        int files_cleaned;
-        int outs;
-        int ins;
-    } swap;
-};
-
-/* per header statistics */
-
-struct _HttpHeaderStat {
-    const char *label;
-    HttpHeaderMask *owner_mask;
-
-    StatHist hdrUCountDistr;
-    StatHist fieldTypeDistr;
-    StatHist ccTypeDistr;
-    StatHist scTypeDistr;
-
-    int parsedCount;
-    int ccParsedCount;
-    int scParsedCount;
-    int destroyedCount;
-    int busyDestroyedCount;
-};
-
 
 struct _CacheDigest {
     /* public, read-only */
     char *mask;			/* bit mask */
     int mask_size;		/* mask size in bytes */
     int capacity;		/* expected maximum for .count, not a hard limit */
     int bits_per_entry;		/* number of bits allocated for each entry from capacity */
     int count;			/* number of digested entries */
     int del_count;		/* number of deletions performed so far */
 };
 
 
 struct _store_rebuild_data {
     int objcount;		/* # objects successfully reloaded */
     int expcount;		/* # objects expired */
     int scancount;		/* # entries scanned or read from state file */
     int clashcount;		/* # swapfile clashes avoided */
     int dupcount;		/* # duplicates purged */
     int cancelcount;		/* # SWAP_LOG_DEL objects purged */
     int invalid;		/* # bad lines */

=== modified file 'src/tests/stub_StatHist.cc'
--- src/tests/stub_StatHist.cc	2009-07-26 09:24:07 +0000
+++ src/tests/stub_StatHist.cc	2011-12-15 07:00:14 +0000
@@ -1,22 +1,24 @@
-#include "squid.h"
+#include "config.h"
+#include "STUB.h"
+#include "StatHist.h"
 
-// for StatHist definitions
-#include "protos.h"
+#define STUB_API "StatHist.cc"
 
 void
-statHistDump(const StatHist * H, StoreEntry * sentry, StatHistBinDumper * bd)
-{
-    fatal("statHistDump: Not implemented");
-}
+StatHist::init(int capacity_, hbase_f * val_in_, hbase_f * val_out_, double min_, double max_)
+{}
+
+StatHist::~StatHist()
+{}
+
+void
+StatHist::enumInit(int last_enum)
+{}
 
 void
-statHistCount(StatHist * H, double val)
-{
-    fatal("statHistCount: Not implemented");
-}
+StatHist::count(double val)
+{}
 
 void
-statHistEnumInit(StatHist * H, int last_enum)
-{
-//NO-OP    fatal("statHistEnumInit: Not implemented");
-}
+StatHist::dump(StoreEntry * sentry, StatHistBinDumper * bd) const
+{}

=== modified file 'src/tunnel.cc'
--- src/tunnel.cc	2011-11-28 01:39:47 +0000
+++ src/tunnel.cc	2011-12-10 15:30:20 +0000
@@ -34,40 +34,41 @@
  */
 
 #include "squid.h"
 #include "errorpage.h"
 #include "HttpRequest.h"
 #include "fde.h"
 #include "Array.h"
 #include "comm.h"
 #include "comm/Connection.h"
 #include "comm/ConnOpener.h"
 #include "comm/Write.h"
 #include "client_side_request.h"
 #include "acl/FilledChecklist.h"
 #if USE_DELAY_POOLS
 #include "DelayId.h"
 #endif
 #include "client_side.h"
 #include "MemBuf.h"
 #include "http.h"
 #include "PeerSelectState.h"
+#include "StatCounters.h"
 
 class TunnelStateData
 {
 
 public:
 
     class Connection;
     void *operator new(size_t);
     void operator delete (void *);
     static void ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
     static void ReadServer(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data);
     static void WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
     static void WriteServerDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data);
 
     bool noConnections() const;
     char *url;
     HttpRequest *request;
     Comm::ConnectionList serverDestinations;
 
     const char * getHost() const {
@@ -232,42 +233,42 @@
     debugs(26, 3, HERE << c);
 
     tunnelState->readServer(buf, len, errcode, xerrno);
 }
 
 void
 TunnelStateData::readServer(char *buf, size_t len, comm_err_t errcode, int xerrno)
 {
     debugs(26, 3, HERE << server.conn << ", read " << len << " bytes, err=" << errcode);
 
     /*
      * Bail out early on COMM_ERR_CLOSING
      * - close handlers will tidy up for us
      */
 
     if (errcode == COMM_ERR_CLOSING)
         return;
 
     if (len > 0) {
         server.bytesIn(len);
-        kb_incr(&statCounter.server.all.kbytes_in, len);
-        kb_incr(&statCounter.server.other.kbytes_in, len);
+        kb_incr(&(statCounter.server.all.kbytes_in), len);
+        kb_incr(&(statCounter.server.other.kbytes_in), len);
     }
 
     copy (len, errcode, xerrno, server, client, WriteClientDone);
 }
 
 void
 TunnelStateData::Connection::error(int const xerrno)
 {
     /* XXX fixme xstrerror and xerrno... */
     errno = xerrno;
 
     debugs(50, debugLevelForError(xerrno), HERE << conn << ": read/write failure: " << xstrerror());
 
     if (!ignoreErrno(xerrno))
         conn->close();
 }
 
 /* Read from client side and queue it for writing to the server */
 void
 TunnelStateData::ReadClient(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t errcode, int xerrno, void *data)
@@ -276,41 +277,41 @@
     assert (cbdataReferenceValid (tunnelState));
 
     tunnelState->readClient(buf, len, errcode, xerrno);
 }
 
 void
 TunnelStateData::readClient(char *buf, size_t len, comm_err_t errcode, int xerrno)
 {
     debugs(26, 3, HERE << client.conn << ", read " << len << " bytes, err=" << errcode);
 
     /*
      * Bail out early on COMM_ERR_CLOSING
      * - close handlers will tidy up for us
      */
 
     if (errcode == COMM_ERR_CLOSING)
         return;
 
     if (len > 0) {
         client.bytesIn(len);
-        kb_incr(&statCounter.client_http.kbytes_in, len);
+        kb_incr(&(statCounter.client_http.kbytes_in), len);
     }
 
     copy (len, errcode, xerrno, client, server, WriteServerDone);
 }
 
 void
 TunnelStateData::copy (size_t len, comm_err_t errcode, int xerrno, Connection &from, Connection &to, IOCB *completion)
 {
     debugs(26, 3, HERE << "from={" << from.conn << "}, to={" << to.conn << "}");
 
     /* I think this is to prevent free-while-in-a-callback behaviour
      * - RBC 20030229
      * from.conn->close() / to.conn->close() done here trigger close callbacks which may free TunnelStateData
      */
     cbdataInternalLock(this);	/* ??? should be locked by the caller... */
 
     /* Bump the source connection read timeout on any activity */
     if (Comm::IsConnOpen(from.conn)) {
         AsyncCall::Pointer timeoutCall = commCbCall(5, 4, "tunnelTimeout",
                                          CommTimeoutCbPtrFun(tunnelTimeout, this));
@@ -352,42 +353,42 @@
 {
     debugs(26, 3, HERE  << server.conn << ", " << len << " bytes written, flag=" << flag);
 
     /* Error? */
     if (flag != COMM_OK) {
         if (flag != COMM_ERR_CLOSING) {
             debugs(26, 4, HERE << "calling TunnelStateData::server.error(" << xerrno <<")");
             server.error(xerrno); // may call comm_close
         }
         return;
     }
 
     /* EOF? */
     if (len == 0) {
         debugs(26, 4, HERE << "No read input. Closing server connection.");
         server.conn->close();
         return;
     }
 
     /* Valid data */
-    kb_incr(&statCounter.server.all.kbytes_out, len);
-    kb_incr(&statCounter.server.other.kbytes_out, len);
+    kb_incr(&(statCounter.server.all.kbytes_out), len);
+    kb_incr(&(statCounter.server.other.kbytes_out), len);
     client.dataSent(len);
 
     /* If the other end has closed, so should we */
     if (!Comm::IsConnOpen(client.conn)) {
         debugs(26, 4, HERE << "Client gone away. Shutting down server connection.");
         server.conn->close();
         return;
     }
 
     cbdataInternalLock(this);	/* ??? should be locked by the caller... */
 
     if (cbdataReferenceValid(this))
         copyRead(client, ReadClient);
 
     cbdataInternalUnlock(this);	/* ??? */
 }
 
 /* Writes data from the server buffer to the client side */
 void
 TunnelStateData::WriteClientDone(const Comm::ConnectionPointer &, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
@@ -415,41 +416,41 @@
 {
     debugs(26, 3, HERE << client.conn << ", " << len << " bytes written, flag=" << flag);
 
     /* Error? */
     if (flag != COMM_OK) {
         if (flag != COMM_ERR_CLOSING) {
             debugs(26, 4, HERE << "Closing client connection due to comm flags.");
             client.error(xerrno); // may call comm_close
         }
         return;
     }
 
     /* EOF? */
     if (len == 0) {
         debugs(26, 4, HERE << "Closing client connection due to 0 byte read.");
         client.conn->close();
         return;
     }
 
     /* Valid data */
-    kb_incr(&statCounter.client_http.kbytes_out, len);
+    kb_incr(&(statCounter.client_http.kbytes_out), len);
     server.dataSent(len);
 
     /* If the other end has closed, so should we */
     if (!Comm::IsConnOpen(server.conn)) {
         debugs(26, 4, HERE << "Server has gone away. Terminating client connection.");
         client.conn->close();
         return;
     }
 
     cbdataInternalLock(this);	/* ??? should be locked by the caller... */
 
     if (cbdataReferenceValid(this))
         copyRead(server, ReadServer);
 
     cbdataInternalUnlock(this);	/* ??? */
 }
 
 static void
 tunnelTimeout(const CommTimeoutCbParams &io)
 {

=== modified file 'src/typedefs.h'
--- src/typedefs.h	2011-12-07 18:56:59 +0000
+++ src/typedefs.h	2011-12-15 22:48:06 +0000
@@ -41,76 +41,68 @@
 
 typedef uint32_t nfmark_t;
 typedef unsigned char tos_t;
 
 typedef struct {
     size_t bytes;
     size_t kb;
 } kb_t;
 
 struct http_port_list;
 struct https_port_list;
 
 typedef struct _close_handler close_handler;
 
 typedef struct _dread_ctrl dread_ctrl;
 
 typedef struct _dwrite_q dwrite_q;
 
 typedef struct _HttpHeaderFieldAttrs HttpHeaderFieldAttrs;
 
-typedef struct _HttpHeaderStat HttpHeaderStat;
-
 typedef struct _domain_ping domain_ping;
 
 typedef struct _domain_type domain_type;
 
 typedef struct _DigestFetchState DigestFetchState;
 
 typedef struct _net_db_name net_db_name;
 
 typedef struct _net_db_peer net_db_peer;
 
 typedef struct _netdbEntry netdbEntry;
 
 typedef struct _icp_common_t icp_common_t;
 
 typedef struct _iostats iostats;
 
 typedef struct _http_state_flags http_state_flags;
 
 typedef struct _header_mangler header_mangler;
 
 typedef struct _cachemgr_passwd cachemgr_passwd;
 
 typedef struct _refresh_t refresh_t;
 
 typedef struct _CommWriteStateData CommWriteStateData;
 
-typedef struct _StatCounters StatCounters;
-
 typedef struct _storeSwapLogData storeSwapLogData;
 
-typedef struct _StatHist StatHist;
-
-typedef struct _cd_guess_stats cd_guess_stats;
-
 typedef struct _CacheDigest CacheDigest;
 
 typedef struct _Version Version;
 
 typedef struct _link_list link_list;
 
 typedef struct _customlog customlog;
 
 #if SQUID_SNMP
 typedef variable_list *(oid_ParseFn) (variable_list *, snint *);
 
 typedef struct _snmp_request_t snmp_request_t;
 #endif
 
 typedef void FREE(void *);
 typedef void CBDUNL(void *);
 typedef void FOCB(void *, int fd, int errcode);
 typedef void PF(int, void *);
 
 /* disk.c / diskd.c callback typedefs */
@@ -133,34 +125,31 @@
 /* in wordlist.h */
 
 class wordlist;
 typedef void UH(void *data, wordlist *);
 typedef int READ_HANDLER(int, char *, int);
 typedef int WRITE_HANDLER(int, const char *, int);
 
 typedef int QS(const void *, const void *);	/* qsort */
 typedef void STABH(void *);
 typedef void ERCB(int fd, void *, size_t);
 class StoreEntry;
 typedef void OBJH(StoreEntry *);
 typedef void SIGHDLR(int sig);
 typedef void STVLDCB(void *, int, int);
 typedef void HLPCB(void *, char *buf);
 typedef int HLPSAVAIL(void *);
 typedef void HLPSONEQ(void *);
 typedef void HLPCMDOPTS(int *argc, char **argv);
 typedef void IDNSCB(void *, rfc1035_rr *, int, const char *);
 
-typedef double hbase_f(double);
-typedef void StatHistBinDumper(StoreEntry *, int idx, double val, double size, int count);
-
 /* MD5 cache keys */
 typedef unsigned char cache_key;
 
 /* in case we want to change it later */
 typedef ssize_t mb_size_t;
 
 typedef int STDIRSELECT(const StoreEntry *);
 
 /*Use uint64_t to store miliseconds*/
 typedef uint64_t time_msec_t;
 #endif /* SQUID_TYPEDEFS_H */

=== modified file 'src/unlinkd.cc'
--- src/unlinkd.cc	2011-11-26 12:12:26 +0000
+++ src/unlinkd.cc	2011-12-10 15:30:21 +0000
@@ -18,40 +18,41 @@
  *  sources; 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 "squid.h"
 #include "SquidTime.h"
+#include "StatCounters.h"
 #include "SwapDir.h"
 #include "fde.h"
 #include "xusleep.h"
 
 /* This code gets linked to Squid */
 
 static int unlinkd_wfd = -1;
 static int unlinkd_rfd = -1;
 
 static void * hIpc;
 static pid_t pid;
 
 #define UNLINKD_QUEUE_LIMIT 20
 
 void
 unlinkdUnlink(const char *path)
 {
     char buf[MAXPATHLEN];
     int l;
     int bytes_written;
@@ -114,47 +115,47 @@
             assert(queuelen >= 0);
         }
     }
 
     l = strlen(path);
     assert(l < MAXPATHLEN);
     xstrncpy(buf, path, MAXPATHLEN);
     buf[l++] = '\n';
     bytes_written = write(unlinkd_wfd, buf, l);
 
     if (bytes_written < 0) {
         debugs(2, 1, "unlinkdUnlink: write FD " << unlinkd_wfd << " failed: " << xstrerror());
         safeunlink(path, 0);
         return;
     } else if (bytes_written != l) {
         debugs(2, 1, "unlinkdUnlink: FD " << unlinkd_wfd << " only wrote " << bytes_written << " of " << l << " bytes");
         safeunlink(path, 0);
         return;
     }
 
-    statCounter.unlink.requests++;
+    ++statCounter.unlink.requests;
     /*
     * Increment this syscalls counter here, even though the syscall
     * is executed by the helper process.  We try to be consistent
     * in counting unlink operations.
     */
-    statCounter.syscalls.disk.unlinks++;
+    ++statCounter.syscalls.disk.unlinks;
     queuelen++;
 }
 
 void
 unlinkdClose(void)
 #if _SQUID_MSWIN_
 {
 
     if (unlinkd_wfd > -1) {
         debugs(2, 1, "Closing unlinkd pipe on FD " << unlinkd_wfd);
         shutdown(unlinkd_wfd, SD_BOTH);
         comm_close(unlinkd_wfd);
 
         if (unlinkd_wfd != unlinkd_rfd)
             comm_close(unlinkd_rfd);
 
         unlinkd_wfd = -1;
 
         unlinkd_rfd = -1;
     }

=== modified file 'src/whois.cc'
--- src/whois.cc	2011-11-27 12:37:35 +0000
+++ src/whois.cc	2011-12-10 15:30:21 +0000
@@ -25,40 +25,41 @@
  *  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 "squid.h"
 #include "comm/Write.h"
 #include "errorpage.h"
 #include "Store.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "comm.h"
 #include "HttpRequest.h"
 #include "forward.h"
+#include "StatCounters.h"
 
 #define WHOIS_PORT 43
 
 class WhoisState
 {
 
 public:
     ~WhoisState();
     void readReply(const Comm::ConnectionPointer &, char *aBuffer, size_t aBufferLength, comm_err_t flag, int xerrno);
     void setReplyToOK(StoreEntry *sentry);
     StoreEntry *entry;
     HttpRequest *request;
     FwdState::Pointer fwd;
     char buf[BUFSIZ+1];		/* readReply adds terminating NULL */
     bool dataWritten;
 };
 
 static CLCB whoisClose;
 static CTCB whoisTimeout;
 static IOCB whoisReadReply;
@@ -152,42 +153,42 @@
     if (flag != COMM_OK) {
         debugs(50, 2, HERE  << conn << ": read failure: " << xstrerror() << ".");
 
         if (ignoreErrno(errno)) {
             AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply",
                                                  CommIoCbPtrFun(whoisReadReply, this));
             comm_read(conn, aBuffer, BUFSIZ, call);
         } else {
             ErrorState *err = new ErrorState(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, fwd->request);
             err->xerrno = errno;
             fwd->fail(err);
             conn->close();
         }
         return;
     }
 
     if (aBufferLength > 0) {
         if (!dataWritten)
             setReplyToOK(entry);
 
-        kb_incr(&statCounter.server.all.kbytes_in, aBufferLength);
-        kb_incr(&statCounter.server.http.kbytes_in, aBufferLength);
+        kb_incr(&(statCounter.server.all.kbytes_in), aBufferLength);
+        kb_incr(&(statCounter.server.http.kbytes_in), aBufferLength);
 
         /* No range support, we always grab it all */
         dataWritten = true;
         entry->append(aBuffer, aBufferLength);
         entry->flush();
 
         AsyncCall::Pointer call = commCbCall(5,4, "whoisReadReply",
                                              CommIoCbPtrFun(whoisReadReply, this));
         comm_read(conn, aBuffer, BUFSIZ, call);
         return;
     }
 
     /* no bytes read. stop reading */
     entry->timestampsSet();
     entry->flush();
 
     if (!EBIT_TEST(entry->flags, RELEASE_REQUEST))
         entry->setPublicKey();
 
     fwd->complete();

