[squid-dev] [PATCH] convert CacheDigest to C++ and MEMPROXY

Amos Jeffries squid3 at treenet.co.nz
Fri Nov 6 18:19:50 UTC 2015


Convert the gobal C-style functions that operate on class CacheDigest to
class methods in C++ style.

This is largely a symbol renaming change. But there are two relatively
small logic changes:

1) convert the class to MEMPROXY_CLASS.

Which alters the pool creation timing from general memory pool
initialization time, to whenever the CacheDigest object is first used.

A nice side effect is removal the macro conditional within the old pool
type enumeration. Macros like that in enumeration lists such as this one
have been causing some builds to have run-time errors accessing memory
arrays out-of-bounds or incorrect postions when the build-time
dependency detection issues caused build objects to link with different
./configure'd versions.


2) Constructor logic sequence alteration.

The old *Create function used to set some members then call the *Init
function which would re-set some of them, and initialize most of the
rest (but not all).
The old *UpdateCap function would call a helper that emulated
safe_free(mask) then *Init to alter the objects mask related members
whether they needed it or not.

The class constructor now initializes all members via initialization
list then calls updateCapacity(), which calls a simplified init(). This
altered sequence contains the same operational acts while the new order
avoids repeated or unnecesarily setting members on create and update.


Amos
-------------- next part --------------
=== modified file 'src/CacheDigest.cc'
--- src/CacheDigest.cc	2015-01-13 07:25:36 +0000
+++ src/CacheDigest.cc	2015-11-06 10:06:29 +0000
@@ -17,219 +17,202 @@
 #if USE_CACHE_DIGESTS
 
 #include "CacheDigest.h"
 #include "util.h"
 
 /* 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
-cacheDigestInit(CacheDigest * cd, int capacity, int bpe)
+void
+CacheDigest::init(int newCapacity)
 {
-    const size_t mask_size = cacheDigestCalcMaskSize(capacity, bpe);
-    assert(cd);
-    assert(capacity > 0 && bpe > 0);
-    assert(mask_size > 0);
-    cd->capacity = capacity;
-    cd->bits_per_entry = bpe;
-    cd->mask_size = mask_size;
-    cd->mask = (char *)xcalloc(cd->mask_size, 1);
-    debugs(70, 2, "cacheDigestInit: capacity: " << cd->capacity << " entries, bpe: " << cd->bits_per_entry << "; size: "
-           << cd->mask_size << " bytes");
-}
-
-CacheDigest *
-cacheDigestCreate(int capacity, int bpe)
+    const auto newMaskSz = CacheDigest::CalcMaskSize(newCapacity, bits_per_entry);
+    assert(newCapacity > 0 && bits_per_entry > 0);
+    assert(newMaskSz > 0);
+    capacity = newCapacity;
+    mask_size = newMaskSz;
+    mask = static_cast<char *>(xcalloc(mask_size,1));
+    debugs(70, 2, "capacity: " << capacity << " entries, bpe: " << bits_per_entry << "; size: "
+           << mask_size << " bytes");
+}
+
+CacheDigest::CacheDigest(int aCapacity, int bpe) :
+        mask(nullptr),
+        mask_size(0),
+        capacity(0),
+        bits_per_entry(bpe),
+        count(0),
+        del_count(0)
 {
-    CacheDigest *cd = (CacheDigest *)memAllocate(MEM_CACHE_DIGEST);
     assert(SQUID_MD5_DIGEST_LENGTH == 16);  /* our hash functions rely on 16 byte keys */
-    cacheDigestInit(cd, capacity, bpe);
-    return cd;
+    updateCapacity(aCapacity);
 }
 
-static void
-cacheDigestClean(CacheDigest * cd)
+CacheDigest::~CacheDigest()
 {
-    assert(cd);
-    xfree(cd->mask);
-    cd->mask = NULL;
-}
-
-void
-cacheDigestDestroy(CacheDigest * cd)
-{
-    assert(cd);
-    cacheDigestClean(cd);
-    memFree(cd, MEM_CACHE_DIGEST);
+    xfree(mask);
 }
 
 CacheDigest *
-cacheDigestClone(const CacheDigest * cd)
+CacheDigest::clone() const
 {
-    CacheDigest *clone;
-    assert(cd);
-    clone = cacheDigestCreate(cd->capacity, cd->bits_per_entry);
-    clone->count = cd->count;
-    clone->del_count = cd->del_count;
-    assert(cd->mask_size == clone->mask_size);
-    memcpy(clone->mask, cd->mask, cd->mask_size);
-    return clone;
+    CacheDigest *cl = new CacheDigest(capacity, bits_per_entry);
+    cl->count = count;
+    cl->del_count = del_count;
+    assert(mask_size == cl->mask_size);
+    memcpy(cl->mask, mask, mask_size);
+    return cl;
 }
 
 void
-cacheDigestClear(CacheDigest * cd)
+CacheDigest::clear()
 {
-    assert(cd);
-    cd->count = cd->del_count = 0;
-    memset(cd->mask, 0, cd->mask_size);
+    count = del_count = 0;
+    memset(mask, 0, mask_size);
 }
 
-/* changes mask size, resets bits to 0, preserves "cd" pointer */
 void
-cacheDigestChangeCap(CacheDigest * cd, int new_cap)
+CacheDigest::updateCapacity(int newCapacity)
 {
-    assert(cd);
-    cacheDigestClean(cd);
-    cacheDigestInit(cd, new_cap, cd->bits_per_entry);
+    safe_free(mask);
+    init(newCapacity); // will re-init mask and mask_size
 }
 
-/* returns true if the key belongs to the digest */
-int
-cacheDigestTest(const CacheDigest * cd, const cache_key * key)
+bool
+CacheDigest::test(const cache_key * key) const
 {
-    assert(cd && key);
+    assert(key);
     /* hash */
-    cacheDigestHashKey(cd, key);
+    cacheDigestHashKey(this, key);
     /* test corresponding bits */
     return
-        CBIT_TEST(cd->mask, hashed_keys[0]) &&
-        CBIT_TEST(cd->mask, hashed_keys[1]) &&
-        CBIT_TEST(cd->mask, hashed_keys[2]) &&
-        CBIT_TEST(cd->mask, hashed_keys[3]);
+        CBIT_TEST(mask, hashed_keys[0]) &&
+        CBIT_TEST(mask, hashed_keys[1]) &&
+        CBIT_TEST(mask, hashed_keys[2]) &&
+        CBIT_TEST(mask, hashed_keys[3]);
 }
 
 void
-cacheDigestAdd(CacheDigest * cd, const cache_key * key)
+CacheDigest::add(const cache_key * key)
 {
-    assert(cd && key);
+    assert(key);
     /* hash */
-    cacheDigestHashKey(cd, key);
+    cacheDigestHashKey(this, key);
     /* turn on corresponding bits */
 #if CD_FAST_ADD
 
-    CBIT_SET(cd->mask, hashed_keys[0]);
-    CBIT_SET(cd->mask, hashed_keys[1]);
-    CBIT_SET(cd->mask, hashed_keys[2]);
-    CBIT_SET(cd->mask, hashed_keys[3]);
+    CBIT_SET(mask, hashed_keys[0]);
+    CBIT_SET(mask, hashed_keys[1]);
+    CBIT_SET(mask, hashed_keys[2]);
+    CBIT_SET(mask, hashed_keys[3]);
 #else
 
     {
         int on_xition_cnt = 0;
 
-        if (!CBIT_TEST(cd->mask, hashed_keys[0])) {
-            CBIT_SET(cd->mask, hashed_keys[0]);
+        if (!CBIT_TEST(mask, hashed_keys[0])) {
+            CBIT_SET(mask, hashed_keys[0]);
             ++on_xition_cnt;
         }
 
-        if (!CBIT_TEST(cd->mask, hashed_keys[1])) {
-            CBIT_SET(cd->mask, hashed_keys[1]);
+        if (!CBIT_TEST(mask, hashed_keys[1])) {
+            CBIT_SET(mask, hashed_keys[1]);
             ++on_xition_cnt;
         }
 
-        if (!CBIT_TEST(cd->mask, hashed_keys[2])) {
-            CBIT_SET(cd->mask, hashed_keys[2]);
+        if (!CBIT_TEST(mask, hashed_keys[2])) {
+            CBIT_SET(mask, hashed_keys[2]);
             ++on_xition_cnt;
         }
 
-        if (!CBIT_TEST(cd->mask, hashed_keys[3])) {
-            CBIT_SET(cd->mask, hashed_keys[3]);
+        if (!CBIT_TEST(mask, hashed_keys[3])) {
+            CBIT_SET(mask, hashed_keys[3]);
             ++on_xition_cnt;
         }
 
         statCounter.cd.on_xition_count.count(on_xition_cnt);
     }
 #endif
-    ++ cd->count;
+    ++count;
 }
 
 void
-cacheDigestDel(CacheDigest * cd, const cache_key * key)
+CacheDigest::remove(const cache_key * key)
 {
-    assert(cd && key);
-    ++ cd->del_count;
+    assert(key);
+    ++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;
     int seq_count = 0;
     int cur_seq_len = 0;
     int cur_seq_type = 1;
     assert(stats);
     memset(stats, 0, sizeof(*stats));
 
     while (pos-- > 0) {
         const int is_on = 0 != CBIT_TEST(cd->mask, pos);
 
         if (is_on)
             ++on_count;
 
         if (is_on != cur_seq_type || !pos) {
             seq_len_sum += cur_seq_len;
             ++seq_count;
             cur_seq_type = is_on;
             cur_seq_len = 0;
         }
 
         ++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)
+double
+CacheDigest::usedMaskPercent() const
 {
     CacheDigestStats stats;
-    assert(cd);
-    cacheDigestStats(cd, &stats);
-    return xpercentInt(stats.bit_on_count, stats.bit_count);
+    cacheDigestStats(this, &stats);
+    return xpercent(stats.bit_on_count, stats.bit_count);
 }
 
 void
 cacheDigestGuessStatsUpdate(CacheDigestGuessStats * stats, int real_hit, int guess_hit)
 {
     assert(stats);
 
     if (real_hit) {
         if (guess_hit)
             ++stats->trueHits;
         else
             ++stats->falseMisses;
     } else {
         if (guess_hit)
             ++stats->falseHits;
         else
             ++stats->trueMisses;
     }
 }
 
@@ -281,42 +264,43 @@
     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",
                       cd->bits_per_entry,
                       stats.bit_on_count, stats.bit_count,
                       xpercentInt(stats.bit_on_count, stats.bit_count)
                      );
     storeAppendPrintf(e, "\t bit-seq: count: %d avg.len: %.2f\n",
                       stats.bseq_count,
                       xdiv(stats.bseq_len_sum, stats.bseq_count)
                      );
 }
 
 size_t
-cacheDigestCalcMaskSize(int cap, int bpe)
+CacheDigest::CalcMaskSize(int cap, int bpe)
 {
+    // XXX: might 32-bit overflow during multiply
     return (size_t) (cap * bpe + 7) / 8;
 }
 
 static void
 cacheDigestHashKey(const CacheDigest * cd, const cache_key * key)
 {
     const unsigned int bit_count = cd->mask_size * 8;
     unsigned int tmp_keys[4];
     /* we must memcpy to ensure alignment */
     memcpy(tmp_keys, key, sizeof(tmp_keys));
     hashed_keys[0] = htonl(tmp_keys[0]) % bit_count;
     hashed_keys[1] = htonl(tmp_keys[1]) % bit_count;
     hashed_keys[2] = htonl(tmp_keys[2]) % bit_count;
     hashed_keys[3] = htonl(tmp_keys[3]) % bit_count;
     debugs(70, 9, "cacheDigestHashKey: " << storeKeyText(key) << " -(" <<
            bit_count << ")-> " << hashed_keys[0] << " " << hashed_keys[1] <<
            " " << hashed_keys[2] << " " << hashed_keys[3]);
 }
 
 #endif

=== modified file 'src/CacheDigest.h'
--- src/CacheDigest.h	2015-08-31 06:17:22 +0000
+++ src/CacheDigest.h	2015-11-06 09:12:28 +0000
@@ -1,47 +1,68 @@
 /*
  * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 /* DEBUG: section 70    Cache Digest */
 
 #ifndef SQUID_CACHEDIGEST_H_
 #define SQUID_CACHEDIGEST_H_
 
+#include "mem/forward.h"
 #include "store_key_md5.h"
 
 class CacheDigestGuessStats;
 class StoreEntry;
 
-// currently a POD
 class CacheDigest
 {
+    MEMPROXY_CLASS(CacheDigest);
+public:
+    CacheDigest(int capacity, int bpe);
+    ~CacheDigest();
+
+    // NP: only used by broken unit-test
+    /// produce a new identical copy of the digest object
+    CacheDigest *clone() const;
+
+    /// reset the digest mask and counters
+    void clear();
+
+    /// changes mask size to fit newCapacity, resets bits to 0
+    void updateCapacity(int newCapacity);
+
+    void add(const cache_key * key);
+    void remove(const cache_key * key);
+
+    /// \returns true if the key belongs to the digest
+    bool test(const cache_key * key) const;
+
+    /// percentage of mask bits which are used
+    double usedMaskPercent() const;
+
+    /// calculate the size of mask required to digest up to
+    /// a specified capacity and bitsize.
+    static size_t CalcMaskSize(int cap, int bpe);
+
+private:
+    void init(int newCapacity);
+
 public:
     /* 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 */
 };
 
-CacheDigest *cacheDigestCreate(int capacity, int bpe);
-void cacheDigestDestroy(CacheDigest * cd);
-CacheDigest *cacheDigestClone(const CacheDigest * cd);
-void cacheDigestClear(CacheDigest * cd);
-void cacheDigestChangeCap(CacheDigest * cd, int new_cap);
-int cacheDigestTest(const CacheDigest * cd, const cache_key * key);
-void cacheDigestAdd(CacheDigest * cd, const cache_key * key);
-void cacheDigestDel(CacheDigest * cd, const cache_key * key);
-size_t cacheDigestCalcMaskSize(int cap, int bpe);
-int cacheDigestBitUtil(const CacheDigest * cd);
 void cacheDigestGuessStatsUpdate(CacheDigestGuessStats * stats, int real_hit, int guess_hit);
 void cacheDigestGuessStatsReport(const CacheDigestGuessStats * stats, StoreEntry * sentry, const char *label);
 void cacheDigestReport(CacheDigest * cd, const char *label, StoreEntry * e);
 
 #endif /* SQUID_CACHEDIGEST_H_ */
 

=== modified file 'src/mem/forward.h'
--- src/mem/forward.h	2015-08-31 08:01:10 +0000
+++ src/mem/forward.h	2015-11-05 11:59:44 +0000
@@ -29,43 +29,40 @@
 void Report(std::ostream &);
 void PoolReport(const MemPoolStats * mp_st, const MemPoolMeter * AllMeter, std::ostream &);
 };
 
 extern const size_t squidSystemPageSize;
 
 /// \deprecated use MEMPROXY_CLASS instead.
 typedef void FREE(void *);
 
 /// Types of memory pool which do not yet use MEMPROXY_CLASS() API
 typedef enum {
     MEM_NONE,
     MEM_2K_BUF,
     MEM_4K_BUF,
     MEM_8K_BUF,
     MEM_16K_BUF,
     MEM_32K_BUF,
     MEM_64K_BUF,
     MEM_ACL_DENY_INFO_LIST,
     MEM_ACL_NAME_LIST,
-#if USE_CACHE_DIGESTS
-    MEM_CACHE_DIGEST,
-#endif
     MEM_CLIENT_INFO,
     MEM_LINK_LIST,
     MEM_DLINK_NODE,
     MEM_DREAD_CTRL,
     MEM_DWRITE_Q,
     MEM_HTTP_HDR_CONTENT_RANGE,
     MEM_MD5_DIGEST,
     MEM_NETDBENTRY,
     MEM_NET_DB_NAME,
     // IMPORTANT: leave this here. pools above are initialized early with memInit()
     MEM_DONTFREE,
     // following pools are initialized late by their component if needed (or never)
     MEM_FQDNCACHE_ENTRY,
     MEM_FWD_SERVER,
     MEM_IDNS_QUERY,
     MEM_IPCACHE_ENTRY,
     MEM_MAX
 } mem_type;
 
 void memClean(void);

=== modified file 'src/mem/old_api.cc'
--- src/mem/old_api.cc	2015-08-31 09:38:51 +0000
+++ src/mem/old_api.cc	2015-11-05 13:27:09 +0000
@@ -1,35 +1,34 @@
 /*
  * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 /* DEBUG: section 13    High Level Memory Pool Management */
 
 #include "squid.h"
 #include "acl/AclDenyInfoList.h"
 #include "acl/AclNameList.h"
 #include "base/PackableStream.h"
-#include "CacheDigest.h"
 #include "ClientInfo.h"
 #include "disk.h"
 #include "dlink.h"
 #include "event.h"
 #include "icmp/net_db.h"
 #include "md5.h"
 #include "mem/forward.h"
 #include "mem/Meter.h"
 #include "mem/Pool.h"
 #include "MemBuf.h"
 #include "mgr/Registration.h"
 #include "SquidConfig.h"
 #include "SquidList.h"
 #include "SquidTime.h"
 #include "Store.h"
 
 #include <iomanip>
 
 /* forward declarations */
 static void memFree2K(void *);
@@ -411,45 +410,40 @@
     memset(MemPools, '\0', sizeof(MemPools));
     /**
      * Then initialize all pools.
      * \par
      * Starting with generic 2kB - 64kB buffr pools, then specific object types.
      * \par
      * It does not hurt much to have a lot of pools since sizeof(MemPool) is
      * small; someday we will figure out what to do with all the entries here
      * that are never used or used only once; perhaps we should simply use
      * malloc() for those? @?@
      */
     memDataInit(MEM_2K_BUF, "2K Buffer", 2048, 10, false);
     memDataInit(MEM_4K_BUF, "4K Buffer", 4096, 10, false);
     memDataInit(MEM_8K_BUF, "8K Buffer", 8192, 10, false);
     memDataInit(MEM_16K_BUF, "16K Buffer", 16384, 10, false);
     memDataInit(MEM_32K_BUF, "32K Buffer", 32768, 10, false);
     memDataInit(MEM_64K_BUF, "64K Buffer", 65536, 10, false);
     memDataInit(MEM_ACL_DENY_INFO_LIST, "AclDenyInfoList",
                 sizeof(AclDenyInfoList), 0);
     memDataInit(MEM_ACL_NAME_LIST, "acl_name_list", sizeof(AclNameList), 0);
-#if USE_CACHE_DIGESTS
-
-    memDataInit(MEM_CACHE_DIGEST, "CacheDigest", sizeof(CacheDigest), 0);
-#endif
-
     memDataInit(MEM_LINK_LIST, "link_list", sizeof(link_list), 10);
     memDataInit(MEM_DLINK_NODE, "dlink_node", sizeof(dlink_node), 10);
     memDataInit(MEM_DREAD_CTRL, "dread_ctrl", sizeof(dread_ctrl), 0);
     memDataInit(MEM_DWRITE_Q, "dwrite_q", sizeof(dwrite_q), 0);
     memDataInit(MEM_HTTP_HDR_CONTENT_RANGE, "HttpHdrContRange", sizeof(HttpHdrContRange), 0);
     memDataInit(MEM_NETDBENTRY, "netdbEntry", sizeof(netdbEntry), 0);
     memDataInit(MEM_NET_DB_NAME, "net_db_name", sizeof(net_db_name), 0);
     memDataInit(MEM_CLIENT_INFO, "ClientInfo", sizeof(ClientInfo), 0);
     memDataInit(MEM_MD5_DIGEST, "MD5 digest", SQUID_MD5_DIGEST_LENGTH, 0);
     MemPools[MEM_MD5_DIGEST]->setChunkSize(512 * 1024);
 
     /** Lastly init the string pools. */
     for (i = 0; i < mem_str_pool_count; ++i) {
         StrPools[i].pool = memPoolCreate(StrPoolsAttrs[i].name, StrPoolsAttrs[i].obj_size);
         StrPools[i].pool->zeroBlocks(false);
 
         if (StrPools[i].pool->objectSize() != StrPoolsAttrs[i].obj_size)
             debugs(13, DBG_IMPORTANT, "Notice: " << StrPoolsAttrs[i].name << " is " << StrPools[i].pool->objectSize() << " bytes instead of requested " << StrPoolsAttrs[i].obj_size << " bytes");
     }
 

=== modified file 'src/neighbors.cc'
--- src/neighbors.cc	2015-09-05 11:28:21 +0000
+++ src/neighbors.cc	2015-11-05 17:12:38 +0000
@@ -745,41 +745,41 @@
 
     if (!p->digest) {
         debugs(15, 5, "peerDigestLookup: gone!");
         return LOOKUP_NONE;
     } else if (!peerHTTPOkay(p, request)) {
         debugs(15, 5, "peerDigestLookup: !peerHTTPOkay");
         return LOOKUP_NONE;
     } else if (!p->digest->flags.needed) {
         debugs(15, 5, "peerDigestLookup: note need");
         peerDigestNeeded(p->digest);
         return LOOKUP_NONE;
     } else if (!p->digest->flags.usable) {
         debugs(15, 5, "peerDigestLookup: !ready && " << (p->digest->flags.requested ? "" : "!") << "requested");
         return LOOKUP_NONE;
     }
 
     debugs(15, 5, "peerDigestLookup: OK to lookup peer " << p->host);
     assert(p->digest->cd);
     /* does digest predict a hit? */
 
-    if (!cacheDigestTest(p->digest->cd, key))
+    if (!p->digest->cd->test(key))
         return LOOKUP_MISS;
 
     debugs(15, 5, "peerDigestLookup: peer " << p->host << " says HIT!");
 
     return LOOKUP_HIT;
 
 #endif
 
     return LOOKUP_NONE;
 }
 
 /* select best CachePeer based on cache digests */
 CachePeer *
 neighborsDigestSelect(HttpRequest * request)
 {
     CachePeer *best_p = NULL;
 #if USE_CACHE_DIGESTS
 
     int best_rtt = 0;
     int choice_count = 0;

=== modified file 'src/peer_digest.cc'
--- src/peer_digest.cc	2015-10-26 02:53:30 +0000
+++ src/peer_digest.cc	2015-11-06 08:58:47 +0000
@@ -18,41 +18,40 @@
 #include "HttpReply.h"
 #include "HttpRequest.h"
 #include "internal.h"
 #include "MemObject.h"
 #include "mime_header.h"
 #include "neighbors.h"
 #include "PeerDigest.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "store_key_md5.h"
 #include "StoreClient.h"
 #include "tools.h"
 #include "util.h"
 
 /* local types */
 
 /* local prototypes */
 static time_t peerDigestIncDelay(const PeerDigest * pd);
 static time_t peerDigestNewDelay(const StoreEntry * e);
 static void peerDigestSetCheck(PeerDigest * pd, time_t delay);
-static void peerDigestClean(PeerDigest *);
 static EVH peerDigestCheck;
 static void peerDigestRequest(PeerDigest * pd);
 static STCB peerDigestHandleReply;
 static int peerDigestFetchReply(void *, char *, ssize_t);
 int peerDigestSwapInHeaders(void *, char *, ssize_t);
 int peerDigestSwapInCBlock(void *, char *, ssize_t);
 int peerDigestSwapInMask(void *, char *, ssize_t);
 static int peerDigestFetchedEnough(DigestFetchState * fetch, char *buf, ssize_t size, const char *step_name);
 static void peerDigestFetchStop(DigestFetchState * fetch, char *buf, const char *reason);
 static void peerDigestFetchAbort(DigestFetchState * fetch, char *buf, const char *reason);
 static void peerDigestReqFinish(DigestFetchState * fetch, char *buf, int, int, int, const char *reason, int err);
 static void peerDigestPDFinish(DigestFetchState * fetch, int pcb_valid, int err);
 static void peerDigestFetchFinish(DigestFetchState * fetch, int err);
 static void peerDigestFetchSetStats(DigestFetchState * fetch);
 static int peerDigestSetCBlock(PeerDigest * pd, const char *buf);
 static int peerDigestUseful(const PeerDigest * pd);
 
 /* local constants */
 Version const CacheDigestVer = { 5, 3 };
 
@@ -69,51 +68,40 @@
 
 /* initialize peer digest */
 static void
 peerDigestInit(PeerDigest * pd, CachePeer * p)
 {
     assert(pd && p);
 
     memset(pd, 0, sizeof(*pd));
     /*
      * DPW 2007-04-12
      * Lock on to the peer here.  The corresponding cbdataReferenceDone()
      * is in peerDigestDestroy().
      */
     pd->peer = cbdataReference(p);
     /* if peer disappears, we will know it's name */
     pd->host = p->host;
 
     pd->times.initialized = squid_curtime;
 }
 
-static void
-peerDigestClean(PeerDigest * pd)
-{
-    assert(pd);
-
-    if (pd->cd)
-        cacheDigestDestroy(pd->cd);
-
-    pd->host.clean();
-}
-
 CBDATA_CLASS_INIT(PeerDigest);
 
 CBDATA_CLASS_INIT(DigestFetchState);
 
 DigestFetchState::DigestFetchState(PeerDigest *aPd, HttpRequest *req) :
     pd(cbdataReference(aPd)),
     entry(NULL),
     old_entry(NULL),
     sc(NULL),
     old_sc(NULL),
     request(req),
     offset(0),
     mask_offset(0),
     start_time(squid_curtime),
     resp_time(0),
     expires(0),
     bufofs(0),
     state(DIGEST_READ_REPLY)
 {
     HTTPMSGLOCK(request);
@@ -154,73 +142,72 @@
     return cbdataReference(pd);
 }
 
 /* call Clean and free/unlock everything */
 static void
 peerDigestDestroy(PeerDigest * pd)
 {
     void *p;
     assert(pd);
     void * peerTmp = pd->peer;
 
     /*
      * DPW 2007-04-12
      * We locked the peer in peerDigestInit(), this is
      * where we unlock it.  If the peer is still valid,
      * tell it that the digest is gone.
      */
     if (cbdataReferenceValidDone(peerTmp, &p))
         peerNoteDigestGone((CachePeer *)p);
 
-    peerDigestClean(pd);
+    delete pd->cd;
+    pd->host.clean();
 
     delete pd;
 }
 
 /* called by peer to indicate that somebody actually needs this digest */
 void
 peerDigestNeeded(PeerDigest * pd)
 {
     assert(pd);
     assert(!pd->flags.needed);
     assert(!pd->cd);
 
     pd->flags.needed = true;
     pd->times.needed = squid_curtime;
     peerDigestSetCheck(pd, 0);  /* check asap */
 }
 
 /* currently we do not have a reason to disable without destroying */
 #if FUTURE_CODE
 /* disables peer for good */
 static void
 peerDigestDisable(PeerDigest * pd)
 {
     debugs(72, 2, "peerDigestDisable: peer " << pd->host.buf() << " disabled for good");
     pd->times.disabled = squid_curtime;
     pd->times.next_check = -1;  /* never */
     pd->flags.usable = 0;
 
-    if (pd->cd) {
-        cacheDigestDestroy(pd->cd);
-        pd->cd = NULL;
-    }
+    delete pd->cd
+    pd->cd = nullptr;
 
     /* we do not destroy the pd itself to preserve its "history" and stats */
 }
 
 #endif
 
 /* increment retry delay [after an unsuccessful attempt] */
 static time_t
 peerDigestIncDelay(const PeerDigest * pd)
 {
     assert(pd);
     return pd->times.retry_delay > 0 ?
            2 * pd->times.retry_delay :  /* exponential backoff */
            PeerDigestReqMinGap; /* minimal delay */
 }
 
 /* artificially increases Expires: setting to avoid race conditions
  * returns the delay till that [increased] expiration time */
 static time_t
 peerDigestNewDelay(const StoreEntry * e)
@@ -844,44 +831,42 @@
 }
 
 /* destroys digest if peer disappeared
  * must be called only when fetch and pd cbdata are valid */
 static void
 peerDigestPDFinish(DigestFetchState * fetch, int pcb_valid, int err)
 {
     PeerDigest *pd = fetch->pd;
     const char *host = pd->host.termedBuf();
 
     pd->times.received = squid_curtime;
     pd->times.req_delay = fetch->resp_time;
     pd->stats.sent.kbytes += fetch->sent.bytes;
     pd->stats.recv.kbytes += fetch->recv.bytes;
     pd->stats.sent.msgs += fetch->sent.msg;
     pd->stats.recv.msgs += fetch->recv.msg;
 
     if (err) {
         debugs(72, DBG_IMPORTANT, "" << (pcb_valid ? "temporary " : "" ) << "disabling (" << pd->req_result << ") digest from " << host);
 
-        if (pd->cd) {
-            cacheDigestDestroy(pd->cd);
-            pd->cd = NULL;
-        }
+        delete pd->cd;
+        pd->cd = nullptr;
 
         pd->flags.usable = false;
 
         if (!pcb_valid)
             peerDigestNotePeerGone(pd);
     } else {
         assert(pcb_valid);
 
         pd->flags.usable = true;
 
         /* XXX: ugly condition, but how? */
 
         if (fetch->entry->store_status == STORE_OK)
             debugs(72, 2, "re-used old digest from " << host);
         else
             debugs(72, 2, "received valid digest from " << host);
     }
 
     cbdataReferenceDone(fetch->pd);
 }
@@ -975,93 +960,92 @@
         return 0;
     }
 
     if (cblock.ver.current < CacheDigestVer.required) {
         debugs(72, DBG_IMPORTANT, "" << host << " digest is version " <<
                cblock.ver.current << "; we require: " <<
                CacheDigestVer.required);
 
         return 0;
     }
 
     /* check consistency */
     if (cblock.ver.required > cblock.ver.current ||
             cblock.mask_size <= 0 || cblock.capacity <= 0 ||
             cblock.bits_per_entry <= 0 || cblock.hash_func_count <= 0) {
         debugs(72, DBG_CRITICAL, "" << host << " digest cblock is corrupted.");
         return 0;
     }
 
     /* check consistency further */
-    if ((size_t)cblock.mask_size != cacheDigestCalcMaskSize(cblock.capacity, cblock.bits_per_entry)) {
+    if ((size_t)cblock.mask_size != CacheDigest::CalcMaskSize(cblock.capacity, cblock.bits_per_entry)) {
         debugs(72, DBG_CRITICAL, host << " digest cblock is corrupted " <<
                "(mask size mismatch: " << cblock.mask_size << " ? " <<
-               cacheDigestCalcMaskSize(cblock.capacity, cblock.bits_per_entry)
+               CacheDigest::CalcMaskSize(cblock.capacity, cblock.bits_per_entry)
                << ").");
         return 0;
     }
 
     /* there are some things we cannot do yet */
     if (cblock.hash_func_count != CacheDigestHashFuncCount) {
         debugs(72, DBG_CRITICAL, "" << host << " digest: unsupported #hash functions: " <<
                cblock.hash_func_count << " ? " << CacheDigestHashFuncCount << ".");
         return 0;
     }
 
     /*
      * no cblock bugs below this point
      */
     /* check size changes */
     if (pd->cd && cblock.mask_size != (ssize_t)pd->cd->mask_size) {
         debugs(72, 2, host << " digest changed size: " << cblock.mask_size <<
                " -> " << pd->cd->mask_size);
         freed_size = pd->cd->mask_size;
-        cacheDigestDestroy(pd->cd);
-        pd->cd = NULL;
+        delete pd->cd;
+        pd->cd = nullptr;
     }
 
     if (!pd->cd) {
         debugs(72, 2, "creating " << host << " digest; size: " << cblock.mask_size << " (" <<
                std::showpos <<  (int) (cblock.mask_size - freed_size) << ") bytes");
-        pd->cd = cacheDigestCreate(cblock.capacity, cblock.bits_per_entry);
+        pd->cd = new CacheDigest(cblock.capacity, cblock.bits_per_entry);
 
         if (cblock.mask_size >= freed_size)
             statCounter.cd.memory += (cblock.mask_size - freed_size);
     }
 
     assert(pd->cd);
     /* these assignments leave us in an inconsistent state until we finish reading the digest */
     pd->cd->count = cblock.count;
     pd->cd->del_count = cblock.del_count;
     return 1;
 }
 
 static int
 peerDigestUseful(const PeerDigest * pd)
 {
     /* TODO: we should calculate the prob of a false hit instead of bit util */
-    const int bit_util = cacheDigestBitUtil(pd->cd);
+    const auto bit_util = pd->cd->usedMaskPercent();
 
-    if (bit_util > 65) {
+    if (bit_util > 65.0) {
         debugs(72, DBG_CRITICAL, "Warning: " << pd->host <<
-               " peer digest has too many bits on (" << bit_util << "%%).");
-
+               " peer digest has too many bits on (" << bit_util << "%).");
         return 0;
     }
 
     return 1;
 }
 
 static int
 saneDiff(time_t diff)
 {
     return abs((int) diff) > squid_curtime / 2 ? 0 : diff;
 }
 
 void
 peerDigestStatsReport(const PeerDigest * pd, StoreEntry * e)
 {
 #define f2s(flag) (pd->flags.flag ? "yes" : "no")
 #define appendTime(tm) storeAppendPrintf(e, "%s\t %10ld\t %+d\t %+d\n", \
     ""#tm, (long int)pd->times.tm, \
     saneDiff(pd->times.tm - squid_curtime), \
     saneDiff(pd->times.tm - pd->times.initialized))

=== modified file 'src/store.cc'
--- src/store.cc	2015-09-21 14:02:38 +0000
+++ src/store.cc	2015-11-05 13:12:15 +0000
@@ -1504,46 +1504,42 @@
  */
 void
 StoreEntry::negativeCache()
 {
     // XXX: should make the default for expires 0 instead of -1
     //      so we can distinguish "Expires: -1" from nothing.
     if (expires <= 0)
 #if USE_HTTP_VIOLATIONS
         expires = squid_curtime + Config.negativeTtl;
 #else
         expires = squid_curtime;
 #endif
     EBIT_SET(flags, ENTRY_NEGCACHED);
 }
 
 void
 storeFreeMemory(void)
 {
     Store::Root(NULL);
 #if USE_CACHE_DIGESTS
-
-    if (store_digest)
-        cacheDigestDestroy(store_digest);
-
+    delete store_digest;
 #endif
-
     store_digest = NULL;
 }
 
 int
 expiresMoreThan(time_t expires, time_t when)
 {
     if (expires < 0)            /* No Expires given */
         return 1;
 
     return (expires > (squid_curtime + when));
 }
 
 int
 StoreEntry::validToSend() const
 {
     if (EBIT_TEST(flags, RELEASE_REQUEST))
         return 0;
 
     if (EBIT_TEST(flags, ENTRY_NEGCACHED))
         if (expires <= squid_curtime)

=== modified file 'src/store_digest.cc'
--- src/store_digest.cc	2015-07-07 16:35:58 +0000
+++ src/store_digest.cc	2015-11-05 18:19:08 +0000
@@ -90,86 +90,86 @@
 }
 
 /*
  * PUBLIC FUNCTIONS
  */
 
 void
 storeDigestInit(void)
 {
     storeDigestRegisterWithCacheManager();
 
 #if USE_CACHE_DIGESTS
     const int cap = storeDigestCalcCap();
 
     if (!Config.onoff.digest_generation) {
         store_digest = NULL;
         debugs(71, 3, "Local cache digest generation disabled");
         return;
     }
 
-    store_digest = cacheDigestCreate(cap, Config.digest.bits_per_entry);
+    store_digest = new CacheDigest(cap, Config.digest.bits_per_entry);
     debugs(71, DBG_IMPORTANT, "Local cache digest enabled; rebuild/rewrite every " <<
            (int) Config.digest.rebuild_period << "/" <<
            (int) Config.digest.rewrite_period << " sec");
 
     memset(&sd_state, 0, sizeof(sd_state));
 #else
     store_digest = NULL;
     debugs(71, 3, "Local cache digest is 'off'");
 #endif
 }
 
 /* called when store_rebuild completes */
 void
 storeDigestNoteStoreReady(void)
 {
 #if USE_CACHE_DIGESTS
 
     if (Config.onoff.digest_generation) {
         storeDigestRebuildStart(NULL);
         storeDigestRewriteStart(NULL);
     }
 
 #endif
 }
 
 //TODO: this seems to be dead code. Is it needed?
 void
 storeDigestDel(const StoreEntry * entry)
 {
 #if USE_CACHE_DIGESTS
 
     if (!Config.onoff.digest_generation) {
         return;
     }
 
     assert(entry && store_digest);
     debugs(71, 6, "storeDigestDel: checking entry, key: " << entry->getMD5Text());
 
     if (!EBIT_TEST(entry->flags, KEY_PRIVATE)) {
-        if (!cacheDigestTest(store_digest,  (const cache_key *)entry->key)) {
+        if (!store_digest->test(static_cast<const cache_key *>(entry->key))) {
             ++sd_stats.del_lost_count;
             debugs(71, 6, "storeDigestDel: lost entry, key: " << entry->getMD5Text() << " url: " << entry->url()  );
         } else {
             ++sd_stats.del_count;
-            cacheDigestDel(store_digest,  (const cache_key *)entry->key);
+            store_digest->remove(static_cast<const cache_key *>(entry->key));
             debugs(71, 6, "storeDigestDel: deled entry, key: " << entry->getMD5Text());
         }
     }
 #endif //USE_CACHE_DIGESTS
 }
 
 void
 storeDigestReport(StoreEntry * e)
 {
 #if USE_CACHE_DIGESTS
 
     if (!Config.onoff.digest_generation) {
         return;
     }
 
     if (store_digest) {
         cacheDigestReport(store_digest, "store", e);
         storeAppendPrintf(e, "\t added: %d rejected: %d ( %.2f %%) del-ed: %d\n",
                           sd_stats.add_count,
                           sd_stats.rej_count,
@@ -237,88 +237,88 @@
     /*
      * idea: how about also skipping very fresh (thus, potentially
      * unstable) entries? Should be configurable through
      * cd_refresh_pattern, of course.
      */
     /*
      * idea: skip objects that are going to be purged before the next
      * update.
      */
     return 1;
 }
 
 static void
 storeDigestAdd(const StoreEntry * entry)
 {
     assert(entry && store_digest);
 
     if (storeDigestAddable(entry)) {
         ++sd_stats.add_count;
 
-        if (cacheDigestTest(store_digest, (const cache_key *)entry->key))
+        if (store_digest->test(static_cast<const cache_key *>(entry->key)))
             ++sd_stats.add_coll_count;
 
-        cacheDigestAdd(store_digest,  (const cache_key *)entry->key);
+        store_digest->add(static_cast<const cache_key *>(entry->key));
 
         debugs(71, 6, "storeDigestAdd: added entry, key: " << entry->getMD5Text());
     } else {
         ++sd_stats.rej_count;
 
-        if (cacheDigestTest(store_digest,  (const cache_key *)entry->key))
+        if (store_digest->test(static_cast<const cache_key *>(entry->key)))
             ++sd_stats.rej_coll_count;
     }
 }
 
 /* rebuilds digest from scratch */
 static void
 storeDigestRebuildStart(void *datanotused)
 {
     assert(store_digest);
     /* prevent overlapping if rebuild schedule is too tight */
 
     if (sd_state.rebuild_lock) {
         debugs(71, DBG_IMPORTANT, "storeDigestRebuildStart: overlap detected, consider increasing rebuild period");
         return;
     }
 
     sd_state.rebuild_lock = 1;
     debugs(71, 2, "storeDigestRebuildStart: rebuild #" << sd_state.rebuild_count + 1);
 
     if (sd_state.rewrite_lock) {
         debugs(71, 2, "storeDigestRebuildStart: waiting for Rewrite to finish.");
         return;
     }
 
     storeDigestRebuildResume();
 }
 
 /* called be Rewrite to push Rebuild forward */
 static void
 storeDigestRebuildResume(void)
 {
     assert(sd_state.rebuild_lock);
     assert(!sd_state.rewrite_lock);
     sd_state.theSearch = Store::Root().search(NULL, NULL);
     /* resize or clear */
 
     if (!storeDigestResize())
-        cacheDigestClear(store_digest);     /* not clean()! */
+        store_digest->clear();     /* not clean()! */
 
     memset(&sd_stats, 0, sizeof(sd_stats));
 
     eventAdd("storeDigestRebuildStep", storeDigestRebuildStep, NULL, 0.0, 1);
 }
 
 /* finishes swap out sequence for the digest; schedules next rebuild */
 static void
 storeDigestRebuildFinish(void)
 {
     assert(sd_state.rebuild_lock);
     sd_state.rebuild_lock = 0;
     ++sd_state.rebuild_count;
     debugs(71, 2, "storeDigestRebuildFinish: done.");
     eventAdd("storeDigestRebuildStart", storeDigestRebuildStart, NULL, (double)
              Config.digest.rebuild_period, 1);
     /* resume pending Rewrite if any */
 
     if (sd_state.rewrite_lock)
         storeDigestRewriteResume();
@@ -501,27 +501,27 @@
 }
 
 /* returns true if we actually resized the digest */
 static int
 storeDigestResize(void)
 {
     const int cap = storeDigestCalcCap();
     int diff;
     assert(store_digest);
     diff = abs(cap - store_digest->capacity);
     debugs(71, 2, "storeDigestResize: " <<
            store_digest->capacity << " -> " << cap << "; change: " <<
            diff << " (" << xpercentInt(diff, store_digest->capacity) << "%)" );
     /* avoid minor adjustments */
 
     if (diff <= store_digest->capacity / 10) {
         debugs(71, 2, "storeDigestResize: small change, will not resize.");
         return 0;
     } else {
         debugs(71, 2, "storeDigestResize: big change, resizing.");
-        cacheDigestChangeCap(store_digest, cap);
+        store_digest->updateCapacity(cap);
         return 1;
     }
 }
 
 #endif /* USE_CACHE_DIGESTS */
 

=== modified file 'src/test_cache_digest.cc'
--- src/test_cache_digest.cc	2015-01-13 07:25:36 +0000
+++ src/test_cache_digest.cc	2015-11-05 18:19:40 +0000
@@ -216,102 +216,98 @@
 }
 
 static void
 cacheDestroy(Cache * cache)
 {
     CacheEntry *e = NULL;
     hash_table *hash;
     assert(cache);
     hash = cache->hash;
     /* destroy hash table contents */
     hash_first(hash);
 
     while ((e = (CacheEntry *)hash_next(hash))) {
         hash_remove_link(hash, (hash_link *) e);
         cacheEntryDestroy(e);
     }
 
     /* destroy the hash table itself */
     hashFreeMemory(hash);
 
-    if (cache->digest)
-        cacheDigestDestroy(cache->digest);
-
+    delete cache->digest;
     xfree(cache);
 }
 
 /* re-digests currently hashed entries */
 static void
 cacheResetDigest(Cache * cache)
 {
     CacheEntry *e = NULL;
     hash_table *hash;
 
     struct timeval t_start, t_end;
 
     assert(cache);
     fprintf(stderr, "%s: init-ing digest with %d entries\n", cache->name, cache->count);
 
-    if (cache->digest)
-        cacheDigestDestroy(cache->digest);
-
     hash = cache->hash;
 
-    cache->digest = cacheDigestCreate(cache->count + 1, 6);
+    delete cache->digest;
+    cache->digest = new CacheDigest(cache->count + 1, 6);
 
     if (!cache->count)
         return;
 
     gettimeofday(&t_start, NULL);
 
     hash_first(hash);
 
     while ((e = (CacheEntry *)hash_next(hash))) {
-        cacheDigestAdd(cache->digest, e->key);
+        cache->digest->add(e->key);
     }
 
     gettimeofday(&t_end, NULL);
     assert(cache->digest->count == cache->count);
     fprintf(stderr, "%s: init-ed  digest with %d entries\n",
             cache->name, cache->digest->count);
     fprintf(stderr, "%s: init took: %f sec, %f sec/M\n",
             cache->name,
             tvSubDsec(t_start, t_end),
             (double) 1e6 * tvSubDsec(t_start, t_end) / cache->count);
     /* check how long it takes to traverse the hash */
     gettimeofday(&t_start, NULL);
     hash_first(hash);
 
     for (e = (CacheEntry *)hash_next(hash); e; e = (CacheEntry *)hash_next(hash)) {}
 
     gettimeofday(&t_end, NULL);
     fprintf(stderr, "%s: hash scan took: %f sec, %f sec/M\n",
             cache->name,
             tvSubDsec(t_start, t_end),
             (double) 1e6 * tvSubDsec(t_start, t_end) / cache->count);
 }
 
 static void
 cacheQueryPeer(Cache * cache, const cache_key * key)
 {
     const int peer_has_it = hash_lookup(cache->peer->hash, key) != NULL;
-    const int we_think_we_have_it = cacheDigestTest(cache->digest, key);
+    const int we_think_we_have_it = cache->digest->test(key);
 
     ++ cache->qstats.query_count;
 
     if (peer_has_it) {
         if (we_think_we_have_it)
             ++ cache->qstats.true_hit_count;
         else
             ++ cache->qstats.false_miss_count;
     } else {
         if (we_think_we_have_it)
             ++ cache->qstats.false_hit_count;
         else
             ++ cache->qstats.true_miss_count;
     }
 }
 
 static void
 cacheQueryReport(Cache * cache, CacheQueryStats * stats)
 {
     fprintf(stdout, "%s: peer queries: %d (%d%%)\n",
@@ -457,62 +453,62 @@
      */
     memcpy(entry->key, storeKeyPublic(url, method_id), sizeof(entry->key));
 
     /*fprintf(stdout, "%s:%d: %s %s %s %s\n",
      * fname, count, method, storeKeyText(entry->key), url, hier); */
     return frOk;
 }
 
 static void
 cachePurge(Cache * cache, storeSwapLogData * s, int update_digest)
 {
     CacheEntry *olde = (CacheEntry *) hash_lookup(cache->hash, s->key);
 
     if (!olde) {
         ++ cache->bad_del_count;
     } else {
         assert(cache->count);
         hash_remove_link(cache->hash, (hash_link *) olde);
 
         if (update_digest)
-            cacheDigestDel(cache->digest, s->key);
+            cache->digest->remove(s->key);
 
         cacheEntryDestroy(olde);
 
         -- cache->count;
     }
 }
 
 static void
 cacheStore(Cache * cache, storeSwapLogData * s, int update_digest)
 {
     CacheEntry *olde = (CacheEntry *) hash_lookup(cache->hash, s->key);
 
     if (olde) {
         ++ cache->bad_add_count;
     } else {
         CacheEntry *e = cacheEntryCreate(s);
         hash_join(cache->hash, (hash_link *)&e->key);
         ++ cache->count;
 
         if (update_digest)
-            cacheDigestAdd(cache->digest, e->key);
+            cache->digest->add(e->key);
     }
 }
 
 static void
 cacheUpdateStore(Cache * cache, storeSwapLogData * s, int update_digest)
 {
     switch (s->op) {
 
     case SWAP_LOG_ADD:
         cacheStore(cache, s, update_digest);
         break;
 
     case SWAP_LOG_DEL:
         cachePurge(cache, s, update_digest);
         break;
 
     default:
         assert(0);
     }
 }
@@ -568,41 +564,41 @@
         while (fi->inner_time > 0) {
             if (((storeSwapLogData *) fi->entry)->op == SWAP_LOG_DEL) {
                 cachePurge(them, (storeSwapLogData *)fi->entry, 0);
 
                 if (ready_time < 0)
                     ready_time = fi->inner_time;
             } else {
                 if (ready_time > 0 && fi->inner_time > ready_time)
                     break;
 
                 cacheStore(them, (storeSwapLogData *)fi->entry, 0);
             }
 
             fileIteratorAdvance(fi);
         }
     }
 
     /* digest peer cache content */
     cacheResetDigest(them);
 
-    us->digest = cacheDigestClone(them->digest);    /* @netw@ */
+    us->digest = them->digest->clone();
 
     /* shift the time in access log to match ready_time */
     fileIteratorSetCurTime(fis[0], ready_time);
 
     /* iterate, use the iterator with the smallest positive inner_time */
     cur_time = -1;
 
     do {
         int next_i = -1;
         time_t next_time = -1;
         active_fi_count = 0;
 
         for (i = 0; i < fi_count; ++i) {
             if (fis[i]->inner_time >= 0) {
                 if (!active_fi_count || fis[i]->inner_time < next_time) {
                     next_i = i;
                     next_time = fis[i]->inner_time;
                 }
 
                 ++active_fi_count;

=== modified file 'src/tests/stub_CacheDigest.cc'
--- src/tests/stub_CacheDigest.cc	2015-08-31 06:17:22 +0000
+++ src/tests/stub_CacheDigest.cc	2015-11-06 08:58:47 +0000
@@ -1,32 +1,33 @@
 /*
  * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #include "squid.h"
 #include "store_key_md5.h"
 
 #define STUB_API "CacheDigest.cc"
 #include "tests/STUB.h"
 
 class CacheDigest;
 class CacheDigestGuessStats;
 class StoreEntry;
 
-CacheDigest * cacheDigestCreate(int, int) STUB_RETVAL(NULL)
-void cacheDigestDestroy(CacheDigest *) STUB
-CacheDigest * cacheDigestClone(const CacheDigest *) STUB_RETVAL(NULL)
-void cacheDigestClear(CacheDigest * ) STUB
-void cacheDigestChangeCap(CacheDigest *,int) STUB
-int cacheDigestTest(const CacheDigest *, const cache_key *) STUB_RETVAL(1)
-void cacheDigestAdd(CacheDigest *, const cache_key *) STUB
-void cacheDigestDel(CacheDigest *, const cache_key *) STUB
-int cacheDigestBitUtil(const CacheDigest *) STUB_RETVAL(0)
+#include "CacheDigest.h"
+CacheDigest::CacheDigest(int, int) {STUB}
+CacheDigest::~CacheDigest() {STUB}
+CacheDigest *CacheDigest::clone() const STUB_RETVAL(nullptr)
+void CacheDigest::clear() STUB
+void CacheDigest::updateCapacity(int) STUB
+bool CacheDigest::test(const cache_key *) const STUB_RETVAL(false)
+void CacheDigest::add(const cache_key *) STUB
+void CacheDigest::remove(const cache_key *) STUB
+double CacheDigest::usedMaskPercent() const STUB_RETVAL(0.0)
 void cacheDigestGuessStatsUpdate(CacheDigestGuessStats *, int, int) STUB
 void cacheDigestGuessStatsReport(const CacheDigestGuessStats *, StoreEntry *, const char *) STUB
 void cacheDigestReport(CacheDigest *, const char *, StoreEntry *) STUB
-size_t cacheDigestCalcMaskSize(int, int) STUB_RETVAL(1)
+size_t CacheDigest::CalcMaskSize(int, int) STUB_RETVAL(1)
 



More information about the squid-dev mailing list