Update and add missing documentation for class members.
Update syntax to latest standard compliance and Squid
coding guideline style.
#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3
#define AIO_MICRO_BUFS 128
-static MemAllocator *squidaio_large_bufs = nullptr; /* 16K */
-static MemAllocator *squidaio_medium_bufs = nullptr; /* 8K */
-static MemAllocator *squidaio_small_bufs = nullptr; /* 4K */
-static MemAllocator *squidaio_tiny_bufs = nullptr; /* 2K */
-static MemAllocator *squidaio_micro_bufs = nullptr; /* 128K */
+static Mem::Allocator *squidaio_large_bufs = nullptr; /* 16K */
+static Mem::Allocator *squidaio_medium_bufs = nullptr; /* 8K */
+static Mem::Allocator *squidaio_small_bufs = nullptr; /* 4K */
+static Mem::Allocator *squidaio_tiny_bufs = nullptr; /* 2K */
+static Mem::Allocator *squidaio_micro_bufs = nullptr; /* 128K */
static int request_queue_len = 0;
-static MemAllocator *squidaio_request_pool = nullptr;
-static MemAllocator *squidaio_thread_pool = nullptr;
+static Mem::Allocator *squidaio_request_pool = nullptr;
+static Mem::Allocator *squidaio_thread_pool = nullptr;
static squidaio_request_queue_t request_queue;
static struct {
#endif
static pthread_t main_thread;
-static MemAllocator *
+static Mem::Allocator *
squidaio_get_pool(int size)
{
if (size <= AIO_LARGE_BUFS) {
squidaio_xmalloc(int size)
{
void *p;
- MemAllocator *pool;
- if ((pool = squidaio_get_pool(size)) != nullptr) {
+ if (const auto pool = squidaio_get_pool(size)) {
p = pool->alloc();
} else
p = xmalloc(size);
void
squidaio_xfree(void *p, int size)
{
- MemAllocator *pool;
-
- if ((pool = squidaio_get_pool(size)) != nullptr) {
+ if (const auto pool = squidaio_get_pool(size)) {
pool->freeOne(p);
} else
xfree(p);
static void
squidaio_xstrfree(char *str)
{
- MemAllocator *pool;
int len = strlen(str) + 1;
- if ((pool = squidaio_get_pool(len)) != nullptr) {
+ if (const auto pool = squidaio_get_pool(len)) {
pool->freeOne(str);
} else
xfree(str);
#define AIO_TINY_BUFS AIO_LARGE_BUFS >> 3
#define AIO_MICRO_BUFS 128
-static MemAllocator *squidaio_large_bufs = NULL; /* 16K */
-static MemAllocator *squidaio_medium_bufs = NULL; /* 8K */
-static MemAllocator *squidaio_small_bufs = NULL; /* 4K */
-static MemAllocator *squidaio_tiny_bufs = NULL; /* 2K */
-static MemAllocator *squidaio_micro_bufs = NULL; /* 128K */
+static Mem::Allocator *squidaio_large_bufs = nullptr; /* 16K */
+static Mem::Allocator *squidaio_medium_bufs = nullptr; /* 8K */
+static Mem::Allocator *squidaio_small_bufs = nullptr; /* 4K */
+static Mem::Allocator *squidaio_tiny_bufs = nullptr; /* 2K */
+static Mem::Allocator *squidaio_micro_bufs = nullptr; /* 128K */
static int request_queue_len = 0;
-static MemAllocator *squidaio_request_pool = NULL;
-static MemAllocator *squidaio_thread_pool = NULL;
+static Mem::Allocator *squidaio_request_pool = nullptr;
+static Mem::Allocator *squidaio_thread_pool = nullptr;
static squidaio_request_queue_t request_queue;
static struct {
static HANDLE main_thread;
-static MemAllocator *
+static Mem::Allocator *
squidaio_get_pool(int size)
{
if (size <= AIO_LARGE_BUFS) {
squidaio_xmalloc(int size)
{
void *p;
- MemAllocator *pool;
-
- if ((pool = squidaio_get_pool(size)) != NULL) {
+ if (const auto pool = squidaio_get_pool(size)) {
p = pool->alloc();
} else
p = xmalloc(size);
void
squidaio_xfree(void *p, int size)
{
- MemAllocator *pool;
-
- if ((pool = squidaio_get_pool(size)) != NULL) {
+ if (const auto pool = squidaio_get_pool(size)) {
pool->freeOne(p);
} else
xfree(p);
static void
squidaio_xstrfree(char *str)
{
- MemAllocator *pool;
int len = strlen(str) + 1;
- if ((pool = squidaio_get_pool(len)) != NULL) {
+ if (const auto pool = squidaio_get_pool(len)) {
pool->freeOne(str);
} else
xfree(str);
/// flags [truncated or too big] entry with ENTRY_BAD_LENGTH and releases it
void lengthWentBad(const char *reason);
- static MemAllocator *pool;
+ static Mem::Allocator *pool;
unsigned short lock_count; /* Assume < 65536! */
static hash_table *digest_nonce_cache;
static int authdigest_initialised = 0;
-static MemAllocator *digest_nonce_pool = nullptr;
+static Mem::Allocator *digest_nonce_pool = nullptr;
enum http_digest_attr_type {
DIGEST_USERNAME,
#endif
struct CBDataIndex {
- MemAllocator *pool;
+ Mem::Allocator *pool;
}
*cbdata_index = nullptr;
storeAppendPrintf(sentry, "types\tsize\tallocated\ttotal\n");
for (int i = 1; i < cbdata_types; ++i) {
- MemAllocator *pool = cbdata_index[i].pool;
-
- if (pool) {
+ if (const auto pool = cbdata_index[i].pool) {
#if WITH_VALGRIND
int obj_size = pool->objectSize();
#else
--- /dev/null
+/*
+ * Copyright (C) 1996-2022 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.
+ */
+
+#ifndef SQUID_SRC_MEM_ALLOCATOR_H
+#define SQUID_SRC_MEM_ALLOCATOR_H
+
+#include "base/TypeTraits.h"
+#include "mem/forward.h"
+
+namespace Mem
+{
+
+/// An interface for memory allocators that deal with fixed-size objects.
+/// Allocators may optimize repeated de/allocations using memory pools.
+class Allocator : public Interface
+{
+public:
+ explicit Allocator(const char * const aLabel): label(aLabel) {}
+
+ // TODO make this method const
+ /**
+ * fill the given object with statistical data about pool
+ * \returns Number of objects in use, ie. allocated.
+ */
+ virtual int getStats(MemPoolStats *, int accumulate = 0) = 0;
+
+ virtual PoolMeter const &getMeter() const = 0;
+
+ /// provide (and reserve) memory suitable for storing one object
+ virtual void *alloc() = 0;
+
+ /// return memory reserved by alloc()
+ virtual void freeOne(void *) = 0;
+
+ /// brief description of objects returned by alloc()
+ virtual char const *objectType() const { return label; }
+
+ /// the size (in bytes) of objects managed by this allocator
+ virtual size_t objectSize() const = 0;
+
+ /// the difference between the number of alloc() and freeOne() calls
+ virtual int getInUseCount() = 0;
+
+ /// \see doZero
+ void zeroBlocks(const bool doIt) { doZero = doIt; }
+
+ int inUseCount() { return getInUseCount(); } // XXX: drop redundant?
+
+ /// XXX: Misplaced -- not all allocators have a notion of a "chunk". See MemPoolChunked.
+ virtual void setChunkSize(size_t) {}
+
+ /**
+ * \param minSize Minimum size needed to be allocated.
+ * \retval n Smallest size divisible by sizeof(void*)
+ */
+ static size_t RoundedSize(const size_t minSize) { return ((minSize + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*); }
+
+protected:
+ /**
+ * Whether to zero memory on initial allocation and on return to the pool.
+ *
+ * We do this on some pools because many object constructors are/were incomplete
+ * and we are afraid some code may use the object after free.
+ * When possible, set this to false to avoid zeroing overheads.
+ */
+ bool doZero = true;
+
+private:
+ const char *label = nullptr;
+};
+
+} // namespace Mem
+
+#endif /* SQUID_SRC_MEM_ALLOCATOR_H */
*/
}
-MemAllocator *
+Mem::Allocator *
Mem::AllocatorProxy::getAllocator() const
{
if (!theAllocator) {
#ifndef _SQUID_SRC_MEM_ALLOCATORPROXY_H
#define _SQUID_SRC_MEM_ALLOCATORPROXY_H
-class MemAllocator;
+// XXX: remove AllocatorProxy.h include from mem/forward.h
+namespace Mem {
+class Allocator;
+}
class MemPoolStats;
/**
void zeroBlocks(bool doIt);
private:
- MemAllocator *getAllocator() const;
+ Allocator *getAllocator() const;
const char *label;
size_t size;
- mutable MemAllocator *theAllocator;
+ mutable Allocator *theAllocator;
bool doZero;
};
# a full-featured memory management library for sbin/squid use
libmem_la_SOURCES = \
+ Allocator.h \
AllocatorProxy.cc \
Meter.h \
Pool.cc \
defaultIsChunked = aBool;
}
-char const *
-MemAllocator::objectType() const
-{
- return label;
-}
-
-int
-MemAllocator::inUseCount()
-{
- return getInUseCount();
-}
-
void
MemImplementingAllocator::flushMeters()
{
memPoolGetGlobalStats(MemPoolGlobalStats * stats)
{
int pools_inuse = 0;
- MemAllocator *pool;
MemPoolIterator *iter;
memset(stats, 0, sizeof(MemPoolGlobalStats));
/* gather all stats for Totals */
iter = memPoolIterate();
- while ((pool = memPoolIterateNext(iter))) {
+ while (const auto pool = memPoolIterateNext(iter)) {
if (pool->getStats(&pp_stats, 1) > 0)
++pools_inuse;
}
stats->tot_items_inuse = pp_stats.items_inuse;
stats->tot_items_idle = pp_stats.items_idle;
- stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(MemAllocator *);
+ stats->tot_overhead += pp_stats.overhead + MemPools::GetInstance().poolCount * sizeof(Mem::Allocator *);
stats->mem_idle_limit = MemPools::GetInstance().idleLimit();
return pools_inuse;
}
-MemAllocator::MemAllocator(char const *aLabel) : doZero(true), label(aLabel)
-{
-}
-
-size_t MemAllocator::RoundedSize(size_t s)
-{
- return ((s + sizeof(void*) - 1) / sizeof(void*)) * sizeof(void*);
-}
-
int
memPoolsTotalAllocated(void)
{
return stats.TheMeter->alloc.currentLevel();
}
-MemImplementingAllocator::MemImplementingAllocator(char const *aLabel, size_t aSize) : MemAllocator(aLabel),
+MemImplementingAllocator::MemImplementingAllocator(char const * const aLabel, const size_t aSize):
+ Mem::Allocator(aLabel),
next(nullptr),
alloc_calls(0),
free_calls(0),
* might be the way to go.
*/
+#include "mem/Allocator.h"
#include "mem/Meter.h"
#include "util.h"
ssize_t idleLimit_ = (2 << 20);
};
-/**
- \ingroup MemPoolsAPI
- * a pool is a [growing] space for objects of the same size
- */
-class MemAllocator
-{
-public:
- typedef Mem::PoolMeter PoolMeter; // TODO remove
-
- MemAllocator (char const *aLabel);
- virtual ~MemAllocator() {}
-
- /**
- \param stats Object to be filled with statistical data about pool.
- \retval Number of objects in use, ie. allocated.
- */
- virtual int getStats(MemPoolStats * stats, int accumulate = 0) = 0;
-
- virtual PoolMeter const &getMeter() const = 0;
-
- /**
- * Allocate one element from the pool
- */
- virtual void *alloc() = 0;
-
- /**
- * Free a element allocated by MemAllocator::alloc()
- */
- virtual void freeOne(void *) = 0;
-
- virtual char const *objectType() const;
- virtual size_t objectSize() const = 0;
- virtual int getInUseCount() = 0;
- void zeroBlocks(bool doIt) {doZero = doIt;}
- int inUseCount();
-
- /**
- * Allows you tune chunk size of pooling. Objects are allocated in chunks
- * instead of individually. This conserves memory, reduces fragmentation.
- * Because of that memory can be freed also only in chunks. Therefore
- * there is tradeoff between memory conservation due to chunking and free
- * memory fragmentation.
- *
- \note As a general guideline, increase chunk size only for pools that keep
- * very many items for relatively long time.
- */
- virtual void setChunkSize(size_t) {}
-
- /**
- \param minSize Minimum size needed to be allocated.
- \retval n Smallest size divisible by sizeof(void*)
- */
- static size_t RoundedSize(size_t minSize);
-
-protected:
- /** Whether to zero memory on initial allocation and on return to the pool.
- *
- * We do this on some pools because many object constructors are/were incomplete
- * and we are afraid some code may use the object after free.
- * These probems are becoming less common, so when possible set this to false.
- */
- bool doZero;
-
-private:
- const char *label;
-};
-
/// \ingroup MemPoolsAPI
-class MemImplementingAllocator : public MemAllocator
+class MemImplementingAllocator : public Mem::Allocator
{
public:
typedef Mem::PoolMeter PoolMeter; // TODO remove
MemImplementingAllocator(char const *aLabel, size_t aSize);
virtual ~MemImplementingAllocator();
- virtual PoolMeter const &getMeter() const;
+
virtual PoolMeter &getMeter();
virtual void flushMetersFull();
virtual void flushMeters();
+ virtual bool idleTrigger(int shift) const = 0;
+ virtual void clean(time_t maxage) = 0;
- /**
- * Allocate one element from the pool
- */
+ /* Mem::Allocator API */
+ virtual PoolMeter const &getMeter() const;
virtual void *alloc();
-
- /**
- * Free a element allocated by MemImplementingAllocator::alloc()
- */
virtual void freeOne(void *);
-
- virtual bool idleTrigger(int shift) const = 0;
- virtual void clean(time_t maxage) = 0;
virtual size_t objectSize() const;
virtual int getInUseCount() = 0;
+
protected:
virtual void *allocate() = 0;
virtual void deallocate(void *, bool aggressive) = 0;
{
public:
typedef Mem::PoolMeter PoolMeter; // TODO remove
+ typedef Mem::Allocator Allocator; // TODO remove
- MemAllocator *pool;
+ Allocator *pool;
const char *label;
PoolMeter *meter;
int obj_size;
chunk->next = newChunk;
}
+/**
+ * Allows you tune chunk size of pooling. Objects are allocated in chunks
+ * instead of individually. This conserves memory, reduces fragmentation.
+ * Because of that memory can be freed also only in chunks. Therefore
+ * there is tradeoff between memory conservation due to chunking and free
+ * memory fragmentation.
+ *
+ * \note As a general guideline, increase chunk size only for pools that keep
+ * very many items for relatively long time.
+ */
void
MemPoolChunked::setChunkSize(size_t chunksize)
{
void convertFreeCacheToChunkFreeCache();
virtual void clean(time_t maxage);
- /**
- \param stats Object to be filled with statistical data about pool.
- \retval Number of objects in use, ie. allocated.
- */
- virtual int getStats(MemPoolStats * stats, int accumulate);
-
void createChunk();
void *get();
void push(void *obj);
+
+ /* Mem::Allocator API */
+ virtual int getStats(MemPoolStats *, int);
virtual int getInUseCount();
+ virtual void setChunkSize(size_t);
+
protected:
virtual void *allocate();
virtual void deallocate(void *, bool aggressive);
public:
- /**
- * Allows you tune chunk size of pooling. Objects are allocated in chunks
- * instead of individually. This conserves memory, reduces fragmentation.
- * Because of that memory can be freed also only in chunks. Therefore
- * there is tradeoff between memory conservation due to chunking and free
- * memory fragmentation.
- *
- \note As a general guideline, increase chunk size only for pools that keep
- * very many items for relatively long time.
- */
- virtual void setChunkSize(size_t chunksize);
-
virtual bool idleTrigger(int shift) const;
size_t chunk_size;
virtual bool idleTrigger(int shift) const;
virtual void clean(time_t maxage);
- /**
- \param stats Object to be filled with statistical data about pool.
- \retval Number of objects in use, ie. allocated.
- */
- virtual int getStats(MemPoolStats * stats, int accumulate);
-
+ /* Mem::Allocator API */
+ virtual int getStats(MemPoolStats *, int);
virtual int getInUseCount();
+
protected:
virtual void *allocate();
virtual void deallocate(void *, bool aggressive);
/// The number of currently alive objects (poor man's meter.alloc=meter.inuse).
/// Technically, this is supposed to be a per-allocator statistics, but
-/// AllocatorProxy is not a MemAllocator so we maintain a global counter
+/// AllocatorProxy is not a Mem::Allocator so we maintain a global counter
/// instead. We probably do not have to maintain this statistics at all.
static int Alive = 0;
// XXX: refactor objects using these pools to use MEMPROXY classes instead
// then remove this function entirely
-static MemAllocator *&
+static Mem::Allocator *&
GetPool(size_t type)
{
- static MemAllocator *pools[MEM_MAX];
+ static Mem::Allocator *pools[MEM_MAX];
static bool initialized = false;
if (!initialized) {
return pools[type];
}
-static MemAllocator &
+static Mem::Allocator &
GetStrPool(size_t type)
{
- static MemAllocator *strPools[mem_str_pool_count];
+ static Mem::Allocator *strPools[mem_str_pool_count];
static bool initialized = false;
static const PoolMeta PoolAttrs[mem_str_pool_count] = {
- {"Short Strings", MemAllocator::RoundedSize(36)}, /* to fit rfc1123 and similar */
- {"Medium Strings", MemAllocator::RoundedSize(128)}, /* to fit most urls */
- {"Long Strings", MemAllocator::RoundedSize(512)},
- {"1KB Strings", MemAllocator::RoundedSize(1024)},
- {"4KB Strings", MemAllocator::RoundedSize(4*1024)},
- {"16KB Strings", MemAllocator::RoundedSize(16*1024)}
+ {"Short Strings", Mem::Allocator::RoundedSize(36)}, /* to fit rfc1123 and similar */
+ {"Medium Strings", Mem::Allocator::RoundedSize(128)}, /* to fit most urls */
+ {"Long Strings", Mem::Allocator::RoundedSize(512)},
+ {"1KB Strings", Mem::Allocator::RoundedSize(1024)},
+ {"4KB Strings", Mem::Allocator::RoundedSize(4*1024)},
+ {"16KB Strings", Mem::Allocator::RoundedSize(16*1024)}
};
if (!initialized) {
}
/// \returns the best-fit string pool or nil
-static MemAllocator *
+static Mem::Allocator *
memFindStringPool(size_t net_size, bool fuzzy)
{
for (unsigned int i = 0; i < mem_str_pool_count; ++i) {
static MemPoolGlobalStats mp_total;
int not_used = 0;
MemPoolIterator *iter;
- MemAllocator *pool;
/* caption */
stream << "Current memory usage:\n";
/* main table */
iter = memPoolIterate();
- while ((pool = memPoolIterateNext(iter))) {
+ while (const auto pool = memPoolIterateNext(iter)) {
pool->getStats(&mp_stats);
if (!mp_stats.pool) /* pool destroyed */
#define PCONN_FDS_SZ 8 /* pconn set size, increase for better memcache hit rate */
-//TODO: re-attach to MemPools. WAS: static MemAllocator *pconn_fds_pool = NULL;
+//TODO: re-attach to MemPools. WAS: static Mem::Allocator *pconn_fds_pool = NULL;
PconnModule * PconnModule::instance = nullptr;
CBDATA_CLASS_INIT(IdleConnList);
dlink_node node;
};
-static MemAllocator *lru_node_pool = nullptr;
+static Mem::Allocator *lru_node_pool = nullptr;
static int nr_lru_policies = 0;
static void
* local variables
*/
static std::stack<StoreEntry*> LateReleaseStack;
-MemAllocator *StoreEntry::pool = nullptr;
+Mem::Allocator *StoreEntry::pool = nullptr;
void
Store::Stats(StoreEntry * output)
#define STUB_API "mem/libmem.la"
#include "tests/STUB.h"
+#include "mem/Allocator.h"
+
#include "mem/AllocatorProxy.h"
#include "mem/forward.h"
void MemPools::clean(time_t) STUB
void MemPools::setDefaultPoolChunking(bool const &) STUB
-//MemAllocator::MemAllocator(char const *aLabel);
-char const *MemAllocator::objectType() const STUB_RETVAL(nullptr)
-int MemAllocator::inUseCount() STUB_RETVAL(0)
-size_t MemAllocator::RoundedSize(size_t minSize) STUB_RETVAL(minSize)
-
//MemImplementingAllocator::MemImplementingAllocator(char const *, size_t) STUB_NOP
//MemImplementingAllocator::~MemImplementingAllocator();
Mem::PoolMeter const &MemImplementingAllocator::getMeter() const STUB_RETSTATREF(PoolMeter)
void
testMem::testMemPool()
{
- MemAllocator *Pool = memPoolCreate("Test Pool", sizeof(SomethingToAlloc));
+ const auto Pool = memPoolCreate("Test Pool", sizeof(SomethingToAlloc));
CPPUNIT_ASSERT(Pool);
auto *something = static_cast<SomethingToAlloc *>(Pool->alloc());