]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
SMP Cache Manager, Phase2 implementation.
authorAlex Rousskov <rousskov@measurement-factory.com>
Thu, 28 Oct 2010 18:52:59 +0000 (12:52 -0600)
committerAlex Rousskov <rousskov@measurement-factory.com>
Thu, 28 Oct 2010 18:52:59 +0000 (12:52 -0600)
Cache Manager actions are forwarded to Coordinator. Coordinator iterates over
Kids, aggregating their stats if possible and/or allowing each kid to dump
non-aggregatable output directly into response if needed. Non-aggregated
output is wrapped in "by kidN { ... } by kidN" markup to ease auto-processing.

Regressions and small output formatting changes are probably unavoidable
because stats are aggregated and passed around as doubles instead of integers
(no more overflows though!) and because many stats collection and formatting
lines had to be touched. These are steps in the right direction though, IMO.

Old code both computed and dumped stats to Store at the same time. To avoid
computing code duplication, we now collect stats in primitive Stats objects
and then either dump those to Store or send them to Coordinator for
aggregation and, eventual Store dump. What stats to collect, when to
aggregate, and when to dump is decided by action-specific Mgr::Action classes.

The Cache Manager menu now consists of ActionProfile objects. ActionProfile
maintains hard-coded information about specific actions. It uses ActionCreator
member to create Action objects when a cache manager request is received.

Added Mgr::ActionParams class to maintain action parameters, including HTTP
request details necessary for Store entry creation (in another strand) and
action-specific parameters (currently just credentials). In Phase3, this class
can be extended to supply more parameters such as kid IDs to which the action
should apply.

Added Mgr::Command that combines hard-coded ActionProfile details with
user-specified ActionParams. This simplifies many interfaces because we no
longer need to supply a long list of parameters, covering various parts of
action config.

Moved Cache Manager registration to Mgr::RegisterAction() globals to reduce
dependency on the CacheManager class, which is a singleton anyway, and which
is unused by most of the registration callers.  On the other hand, without
this change, no legacy (function-based actions) code would have been changed!

Enhanced TypedMsgHdr class to simplify storing and loading non-POD classes.
The caller can now easily handle a non-POD class as a series of put/get calls,
one for each POD member. This was necessary to send Mgr::ActionParams to
Coordinator and back. Will probably be useful for sending other complex
structures as well.

Reconfigure, shutdown, and other "basic" actions have been moved to
src/mgr/BasicActions.cc. Mgr::RegisterBasics() registers them.

Most of the Cache Manager code is now in src/mgr/.

Many more polishing touches.

More polishing left for future projects: Move CacheManager to Mgr namespace
and src/mgr/ directory. Use SBuf instead of String for ActionParams and
TypedMsgHdr. Rename Ipc::TypedMsgHdr to Ipc::Msg, Ipc::SocketMsg, or similar
because it maintains more than just msghdr struct. More stats aggregation,
and Phase3 changes.

118 files changed:
configure.in
src/CacheManager.h
src/DiskIO/DiskDaemon/DiskDaemonDiskIOModule.cc
src/DiskIO/DiskDaemon/DiskDaemonDiskIOModule.h
src/DiskIO/DiskDaemon/DiskdAction.cc [new file with mode: 0644]
src/DiskIO/DiskDaemon/DiskdAction.h [new file with mode: 0644]
src/DiskIO/DiskThreads/DiskThreadsIOStrategy.cc
src/HttpHeader.cc
src/Makefile.am
src/ProfStats.cc
src/Store.h
src/StoreIOBuffer.h
src/String.cc
src/acl/Asn.cc
src/auth/basic/auth_basic.cc
src/auth/digest/auth_digest.cc
src/auth/negotiate/auth_negotiate.cc
src/auth/ntlm/auth_ntlm.cc
src/base/AsyncJobCalls.h
src/cache_cf.cc
src/cache_manager.cc
src/carp.cc
src/cbdata.cc
src/client_db.cc
src/comm_epoll.cc
src/comm_kqueue.cc
src/comm_poll.cc
src/comm_select.cc
src/comm_select_win32.cc
src/delay_pools.cc
src/dns.cc
src/dns_internal.cc
src/event.cc
src/external_acl.cc
src/forward.cc
src/fqdncache.cc
src/fs/coss/StoreFScoss.cc
src/icmp/net_db.cc
src/ipc/Coordinator.cc
src/ipc/Coordinator.h
src/ipc/Makefile.am
src/ipc/Messages.h
src/ipc/Port.h
src/ipc/SharedListen.cc
src/ipc/Strand.cc
src/ipc/Strand.h
src/ipc/StrandCoord.cc [moved from src/ipc/Messages.cc with 73% similarity]
src/ipc/StrandCoord.h [new file with mode: 0644]
src/ipc/StrandCoords.h [new file with mode: 0644]
src/ipc/TypedMsgHdr.cc
src/ipc/TypedMsgHdr.h
src/ipc/forward.h [new file with mode: 0644]
src/ipcache.cc
src/log/access_log.cc
src/mem.cc
src/mgr/Action.cc [new file with mode: 0644]
src/mgr/Action.h [new file with mode: 0644]
src/mgr/ActionCreator.h [new file with mode: 0644]
src/mgr/ActionParams.cc [new file with mode: 0644]
src/mgr/ActionParams.h [new file with mode: 0644]
src/mgr/ActionProfile.h [new file with mode: 0644]
src/mgr/ActionWriter.cc [new file with mode: 0644]
src/mgr/ActionWriter.h [new file with mode: 0644]
src/mgr/BasicActions.cc [new file with mode: 0644]
src/mgr/BasicActions.h [new file with mode: 0644]
src/mgr/Command.cc [new file with mode: 0644]
src/mgr/Command.h [new file with mode: 0644]
src/mgr/CountersAction.cc [new file with mode: 0644]
src/mgr/CountersAction.h [new file with mode: 0644]
src/mgr/Filler.cc [new file with mode: 0644]
src/mgr/Filler.h [new file with mode: 0644]
src/mgr/Forwarder.cc [new file with mode: 0644]
src/mgr/Forwarder.h [new file with mode: 0644]
src/mgr/FunAction.cc [new file with mode: 0644]
src/mgr/FunAction.h [new file with mode: 0644]
src/mgr/InfoAction.cc [new file with mode: 0644]
src/mgr/InfoAction.h [new file with mode: 0644]
src/mgr/Inquirer.cc [new file with mode: 0644]
src/mgr/Inquirer.h [new file with mode: 0644]
src/mgr/IntervalAction.cc [new file with mode: 0644]
src/mgr/IntervalAction.h [new file with mode: 0644]
src/mgr/IoAction.cc [new file with mode: 0644]
src/mgr/IoAction.h [new file with mode: 0644]
src/mgr/Makefile.am [new file with mode: 0644]
src/mgr/Registration.cc [new file with mode: 0644]
src/mgr/Registration.h [new file with mode: 0644]
src/mgr/Request.cc [new file with mode: 0644]
src/mgr/Request.h [new file with mode: 0644]
src/mgr/Response.cc [new file with mode: 0644]
src/mgr/Response.h [new file with mode: 0644]
src/mgr/ServiceTimesAction.cc [new file with mode: 0644]
src/mgr/ServiceTimesAction.h [new file with mode: 0644]
src/mgr/StoreIoAction.cc [new file with mode: 0644]
src/mgr/StoreIoAction.h [new file with mode: 0644]
src/mgr/StoreToCommWriter.cc [new file with mode: 0644]
src/mgr/StoreToCommWriter.h [new file with mode: 0644]
src/mgr/forward.h [new file with mode: 0644]
src/neighbors.cc
src/pconn.cc
src/peer_sourcehash.cc
src/peer_userhash.cc
src/redirect.cc
src/refresh.cc
src/stat.cc
src/store.cc
src/store_digest.cc
src/store_io.cc
src/store_log.cc
src/structs.h
src/tests/stub_Port.cc [new file with mode: 0644]
src/tests/stub_TypedMsgHdr.cc [new file with mode: 0644]
src/tests/stub_UdsOp.cc [new file with mode: 0644]
src/tests/stub_cache_manager.cc
src/tests/stub_comm.cc
src/tests/stub_store_swapout.cc
src/tests/stub_tools.cc
src/tests/testCacheManager.cc
src/ufsdump.cc

index 62a7b02da7895e25faffbe449156264d1becd169..3e64fe0b15a342bb12efde44a5c3338a65176ef9 100644 (file)
@@ -3324,6 +3324,7 @@ AC_CONFIG_FILES([\
        src/ip/Makefile \
        src/log/Makefile \
        src/ipc/Makefile \
+       src/mgr/Makefile \
        contrib/Makefile \
        snmplib/Makefile \
        icons/Makefile \
index e3651325817610321a2abfa32dc9ad9dfbb492e0..77c0359a7220c5abe64cd34aa30d3771236f0468 100644 (file)
 #ifndef SQUID_CACHEMANAGER_H
 #define SQUID_CACHEMANAGER_H
 
-#include "squid.h"
-#include "Array.h"
+#include "mgr/Action.h"
+#include "mgr/ActionProfile.h"
+#include "mgr/Command.h"
+#include "mgr/forward.h"
+#include <vector>
 
 /**
  \defgroup CacheManagerAPI Cache Manager API
  \ingroup CacheManagerAPI
  */
 
-/**
- \ingroup CacheManagerInternal
- * The basic action handler. Its virtual method run(StoreEntry *) is invoked
- * to perform the actual action.
- */
-class CacheManagerAction
-{
-public:
-    virtual void run(StoreEntry *sentry) = 0;
-    char *action;
-    char *desc;
-    struct {
-        unsigned int pw_req:1;
-        unsigned int atomic:1;
-    } flags;
-    virtual ~CacheManagerAction();
-    CacheManagerAction(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic);
-
-};
-
-/**
- \ingroup CacheManagerInternal
- * wrapper allowing c-style callbacks to be used. Arguments are supposed to
- * managed by the caller.
- * This object is generated by CacheManager::registerAction
- */
-class CacheManagerActionLegacy : public CacheManagerAction
-{
-public:
-    OBJH *handler;
-    virtual void run (StoreEntry *sentry);
-    CacheManagerActionLegacy(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic, OBJH *aHandler);
-};
-
-
 /**
  \ingroup CacheManagerAPI
  * a CacheManager - the menu system for interacting with squid.
@@ -90,90 +58,39 @@ public:
  */
 class CacheManager
 {
-
 public:
-    /* the holy trinity - assignment, copy cons, destructor */
-    /* unimplemented - prevents bugs from synthetic */
-    CacheManager & operator = (CacheManager &);
-    /* unimplemented - prevents bugs from synthetic */
-    CacheManager(CacheManager const &);
-    /* inline so that we dont need to link in cachemgr.cc at all in tests */
-    virtual ~CacheManager() {}
-
-    void registerAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic);
-    void registerAction(CacheManagerAction *anAction);
-    CacheManagerAction * findAction(char const * action);
+    typedef std::vector<Mgr::ActionProfilePointer> Menu;
+
+    void registerProfile(char const * action, char const * desc,
+        OBJH * handler,
+        int pw_req_flag, int atomic);
+    void registerProfile(char const * action, char const * desc,
+        Mgr::ClassActionCreationHandler *handler,
+        int pw_req_flag, int atomic);
+    Mgr::ActionProfilePointer findAction(char const * action) const;
+    Mgr::Action::Pointer createNamedAction(const char *actionName);
+    Mgr::Action::Pointer createRequestedAction(const Mgr::ActionParams &);
+    const Menu& menu() const { return menu_; }
 
     void Start(int fd, HttpRequest * request, StoreEntry * entry);
 
     static CacheManager* GetInstance();
-    const char *ActionProtection(const CacheManagerAction * at);
+    const char *ActionProtection(const Mgr::ActionProfilePointer &profile);
 
 protected:
-    // command classes. They are private to the cachemanager, they
-    // may require access to local data, plus we avoid polluting
-    // the namespace more than needed.
-    class ShutdownAction : public CacheManagerAction
-    {
-    public:
-        virtual void run (StoreEntry *sentry);
-        ShutdownAction();
-    };
-    class ReconfigureAction : public CacheManagerAction
-    {
-    public:
-        virtual void run (StoreEntry *sentry);
-        ReconfigureAction();
-    };
-    class RotateAction : public CacheManagerAction
-    {
-    public:
-        virtual void run (StoreEntry *sentry);
-        RotateAction();
-    };
-    class OfflineToggleAction : public CacheManagerAction
-    {
-    public:
-        virtual void run (StoreEntry *sentry);
-        OfflineToggleAction();
-    };
-    class MenuAction : public CacheManagerAction
-    {
-    private:
-        //needs to reference the cachemgr in order to get to ActionsList
-        CacheManager *cmgr;
-    public:
-        virtual void run (StoreEntry *sentry);
-        MenuAction(CacheManager *);
-
-    };
+    CacheManager() {} ///< use Instance() instead
 
-    /// \ingroup CacheManagerInternal
-    typedef struct {
-        StoreEntry *entry;
-        char *action;
-        char *user_name;
-        char *passwd;
-    } cachemgrStateData;
-
-
-    CacheManager();
-    cachemgrStateData* ParseUrl(const char *url);
-    void ParseHeaders(cachemgrStateData * mgr, const HttpRequest * request);
-    int CheckPassword(cachemgrStateData * mgr);
+    Mgr::CommandPointer ParseUrl(const char *url);
+    void ParseHeaders(const HttpRequest * request, Mgr::ActionParams &params);
+    int CheckPassword(const Mgr::Command &cmd);
     char *PasswdGet(cachemgr_passwd *, const char *);
 
-    // \ingroup CacheManagerInternal
-    typedef Vector<CacheManagerAction *> CacheManagerActionList;
-    CacheManagerActionList ActionsList;
+    void registerProfile(const Mgr::ActionProfilePointer &profile);
 
+    Menu menu_;
 
 private:
     static CacheManager* instance;
-
-    void StateFree(cachemgrStateData * mgr);
-
-
 };
 
 #endif /* SQUID_CACHEMANAGER_H */
index d7377420601bc681697963982ce9e328b52e1105..4e482996d67a0a102bd59501930d02c95b75f5b0 100644 (file)
@@ -33,8 +33,9 @@
 
 #include "squid.h"
 #include "DiskDaemonDiskIOModule.h"
-#include "CacheManager.h"
 #include "DiskdIOStrategy.h"
+#include "DiskIO/DiskDaemon/DiskdAction.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 
 DiskDaemonDiskIOModule::DiskDaemonDiskIOModule() : initialised(false)
@@ -76,7 +77,7 @@ DiskDaemonDiskIOModule::init()
 void
 DiskDaemonDiskIOModule::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->registerAction("diskd", "DISKD Stats", Stats, 0, 1);
+    Mgr::RegisterAction("diskd", "DISKD Stats", &DiskdAction::Create, 0, 1);
 }
 
 void
@@ -93,31 +94,6 @@ DiskDaemonDiskIOModule::createStrategy()
 
 DiskDaemonDiskIOModule DiskDaemonDiskIOModule::Instance;
 
-void
-DiskDaemonDiskIOModule::Stats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "sent_count: %d\n", diskd_stats.sent_count);
-    storeAppendPrintf(sentry, "recv_count: %d\n", diskd_stats.recv_count);
-    storeAppendPrintf(sentry, "max_away: %d\n", diskd_stats.max_away);
-    storeAppendPrintf(sentry, "max_shmuse: %d\n", diskd_stats.max_shmuse);
-    storeAppendPrintf(sentry, "open_fail_queue_len: %d\n", diskd_stats.open_fail_queue_len);
-    storeAppendPrintf(sentry, "block_queue_len: %d\n", diskd_stats.block_queue_len);
-    diskd_stats.max_away = diskd_stats.max_shmuse = 0;
-    storeAppendPrintf(sentry, "\n              OPS   SUCCESS    FAIL\n");
-    storeAppendPrintf(sentry, "%7s %9d %9d %7d\n",
-                      "open", diskd_stats.open.ops, diskd_stats.open.success, diskd_stats.open.fail);
-    storeAppendPrintf(sentry, "%7s %9d %9d %7d\n",
-                      "create", diskd_stats.create.ops, diskd_stats.create.success, diskd_stats.create.fail);
-    storeAppendPrintf(sentry, "%7s %9d %9d %7d\n",
-                      "close", diskd_stats.close.ops, diskd_stats.close.success, diskd_stats.close.fail);
-    storeAppendPrintf(sentry, "%7s %9d %9d %7d\n",
-                      "unlink", diskd_stats.unlink.ops, diskd_stats.unlink.success, diskd_stats.unlink.fail);
-    storeAppendPrintf(sentry, "%7s %9d %9d %7d\n",
-                      "read", diskd_stats.read.ops, diskd_stats.read.success, diskd_stats.read.fail);
-    storeAppendPrintf(sentry, "%7s %9d %9d %7d\n",
-                      "write", diskd_stats.write.ops, diskd_stats.write.success, diskd_stats.write.fail);
-}
-
 char const *
 DiskDaemonDiskIOModule::type () const
 {
index 8ad3cf4bd030c7733400f8182f9317826b248639..0445d2a7184da1a7bf349ef51e2f3e1012294f3a 100644 (file)
@@ -48,7 +48,6 @@ public:
     virtual DiskIOStrategy* createStrategy();
 
 private:
-    static void Stats(StoreEntry * sentry);
     static DiskDaemonDiskIOModule Instance;
     bool initialised;
     void registerWithCacheManager(void);
diff --git a/src/DiskIO/DiskDaemon/DiskdAction.cc b/src/DiskIO/DiskDaemon/DiskdAction.cc
new file mode 100644 (file)
index 0000000..2e44af1
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 79    Squid-side DISKD I/O functions.
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "Store.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/ActionWriter.h"
+#include "DiskIO/DiskDaemon/DiskdAction.h"
+#include "DiskIO/DiskDaemon/DiskdIOStrategy.h"
+
+
+DiskdActionData::DiskdActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+DiskdActionData&
+DiskdActionData::operator += (const DiskdActionData& stats)
+{
+    sent_count += stats.sent_count;
+    recv_count += stats.recv_count;
+    if (stats.max_away > max_away)
+        max_away = stats.max_away;
+    if (stats.max_shmuse > max_shmuse)
+        max_shmuse += stats.max_shmuse;
+    open_fail_queue_len += stats.open_fail_queue_len;
+    block_queue_len += stats.block_queue_len;
+    open_ops += stats.open_ops;
+    open_success += stats.open_success;
+    open_fail += stats.open_fail;
+    create_ops += stats.create_ops;
+    create_success += stats.create_success;
+    create_fail += stats.create_fail;
+    close_ops += stats.close_ops;
+    close_success += stats.close_success;
+    close_fail += stats.close_fail;
+    unlink_ops += stats.unlink_ops;
+    unlink_success += stats.unlink_success;
+    unlink_fail += stats.unlink_fail;
+    read_ops += stats.read_ops;
+    read_success += stats.read_success;
+    read_fail += stats.read_fail;
+    write_ops += stats.write_ops;
+    write_success += stats.write_success;
+    write_fail += stats.write_fail;
+
+    return *this;
+}
+
+
+DiskdAction::Pointer
+DiskdAction::Create(const Mgr::CommandPointer &aCmd)
+{
+    return new DiskdAction(aCmd);
+}
+
+DiskdAction::DiskdAction(const Mgr::CommandPointer &aCmd):
+    Action(aCmd), data()
+{
+    debugs(79, 5, HERE);
+}
+
+void
+DiskdAction::add(const Action& action)
+{
+    debugs(79, 5, HERE);
+    data += dynamic_cast<const DiskdAction&>(action).data;
+}
+
+void
+DiskdAction::collect()
+{
+    data.sent_count = diskd_stats.sent_count;
+    data.recv_count = diskd_stats.recv_count;
+    data.max_away = diskd_stats.max_away;
+    data.max_shmuse = diskd_stats.max_shmuse;
+    data.open_fail_queue_len = diskd_stats.open_fail_queue_len;
+    data.block_queue_len = diskd_stats.block_queue_len;
+    diskd_stats.max_away = diskd_stats.max_shmuse = 0;
+
+    data.open_ops = diskd_stats.open.ops;
+    data.open_success = diskd_stats.open.success;
+    data.open_fail = diskd_stats.open.fail;
+
+    data.create_ops = diskd_stats.create.ops;
+    data.create_success = diskd_stats.create.success;
+    data.create_fail = diskd_stats.create.fail;
+
+    data.close_ops = diskd_stats.close.ops;
+    data.close_success = diskd_stats.close.success;
+    data.close_fail = diskd_stats.close.fail;
+
+    data.unlink_ops = diskd_stats.unlink.ops;
+    data.unlink_success = diskd_stats.unlink.success;
+    data.unlink_fail = diskd_stats.unlink.fail;
+
+    data.read_ops = diskd_stats.read.ops;
+    data.read_success = diskd_stats.read.success;
+    data.read_fail = diskd_stats.read.fail;
+
+    data.write_ops = diskd_stats.write.ops;
+    data.write_success = diskd_stats.write.success;
+    data.write_fail = diskd_stats.write.fail;
+}
+
+void
+DiskdAction::dump(StoreEntry* entry)
+{
+    debugs(79, 5, HERE);
+    Must(entry != NULL);
+    storeAppendPrintf(entry, "sent_count: %.0f\n", data.sent_count);
+    storeAppendPrintf(entry, "recv_count: %.0f\n", data.recv_count);
+    storeAppendPrintf(entry, "max_away: %.0f\n", data.max_away);
+    storeAppendPrintf(entry, "max_shmuse: %.0f\n", data.max_shmuse);
+    storeAppendPrintf(entry, "open_fail_queue_len: %.0f\n", data.open_fail_queue_len);
+    storeAppendPrintf(entry, "block_queue_len: %.0f\n", data.block_queue_len);
+    storeAppendPrintf(entry, "\n              OPS   SUCCESS    FAIL\n");
+    storeAppendPrintf(entry, "%7s %9.0f %9.0f %7.0f\n",
+                      "open", data.open_ops, data.open_success, data.open_fail);
+    storeAppendPrintf(entry, "%7s %9.0f %9.0f %7.0f\n",
+                      "create", data.create_ops, data.create_success, data.create_fail);
+    storeAppendPrintf(entry, "%7s %9.0f %9.0f %7.0f\n",
+                      "close", data.close_ops, data.close_success, data.close_fail);
+    storeAppendPrintf(entry, "%7s %9.0f %9.0f %7.0f\n",
+                      "unlink", data.unlink_ops, data.unlink_success, data.unlink_fail);
+    storeAppendPrintf(entry, "%7s %9.0f %9.0f %7.0f\n",
+                      "read", data.read_ops, data.read_success, data.read_fail);
+    storeAppendPrintf(entry, "%7s %9.0f %9.0f %7.0f\n",
+                      "write", data.write_ops, data.write_success, data.write_fail);
+}
+
+void
+DiskdAction::pack(Ipc::TypedMsgHdr& hdrMsg) const
+{
+    hdrMsg.setType(Ipc::mtCacheMgrResponse);
+    hdrMsg.putPod(data);
+}
+
+void
+DiskdAction::unpack(const Ipc::TypedMsgHdr& hdrMsg)
+{
+    hdrMsg.checkType(Ipc::mtCacheMgrResponse);
+    hdrMsg.getPod(data);
+}
diff --git a/src/DiskIO/DiskDaemon/DiskdAction.h b/src/DiskIO/DiskDaemon/DiskdAction.h
new file mode 100644 (file)
index 0000000..e950824
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 79    Squid-side DISKD I/O functions.
+ *
+ */
+
+#ifndef SQUID_DISKD_ACTION_H
+#define SQUID_DISKD_ACTION_H
+
+#include "ipc/forward.h"
+#include "mgr/forward.h"
+#include "mgr/Action.h"
+
+
+/// store disk daemon stats
+class DiskdActionData
+{
+public:
+    DiskdActionData();
+    DiskdActionData& operator += (const DiskdActionData& stats);
+
+public:
+    double sent_count;
+    double recv_count;
+    double max_away;
+    double max_shmuse;
+    double open_fail_queue_len;
+    double block_queue_len;
+    double open_ops;
+    double open_success;
+    double open_fail;
+    double create_ops;
+    double create_success;
+    double create_fail;
+    double close_ops;
+    double close_success;
+    double close_fail;
+    double unlink_ops;
+    double unlink_success;
+    double unlink_fail;
+    double read_ops;
+    double read_success;
+    double read_fail;
+    double write_ops;
+    double write_success;
+    double write_fail;
+};
+
+/// implement aggregated 'diskd' action
+class DiskdAction: public Mgr::Action
+{
+protected:
+    DiskdAction(const Mgr::CommandPointer &aCmd);
+
+public:
+    static Pointer Create(const Mgr::CommandPointer &aCmd);
+    /* Action API */
+    virtual void add(const Mgr::Action& action);
+    virtual void pack(Ipc::TypedMsgHdr& hdrMsg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& hdrMsg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    DiskdActionData data;
+};
+
+#endif /* SQUID_DISKD_ACTION_H */
index d2cc0fd6eecf4e91e1347ae53861386844826370..68461f5cb6668fe1cae343469b52dbede0c704a2 100644 (file)
 
 #include "squid.h"
 
-#include "CacheManager.h"
-#include "DiskThreadsIOStrategy.h"
 #include "DiskThreadsDiskFile.h"
+#include "DiskThreadsIOStrategy.h"
+#include "fde.h"
+#include "mgr/Registration.h"
 /* for statfs */
 #include "Store.h"
-#include "fde.h"
+
 
 void
 DiskThreadsIOStrategy::init(void)
@@ -65,8 +66,7 @@ DiskThreadsIOStrategy::init(void)
 void
 DiskThreadsIOStrategy::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("squidaio_counts", "Async IO Function Counters",
+    Mgr::RegisterAction("squidaio_counts", "Async IO Function Counters",
                    aioStats, 0, 1);
 }
 
index 4529de663c7aa6da177fb849f37dca4021181ed3..e191b56e6bdf0b85e3e392eefcd5d0e5098a02d8 100644 (file)
  */
 
 #include "squid.h"
-#include "CacheManager.h"
-#include "Store.h"
-#include "HttpHeader.h"
 #include "HttpHdrContRange.h"
 #include "HttpHdrSc.h"
+#include "HttpHeader.h"
 #include "MemBuf.h"
+#include "mgr/Registration.h"
+#include "Store.h"
 
 /*
  * On naming conventions:
@@ -283,8 +283,7 @@ static void httpHeaderStatDump(const HttpHeaderStat * hs, StoreEntry * e);
 static void
 httpHeaderRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("http_headers",
+    Mgr::RegisterAction("http_headers",
                    "HTTP Header Statistics",
                    httpHeaderStoreReport, 0, 1);
 }
index aecf5496323131630308892e82aa257c5a8b6508..eef3d09d50dde113199d6358649a061a600627ce 100644 (file)
@@ -39,7 +39,7 @@ LOADABLE_MODULES_SOURCES = \
        LoadableModules.h \
        LoadableModules.cc
 
-SUBDIRS        = base comm eui acl fs repl auth ip icmp ident log ipc
+SUBDIRS        = base comm eui acl fs repl auth ip icmp ident log ipc mgr
 
 if USE_ADAPTATION
 SUBDIRS += adaptation
@@ -173,7 +173,8 @@ COMMON_LIBS = \
        libsquid.la \
        ip/libip.la \
        fs/libfs.la \
-       ipc/libipc.la
+       ipc/libipc.la \
+       mgr/libmgr.la
 
 EXTRA_PROGRAMS = \
        DiskIO/DiskDaemon/diskd \
@@ -727,7 +728,9 @@ libDiskDaemon_a_SOURCES = \
                DiskIO/DiskDaemon/DiskdIOStrategy.h \
                DiskIO/DiskDaemon/diomsg.h \
                DiskIO/DiskDaemon/DiskDaemonDiskIOModule.cc \
-               DiskIO/DiskDaemon/DiskDaemonDiskIOModule.h
+               DiskIO/DiskDaemon/DiskDaemonDiskIOModule.h \
+               DiskIO/DiskDaemon/DiskdAction.cc \
+               DiskIO/DiskDaemon/DiskdAction.h
 
 libDiskThreads_a_SOURCES = \
                $(AIOPS_SOURCE) \
@@ -1295,7 +1298,10 @@ tests_testDiskIO_SOURCES = \
        tests/testDiskIO.h \
        tests/testMain.cc \
        tests/stub_cache_manager.cc \
-       tests/stub_HelperChildConfig.cc
+       tests/stub_HelperChildConfig.cc \
+       tests/stub_Port.cc \
+        tests/stub_TypedMsgHdr.cc \
+       tests/stub_UdsOp.cc
 nodist_tests_testDiskIO_SOURCES= \
        $(SWAP_TEST_GEN_SOURCES) \
        SquidMath.cc \
@@ -1307,6 +1313,8 @@ tests_testDiskIO_LDADD = \
        $(DISK_OS_LIBS) \
        $(COMMON_LIBS) \
        SquidConfig.o \
+       CommCalls.o \
+       DnsLookupDetails.o \
        $(XTRA_LIBS)
 
 tests_testDiskIO_LDFLAGS = $(LIBADD_DL)
@@ -2015,6 +2023,9 @@ tests_testStore_SOURCES= \
        tests/stub_HelperChildConfig.cc \
        tests/stub_HttpReply.cc \
        tests/stub_cache_manager.cc \
+       tests/stub_Port.cc \
+       tests/stub_TypedMsgHdr.cc \
+       tests/stub_UdsOp.cc \
        $(STORE_TEST_SOURCES) \
        tests/stub_fd.cc
 
@@ -2030,6 +2041,8 @@ tests_testStore_LDADD= \
        $(REGEXLIB) \
        $(SQUID_CPPUNIT_LIBS) \
        $(SSLLIB) \
+       CommCalls.o \
+       DnsLookupDetails.o \
        $(COMPAT_LIB) \
        $(XTRA_LIBS)
 tests_testStore_LDFLAGS = $(LIBADD_DL)
@@ -2123,6 +2136,9 @@ tests_testUfs_SOURCES = \
        tests/testUfs.h \
        tests/stub_cache_manager.cc \
        tests/stub_HelperChildConfig.cc \
+       tests/stub_Port.cc \
+       tests/stub_TypedMsgHdr.cc \
+       tests/stub_UdsOp.cc \
        $(SWAP_TEST_SOURCES)
 nodist_tests_testUfs_SOURCES = \
        $(SWAP_TEST_GEN_SOURCES) \
@@ -2133,6 +2149,8 @@ tests_testUfs_LDADD = \
        $(SWAP_TEST_LDADD) \
        $(COMMON_LIBS) \
        $(SSLLIB) \
+       CommCalls.o \
+       DnsLookupDetails.o \
        $(XTRA_LIBS)
 tests_testUfs_LDFLAGS = $(LIBADD_DL)
 tests_testUfs_DEPENDENCIES = \
index 8ea82a64d5d747462bd4190bd54158780850e557..fa671cf9a0996c5a167c0daa6d5c7b5994c366a9 100644 (file)
@@ -37,8 +37,8 @@
 
 #if USE_XPROF_STATS
 
-#include "CacheManager.h"
 #include "event.h"
+#include "mgr/Registration.h"
 #include "SquidMath.h"
 #include "Store.h"
 
@@ -270,8 +270,7 @@ xprof_chk_overhead(int samples)
 static void
 xprofRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("cpu_profile", "CPU Profiling Stats", xprof_summary, 0, 1);
+    Mgr::RegisterAction("cpu_profile", "CPU Profiling Stats", xprof_summary, 0, 1);
 }
 
 // FIXME:
index f08fa514a8f4087c51c99ebec1bd590fa44ed17a..af0f6b3e7713bb78161a85ca85167c7a31a595f4 100644 (file)
@@ -60,6 +60,18 @@ class MemObject;
 class Store;
 class StoreSearch;
 
+typedef struct {
+
+    struct {
+        int calls;
+        int select_fail;
+        int create_fail;
+        int success;
+    } create;
+} StoreIoStats;
+
+extern StoreIoStats store_io_stats;
+
 /**
  \ingroup StoreAPI
  */
index d5267898350058b7e58b36cb00c6b05a1c87b579..db1cb4064db5a70b24a7ec1607d9fe8191377019 100644 (file)
@@ -76,4 +76,12 @@ public:
     char *data;
 };
 
+inline
+std::ostream &
+operator <<(std::ostream &os, const StoreIOBuffer &b)
+{
+    return os << "ioBuf(@" << b.offset << ", len=" << b.length << ", " <<
+        (void*)b.data << (b.flags.error ? ", ERR" : "") << ')';
+}
+
 #endif /* SQUID_STOREIOBUFFER_H */
index 939a85912131ee21fe2ce2baa48972afeb474396..fa13917c6d3c517facad6d99fb557031f0f68c0f 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "squid.h"
 #include "base/TextException.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 
 int
@@ -280,7 +281,7 @@ ptrcmp(C const &lhs, C const &rhs)
 StringRegistry::StringRegistry()
 {
 #if DEBUGSTRINGS
-    CacheManager::GetInstance()->registerAction("strings",
+    Mgr::RegisterAction("strings",
             "Strings in use in squid", Stat, 0, 1);
 #endif
 }
index 8b6f8419d259869f71ac6d920d46556b20cbf4e3..552a2e9670eb2400f520b4813210d457a31ed99f 100644 (file)
@@ -34,7 +34,7 @@
  */
 
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "radix.h"
 #include "HttpRequest.h"
 #include "StoreClient.h"
@@ -189,7 +189,7 @@ ACLASN::prepareForUse()
 static void
 asnRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->registerAction("asndb", "AS Number Database", asnStats, 0, 1);
+    Mgr::RegisterAction("asndb", "AS Number Database", asnStats, 0, 1);
 }
 
 /* initialize the radix tree structure */
index 135c1c215748bcf3a4428c99a8522f8abbfd22fb..29271940c7f896bf0932a523a868c105d471515a 100644 (file)
@@ -43,7 +43,7 @@
 #include "auth/basic/basicUserRequest.h"
 #include "auth/Gadgets.h"
 #include "auth/State.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "HttpReply.h"
 #include "rfc1738.h"
@@ -544,8 +544,7 @@ AuthBasicConfig::init(AuthConfig * schemeCfg)
 void
 AuthBasicConfig::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("basicauthenticator",
+    Mgr::RegisterAction("basicauthenticator",
                    "Basic User Authenticator Stats",
                    authenticateBasicStats, 0, 1);
 }
index 6cafdfb8efbd50ecca860494d4774209952fb25b..8ff9b8025820e12e217bd918f9c9e4f54568f96c 100644 (file)
@@ -42,7 +42,7 @@
 #include "auth/digest/auth_digest.h"
 #include "auth/Gadgets.h"
 #include "event.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "HttpRequest.h"
 #include "HttpReply.h"
@@ -673,8 +673,7 @@ AuthDigestConfig::init(AuthConfig * scheme)
 void
 AuthDigestConfig::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("digestauthenticator",
+    Mgr::RegisterAction("digestauthenticator",
                    "Digest User Authenticator Stats",
                    authenticateDigestStats, 0, 1);
 }
index b3fe433b5a3786cb5283c83b43f2ccb9237be6fe..5fba97f60f5041c4292bada7c8701f574051ddbc 100644 (file)
@@ -41,7 +41,7 @@
 #include "auth/negotiate/auth_negotiate.h"
 #include "auth/Gadgets.h"
 #include "auth/State.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "client_side.h"
 #include "HttpReply.h"
@@ -200,8 +200,7 @@ AuthNegotiateConfig::init(AuthConfig * scheme)
 void
 AuthNegotiateConfig::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("negotiateauthenticator",
+    Mgr::RegisterAction("negotiateauthenticator",
                    "Negotiate User Authenticator Stats",
                    authenticateNegotiateStats, 0, 1);
 }
index d534cd472fa69d654bdb21dc94d231651cc1d0e9..d2c1802554b7ede242b2bda62b6f4e3f635cad06 100644 (file)
@@ -43,7 +43,7 @@
 #include "auth/ntlm/ntlmScheme.h"
 #include "auth/ntlm/ntlmUserRequest.h"
 #include "auth/State.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "client_side.h"
 #include "HttpReply.h"
@@ -186,8 +186,7 @@ AuthNTLMConfig::init(AuthConfig * scheme)
 void
 AuthNTLMConfig::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("ntlmauthenticator",
+    Mgr::RegisterAction("ntlmauthenticator",
                    "NTLM User Authenticator Stats",
                    authenticateNTLMStats, 0, 1);
 }
index 23434a1a1a0a092c37fa3062f5433d3a19a9d83f..380eec5817e3c6fbe00bf10afaa2539733b83f2e 100644 (file)
@@ -101,20 +101,20 @@ protected:
     virtual void doDial() { ((&(*this->job))->*method)(); }
 };
 
-template <class Job, class Argument1>
+template <class Job, class Data, class Argument1 = Data>
 class UnaryMemFunT: public JobDialer<Job>
 {
 public:
     typedef void (Job::*Method)(Argument1);
     explicit UnaryMemFunT(const CbcPointer<Job> &aJob, Method aMethod,
-                          const Argument1 &anArg1): JobDialer<Job>(aJob),
+                          const Data &anArg1): JobDialer<Job>(aJob),
             method(aMethod), arg1(anArg1) {}
 
     virtual void print(std::ostream &os) const {  os << '(' << arg1 << ')'; }
 
 public:
     Method method;
-    Argument1 arg1;
+    Data arg1;
 
 protected:
     virtual void doDial() { ((&(*this->job))->*method)(arg1); }
index 03602a75d859d6261d4723f0c16a5b153fb672e6..b7eb47addc51205090eace3c5e334f8a3944dfa7 100644 (file)
@@ -48,7 +48,6 @@
 #endif
 #include "auth/Config.h"
 #include "auth/Scheme.h"
-#include "CacheManager.h"
 #include "ConfigParser.h"
 #include "CpuAffinityMap.h"
 #include "eui/Config.h"
@@ -62,6 +61,7 @@
 #include "ip/tools.h"
 #include "log/Config.h"
 #include "MemBuf.h"
+#include "mgr/Registration.h"
 #include "Parsing.h"
 #include "ProtoPort.h"
 #include "rfc1738.h"
@@ -536,7 +536,6 @@ int
 parseConfigFile(const char *file_name)
 {
     int err_count = 0;
-    CacheManager *manager=CacheManager::GetInstance();
 
     debugs(5, 4, HERE);
 
@@ -564,7 +563,7 @@ parseConfigFile(const char *file_name)
     }
 
     if (opt_send_signal == -1) {
-        manager->registerAction("config",
+        Mgr::RegisterAction("config",
                                 "Current Squid Configuration",
                                 dump_config,
                                 1, 1);
index b8b72376ea567068e3aea9c89bda6ae13bda7fe7..b95f30b7a8bb5f3a1443270affb7b37145eb7efd 100644 (file)
  *
  */
 
+#include "config.h"
+#include "base/TextException.h"
 #include "CacheManager.h"
+#include "Debug.h"
 #include "errorpage.h"
+#include "fde.h"
 #include "HttpReply.h"
 #include "HttpRequest.h"
-#include "Store.h"
-#include "fde.h"
+#include "mgr/ActionCreator.h"
+#include "mgr/Action.h"
+#include "mgr/ActionProfile.h"
+#include "mgr/BasicActions.h"
+#include "mgr/Command.h"
+#include "mgr/Forwarder.h"
+#include "mgr/FunAction.h"
+#include "protos.h" /* rotate_logs() */
 #include "SquidTime.h"
+#include "Store.h"
 #include "wordlist.h"
-#include "Debug.h"
+#include <algorithm>
 
-// for rotate_logs()
-#include "protos.h"
 
 /// \ingroup CacheManagerInternal
 #define MGR_PASSWD_SZ 128
 
+/// creates Action using supplied Action::Create method and command
+class ClassActionCreator: public Mgr::ActionCreator
+{
+public:
+    typedef Mgr::Action::Pointer Handler(const Mgr::Command::Pointer &cmd);
 
-/**
- \ingroup CacheManagerInternals
- * Constructor. Its purpose is to register internal commands
- */
-CacheManager::CacheManager()
+public:
+    ClassActionCreator(Handler *aHandler): handler(aHandler) {}
+
+    virtual Mgr::Action::Pointer create(const Mgr::Command::Pointer &cmd) const
+    {
+        return handler(cmd);
+    }
+
+private:
+    Handler *handler;
+};
+
+
+/// Registers new profiles, ignoring attempts to register a duplicate
+void
+CacheManager::registerProfile(const Mgr::ActionProfile::Pointer &profile)
 {
-    registerAction(new OfflineToggleAction);
-    registerAction(new ShutdownAction);
-    registerAction(new ReconfigureAction);
-    registerAction(new RotateAction);
-    registerAction(new MenuAction(this));
+    Must(profile != NULL);
+    if (find(menu_.begin(), menu_.end(), profile) == menu_.end()) {
+        menu_.push_back(profile);
+        debugs(16, 3, HERE << "registered profile: " << *profile);
+    } else {
+        debugs(16, 2, HERE << "skipped duplicate profile: " << *profile);
+    }
 }
 
 /**
@@ -70,56 +97,69 @@ CacheManager::CacheManager()
  * Implemented via CacheManagerActionLegacy.
  */
 void
-CacheManager::registerAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
+CacheManager::registerProfile(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
 {
-    debugs(16, 3, "CacheManager::registerAction: registering legacy " <<  action);
-    registerAction(new CacheManagerActionLegacy(action,desc,pw_req_flag,atomic,handler));
+    debugs(16, 3, HERE << "registering legacy " << action);
+    const Mgr::ActionProfile::Pointer profile = new Mgr::ActionProfile(action,
+        desc, pw_req_flag, atomic, new Mgr::FunActionCreator(handler));
+    registerProfile(profile);
 }
 
-/**
- \ingroup CacheManagerAPI
- * Registers a C++-style action, via a poiner to a subclass of
- * a CacheManagerAction object, whose run() method will be invoked when
- * CacheManager identifies that the user has requested the action.
- */
 void
-CacheManager::registerAction(CacheManagerAction *anAction)
+CacheManager::registerProfile(char const * action, char const * desc,
+                             ClassActionCreator::Handler *handler,
+                             int pw_req_flag, int atomic)
 {
-    char *action = anAction->action;
-    if (findAction(action) != NULL) {
-        debugs(16, 2, "CacheManager::registerAction: Duplicate '" << action << "'. Skipping.");
-        return;
-    }
-
-    assert (strstr (" ", action) == NULL);
-
-    ActionsList += anAction;
-
-    debugs(16, 3, "CacheManager::registerAction: registered " <<  action);
+    const Mgr::ActionProfile::Pointer profile = new Mgr::ActionProfile(action,
+        desc, pw_req_flag, atomic, new ClassActionCreator(handler));
+    registerProfile(profile);
 }
 
-
 /**
  \ingroup CacheManagerInternal
  * Locates an action in the actions registry ActionsList.
 \retval NULL  if Action not found
 \retval CacheManagerAction* if the action was found
  */
-CacheManagerAction *
-CacheManager::findAction(char const * action)
+Mgr::ActionProfile::Pointer
+CacheManager::findAction(char const * action) const
 {
-    CacheManagerActionList::iterator a;
+    Must(action != NULL);
+    Menu::const_iterator a;
 
     debugs(16, 5, "CacheManager::findAction: looking for action " << action);
-    for ( a = ActionsList.begin(); a != ActionsList.end(); a++) {
-        if (0 == strcmp((*a)->action, action)) {
+    for (a = menu_.begin(); a != menu_.end(); ++a) {
+        if (0 == strcmp((*a)->name, action)) {
             debugs(16, 6, " found");
             return *a;
         }
     }
 
     debugs(16, 6, "Action not found.");
-    return NULL;
+    return Mgr::ActionProfilePointer();
+}
+
+Mgr::Action::Pointer
+CacheManager::createNamedAction(const char *actionName)
+{
+    Must(actionName);
+
+    Mgr::Command::Pointer cmd = new Mgr::Command;
+    cmd->profile = findAction(actionName);
+    cmd->params.actionName = actionName;
+
+    Must(cmd->profile != NULL);
+    return cmd->profile->creator->create(cmd);
+}
+
+Mgr::Action::Pointer
+CacheManager::createRequestedAction(const Mgr::ActionParams &params)
+{
+    Mgr::Command::Pointer cmd = new Mgr::Command;
+    cmd->params = params;
+    cmd->profile = findAction(params.actionName.termedBuf());
+    Must(cmd->profile != NULL);
+    return cmd->profile->creator->create(cmd);
 }
 
 /**
@@ -130,51 +170,47 @@ CacheManager::findAction(char const * action)
  \retval CacheManager::cachemgrStateData state object for the following handling
  \retval NULL if the action can't be found or can't be accessed by the user
  */
-CacheManager::cachemgrStateData *
+Mgr::Command::Pointer
 CacheManager::ParseUrl(const char *url)
 {
     int t;
     LOCAL_ARRAY(char, host, MAX_URL);
     LOCAL_ARRAY(char, request, MAX_URL);
     LOCAL_ARRAY(char, password, MAX_URL);
-    CacheManagerAction *a;
-    cachemgrStateData *mgr = NULL;
-    const char *prot;
     t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
 
-    if (t < 2) {
+    if (t < 2)
         xstrncpy(request, "menu", MAX_URL);
+
 #ifdef _SQUID_OS2_
+    if (t == 2 && request[0] == '\0') {
         /*
          * emx's sscanf insists of returning 2 because it sets request
          * to null
          */
-    } else if (request[0] == '\0') {
         xstrncpy(request, "menu", MAX_URL);
+    }
 #endif
 
-    } else if ((a = findAction(request)) == NULL) {
+    Mgr::ActionProfile::Pointer profile = findAction(request);
+    if (!profile) {
         debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' not found");
         return NULL;
-    } else {
-        prot = ActionProtection(a);
-
-        if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
-            debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' is " << prot);
-            return NULL;
-        }
     }
 
-    /* set absent entries to NULL so we can test if they are present later */
-    mgr = (cachemgrStateData *)xcalloc(1, sizeof(cachemgrStateData));
-
-    mgr->user_name = NULL;
-
-    mgr->passwd = t == 3 ? xstrdup(password) : NULL;
-
-    mgr->action = xstrdup(request);
+    const char *prot = ActionProtection(profile);
+    if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
+        debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' is " << prot);
+        return NULL;
+    }
 
-    return mgr;
+    Mgr::Command::Pointer cmd = new Mgr::Command;
+    cmd->profile = profile;
+    cmd->params.httpUri = url;
+    cmd->params.userName = String();
+    cmd->params.password = t == 3 ? String(password) : String();
+    cmd->params.actionName = request;
+    return cmd;
 }
 
 /// \ingroup CacheManagerInternal
@@ -184,11 +220,15 @@ CacheManager::ParseUrl(const char *url)
  * the details into the cachemgrStateData argument
  */
 void
-CacheManager::ParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
+CacheManager::ParseHeaders(const HttpRequest * request, Mgr::ActionParams &params)
 {
     const char *basic_cookie;  /* base 64 _decoded_ user:passwd pair */
     const char *passwd_del;
-    assert(mgr && request);
+    assert(request);
+
+    params.httpMethod = request->method.id();
+    params.httpFlags = request->flags;
+
     basic_cookie = request->header.getAuth(HDR_AUTHORIZATION, "Basic");
 
     if (!basic_cookie)
@@ -200,18 +240,12 @@ CacheManager::ParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
     }
 
     /* found user:password pair, reset old values */
-    safe_free(mgr->user_name);
-
-    safe_free(mgr->passwd);
-
-    mgr->user_name = xstrdup(basic_cookie);
-
-    mgr->user_name[passwd_del - basic_cookie] = '\0';
-
-    mgr->passwd = xstrdup(passwd_del + 1);
+    params.userName.limitInit(basic_cookie, passwd_del - basic_cookie);
+    params.password = passwd_del + 1;
 
     /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
-    debugs(16, 9, "CacheManager::ParseHeaders: got user: '" << mgr->user_name << "' passwd: '" << mgr->passwd << "'");
+    debugs(16, 9, "CacheManager::ParseHeaders: got user: '" <<
+        params.userName << "' passwd: '" << params.password << "'");
 }
 
 /**
@@ -222,16 +256,16 @@ CacheManager::ParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
  \retval !0    if mgr->password does not match configured password
  */
 int
-CacheManager::CheckPassword(cachemgrStateData * mgr)
+CacheManager::CheckPassword(const Mgr::Command &cmd)
 {
-    char *pwd = PasswdGet(Config.passwd_list, mgr->action);
-    CacheManagerAction *a = findAction(mgr->action);
+    assert(cmd.profile != NULL);
+    const char *action = cmd.profile->name;
+    char *pwd = PasswdGet(Config.passwd_list, action);
 
-    debugs(16, 4, "CacheManager::CheckPassword for action " << mgr->action);
-    assert(a != NULL);
+    debugs(16, 4, "CacheManager::CheckPassword for action " << action);
 
     if (pwd == NULL)
-        return a->flags.pw_req;
+        return cmd.profile->isPwReq;
 
     if (strcmp(pwd, "disable") == 0)
         return 1;
@@ -239,21 +273,10 @@ CacheManager::CheckPassword(cachemgrStateData * mgr)
     if (strcmp(pwd, "none") == 0)
         return 0;
 
-    if (!mgr->passwd)
+    if (!cmd.params.password.size())
         return 1;
 
-    return strcmp(pwd, mgr->passwd);
-}
-
-/// \ingroup CacheManagerInternal
-void
-CacheManager::StateFree(cachemgrStateData * mgr)
-{
-    safe_free(mgr->action);
-    safe_free(mgr->user_name);
-    safe_free(mgr->passwd);
-    mgr->entry->unlock();
-    xfree(mgr);
+    return cmd.params.password != pwd;
 }
 
 /**
@@ -265,12 +288,11 @@ CacheManager::StateFree(cachemgrStateData * mgr)
 void
 CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
 {
-    cachemgrStateData *mgr = NULL;
     ErrorState *err = NULL;
-    CacheManagerAction *a;
     debugs(16, 3, "CacheManager::Start: '" << entry->url() << "'" );
 
-    if ((mgr = ParseUrl(entry->url())) == NULL) {
+    Mgr::Command::Pointer cmd = ParseUrl(entry->url());
+    if (!cmd) {
         err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND, request);
         err->url = xstrdup(entry->url());
         errorAppendEntry(entry, err);
@@ -278,45 +300,48 @@ CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
         return;
     }
 
-    mgr->entry = entry;
+    const char *actionName = cmd->profile->name;
 
-    entry->lock();
     entry->expires = squid_curtime;
 
-    debugs(16, 5, "CacheManager: " << fd_table[fd].ipaddr << " requesting '" << mgr->action << "'");
+    debugs(16, 5, "CacheManager: " << fd_table[fd].ipaddr << " requesting '" << actionName << "'");
 
     /* get additional info from request headers */
-    ParseHeaders(mgr, request);
+    ParseHeaders(request, cmd->params);
+
+    const char *userName = cmd->params.userName.size() ?
+        cmd->params.userName.termedBuf() : "unknown";
 
     /* Check password */
 
-    if (CheckPassword(mgr) != 0) {
+    if (CheckPassword(*cmd) != 0) {
         /* build error message */
         ErrorState *errState;
         HttpReply *rep;
         errState = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED, request);
         /* warn if user specified incorrect password */
 
-        if (mgr->passwd)
+        if (cmd->params.password.size()) {
             debugs(16, DBG_IMPORTANT, "CacheManager: " <<
-                   (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
+                   userName << "@" <<
                    fd_table[fd].ipaddr << ": incorrect password for '" <<
-                   mgr->action << "'" );
-        else
+                   actionName << "'" );
+        } else {
             debugs(16, DBG_IMPORTANT, "CacheManager: " <<
-                   (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
+                   userName << "@" <<
                    fd_table[fd].ipaddr << ": password needed for '" <<
-                   mgr->action << "'" );
+                   actionName << "'" );
+        }
 
         rep = errState->BuildHttpReply();
 
         errorStateFree(errState);
 
         /*
-         * add Authenticate header, use 'action' as a realm because
-         * password depends on action
+         * add Authenticate header using action name as a realm because
+         * password depends on the action
          */
-        rep->header.putAuth("Basic", mgr->action);
+        rep->header.putAuth("Basic", actionName);
 
         /* store the reply */
         entry->replaceHttpReply(rep);
@@ -325,84 +350,23 @@ CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
 
         entry->complete();
 
-        StateFree(mgr);
-
         return;
     }
 
     debugs(16, 2, "CacheManager: " <<
-           (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
+           userName << "@" <<
            fd_table[fd].ipaddr << " requesting '" <<
-           mgr->action << "'" );
-    /* retrieve object requested */
-    a = findAction(mgr->action);
-    assert(a != NULL);
+           actionName << "'" );
 
-    entry->buffer();
-
-    {
-        HttpReply *rep = new HttpReply;
-        rep->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
-        entry->replaceHttpReply(rep);
+    if (UsingSmp() && IamWorkerProcess()) {
+        AsyncJob::Start(new Mgr::Forwarder(fd, cmd->params, request, entry));
+        return;
     }
 
-    a->run(entry);
-
-    entry->flush();
-
-    if (a->flags.atomic)
-        entry->complete();
-
-    StateFree(mgr);
-}
-
-/// \ingroup CacheManagerInternal
-void CacheManager::ShutdownAction::run(StoreEntry *sentry)
-{
-    debugs(16, DBG_CRITICAL, "Shutdown by Cache Manager command.");
-    shut_down(0);
-}
-/// \ingroup CacheManagerInternal
-CacheManager::ShutdownAction::ShutdownAction() : CacheManagerAction("shutdown","Shut Down the Squid Process", 1, 1) { }
-
-/// \ingroup CacheManagerInternal
-void
-CacheManager::ReconfigureAction::run(StoreEntry * sentry)
-{
-    debugs(16, DBG_IMPORTANT, "Reconfigure by Cache Manager command.");
-    storeAppendPrintf(sentry, "Reconfiguring Squid Process ....");
-    reconfigure(SIGHUP);
-}
-/// \ingroup CacheManagerInternal
-CacheManager::ReconfigureAction::ReconfigureAction() : CacheManagerAction("reconfigure","Reconfigure Squid", 1, 1) { }
-
-/// \ingroup CacheManagerInternal
-void
-CacheManager::RotateAction::run(StoreEntry * sentry)
-{
-    debugs(16, DBG_IMPORTANT, "Rotate Logs by Cache Manager command.");
-    storeAppendPrintf(sentry, "Rotating Squid Process Logs ....");
-#ifdef _SQUID_LINUX_THREADS_
-    rotate_logs(SIGQUIT);
-#else
-    rotate_logs(SIGUSR1);
-#endif
-}
-/// \ingroup CacheManagerInternal
-CacheManager::RotateAction::RotateAction() : CacheManagerAction("rotate","Rotate Squid Logs", 1, 1) { }
-
-/// \ingroup CacheManagerInternal
-void
-CacheManager::OfflineToggleAction::run(StoreEntry * sentry)
-{
-    Config.onoff.offline = !Config.onoff.offline;
-    debugs(16, DBG_IMPORTANT, "offline_mode now " << (Config.onoff.offline ? "ON" : "OFF") << " by Cache Manager request.");
-
-    storeAppendPrintf(sentry, "offline_mode is now %s\n",
-                      Config.onoff.offline ? "ON" : "OFF");
+    Mgr::Action::Pointer action = cmd->profile->creator->create(cmd);
+    Must(action != NULL);
+    action->run(entry, true);
 }
-/// \ingroup CacheManagerInternal
-CacheManager::OfflineToggleAction::OfflineToggleAction() : CacheManagerAction ("offline_toggle", "Toggle offline_mode setting", 1, 1) { }
 
 /*
  \ingroup CacheManagerInternal
@@ -410,14 +374,13 @@ CacheManager::OfflineToggleAction::OfflineToggleAction() : CacheManagerAction ("
  * Also doubles as a check for the protection level.
  */
 const char *
-CacheManager::ActionProtection(const CacheManagerAction * at)
+CacheManager::ActionProtection(const Mgr::ActionProfile::Pointer &profile)
 {
-    char *pwd;
-    assert(at);
-    pwd = PasswdGet(Config.passwd_list, at->action);
+    assert(profile != NULL);
+    const char *pwd = PasswdGet(Config.passwd_list, profile->name);
 
     if (!pwd)
-        return at->flags.pw_req ? "hidden" : "public";
+        return profile->isPwReq ? "hidden" : "public";
 
     if (!strcmp(pwd, "disable"))
         return "disabled";
@@ -428,22 +391,6 @@ CacheManager::ActionProtection(const CacheManagerAction * at)
     return "protected";
 }
 
-/// \ingroup CacheManagerInternal
-void
-CacheManager::MenuAction::run(StoreEntry * sentry)
-{
-    CacheManagerActionList::iterator a;
-
-    debugs(16, 4, "CacheManager::MenuCommand invoked");
-    for (a = cmgr->ActionsList.begin(); a != cmgr->ActionsList.end(); ++a) {
-        debugs(16, 5, "  showing action " << (*a)->action);
-        storeAppendPrintf(sentry, " %-22s\t%-32s\t%s\n",
-                          (*a)->action, (*a)->desc, cmgr->ActionProtection(*a));
-    }
-}
-/// \ingroup CacheManagerInternal
-CacheManager::MenuAction::MenuAction(CacheManager *aMgr) : CacheManagerAction ("menu", "Cache Manager Menu", 0, 1), cmgr(aMgr) { }
-
 /*
  \ingroup CacheManagerInternal
  * gets from the global Config the password the user would need to supply
@@ -481,32 +428,7 @@ CacheManager::GetInstance()
     if (instance == 0) {
         debugs(16, 6, "CacheManager::GetInstance: starting cachemanager up");
         instance = new CacheManager;
+        Mgr::RegisterBasics();
     }
     return instance;
 }
-
-
-/// \ingroup CacheManagerInternal
-void CacheManagerActionLegacy::run(StoreEntry *sentry)
-{
-    handler(sentry);
-}
-/// \ingroup CacheManagerInternal
-CacheManagerAction::CacheManagerAction(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic)
-{
-    flags.pw_req = isPwReq;
-    flags.atomic = isAtomic;
-    action = xstrdup (anAction);
-    desc = xstrdup (aDesc);
-}
-/// \ingroup CacheManagerInternal
-CacheManagerAction::~CacheManagerAction()
-{
-    xfree(action);
-    xfree(desc);
-}
-
-/// \ingroup CacheManagerInternal
-CacheManagerActionLegacy::CacheManagerActionLegacy(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic, OBJH *aHandler) : CacheManagerAction(anAction, aDesc, isPwReq, isAtomic), handler(aHandler)
-{
-}
index 65bec9db0551bb3737cf4fad9673f5ef5d3651a3..f5f6f3624a2e532c18fdb45d2ae46bf0c11c906c 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 
 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
@@ -55,8 +55,7 @@ peerSortWeight(const void *a, const void *b)
 static void
 carpRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("carp", "CARP information", carpCachemgr, 0, 1);
+    Mgr::RegisterAction("carp", "CARP information", carpCachemgr, 0, 1);
 }
 
 void
index 300b27733139769aee09cfc85e7ce2dd4ab688ec..cd4ce8f998d07d660e9292cee950625b563c5db0 100644 (file)
@@ -49,7 +49,7 @@
  */
 
 #include "cbdata.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #if CBDATA_DEBUG
 #include "Stack.h"
@@ -271,13 +271,12 @@ cbdataInternalAddType(cbdata_type type, const char *name, int size, FREE * free_
 void
 cbdataRegisterWithCacheManager(void)
 {
-    CacheManager *manager=CacheManager::GetInstance();
-    manager->registerAction("cbdata",
+    Mgr::RegisterAction("cbdata",
                             "Callback Data Registry Contents",
                             cbdataDump, 0, 1);
 #if CBDATA_DEBUG
 
-    manager->registerAction("cbdatahistory",
+    Mgr::RegisterAction("cbdatahistory",
                             "Detailed call history for all current cbdata contents",
                             cbdataDumpHistory, 0, 1);
 #endif
index aec780da227ebd7746ef22299f74a57f2a9531f7..89668cd21e9b9eea43f296253e7502c8ffed56b6 100644 (file)
@@ -34,9 +34,9 @@
 
 #include "squid.h"
 #include "event.h"
-#include "CacheManager.h"
 #include "ClientInfo.h"
 #include "ip/Address.h"
+#include "mgr/Registration.h"
 #include "SquidMath.h"
 #include "SquidTime.h"
 #include "Store.h"
@@ -104,8 +104,7 @@ clientdbAdd(const Ip::Address &addr)
 static void
 clientdbRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("client_list", "Cache Client List", clientdbDump, 0, 1);
+    Mgr::RegisterAction("client_list", "Cache Client List", clientdbDump, 0, 1);
 }
 
 void
index 56ee42f82f8d3d04435740bd8e4054410597d2c0..e5337203f994e0f32e29e8bff652a5ef03263057 100644 (file)
@@ -53,7 +53,7 @@
 
 #include "squid.h"
 #include "comm_epoll.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "fde.h"
 #include "SquidTime.h"
@@ -221,8 +221,7 @@ static void commIncomingStats(StoreEntry * sentry);
 static void
 commEPollRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("comm_epoll_incoming",
+    Mgr::RegisterAction("comm_epoll_incoming",
                    "comm_incoming() stats",
                    commIncomingStats, 0, 1);
 }
index e420c4f0b9670c0ce0939ee47f267f27fad5d619..70b94ddeba1fc7a4a33990b75b9db893c39dcdd4 100644 (file)
@@ -58,7 +58,6 @@
 #if USE_KQUEUE
 
 #include "comm_kqueue.h"
-#include "CacheManager.h"
 #include "Store.h"
 #include "fde.h"
 #include "SquidTime.h"
index 53325aeb19e84e601dd5d40235665e8055caaec3..bb48aa7cbd10bc27b02a20b191cde70930caba95 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "squid.h"
 #include "comm_poll.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "fde.h"
@@ -625,8 +625,7 @@ comm_poll_dns_incoming(void)
 static void
 commPollRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("comm_poll_incoming",
+    Mgr::RegisterAction("comm_poll_incoming",
                    "comm_incoming() stats",
                    commIncomingStats, 0, 1);
 }
index 4b74b7e8dc4d99ab765cce1b10af9c7c7666acdc..29f80fa9f8eeff476632130fb68810475090220f 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "squid.h"
 #include "comm_select.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "SquidTime.h"
 
 #if USE_SELECT
@@ -663,8 +663,7 @@ comm_select_dns_incoming(void)
 static void
 commSelectRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("comm_select_incoming",
+    Mgr::RegisterAction("comm_select_incoming",
                    "comm_incoming() stats",
                    commIncomingStats, 0, 1);
 }
index d436f9421f4aa0036a37daa5cce65d21b5567566..cbafca9ab394af43d82a578651f40bc1a147997f 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "squid.h"
 #include "comm_select.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "SquidTime.h"
 
 #if USE_SELECT_WIN32
@@ -685,8 +685,7 @@ comm_select_dns_incoming(void)
 static void
 commSelectRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("comm_select_incoming",
+    Mgr::RegisterAction("comm_select_incoming",
                    "comm_incoming() stats",
                    commIncomingStats, 0, 1);
 }
index 73913fa0ecb140dbac76f33cf88847e064e5dd29..82fda98d0e23c9eefb0712c1ac321e696f5f7bad 100644 (file)
@@ -43,7 +43,7 @@
 
 #if DELAY_POOLS
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "DelaySpec.h"
 #include "DelayPools.h"
 #include "event.h"
@@ -543,8 +543,7 @@ unsigned short DelayPools::pools_ (0);
 void
 DelayPools::RegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("delay", "Delay Pool Levels", Stats, 0, 1);
+    Mgr::RegisterAction("delay", "Delay Pool Levels", Stats, 0, 1);
 }
 
 void
index db050e635246ee075a86055f2f8aafbf209e8abc..1935cee427c0c22253e3792e1ae1aded075d677e 100644 (file)
@@ -37,7 +37,7 @@
 #include "Store.h"
 #include "wordlist.h"
 #include "SquidTime.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "helper.h"
 
 /* MS VisualStudio Projects are monolitich, so we need the following
@@ -58,8 +58,7 @@ dnsStats(StoreEntry * sentry)
 static void
 dnsRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("dns", "Dnsserver Statistics", dnsStats, 0, 1);
+    Mgr::RegisterAction("dns", "Dnsserver Statistics", dnsStats, 0, 1);
 }
 
 void
index 7fd523551505a60d28fee20d587a0c468cdefe26..91cf3523760ca14455422167474e736865dd8701 100644 (file)
 #include "config.h"
 #include "squid.h"
 #include "event.h"
-#include "CacheManager.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "comm.h"
 #include "fde.h"
 #include "ip/tools.h"
 #include "MemBuf.h"
+#include "mgr/Registration.h"
 #include "util.h"
 #include "wordlist.h"
 
@@ -1432,8 +1432,7 @@ idnsRcodeCount(int rcode, int attempt)
 static void
 idnsRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
+    Mgr::RegisterAction("idns", "Internal DNS Statistics", idnsStats, 0, 1);
 }
 
 void
index dd0057884dfd138d3639c2351ec01d40fe2cf57a..66bd0432b2b8a1d6f370d52291af15e70a843640 100644 (file)
@@ -34,8 +34,8 @@
 
 #include "config.h"
 #include "compat/drand48.h"
-#include "CacheManager.h"
 #include "event.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "SquidTime.h"
 
@@ -154,8 +154,7 @@ eventDelete(EVH * func, void *arg)
 void
 eventInit(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("events", "Event Queue", eventDump, 0, 1);
+    Mgr::RegisterAction("events", "Event Queue", eventDump, 0, 1);
 }
 
 static void
index 5808ec5ca757f5f480cd5558ec7b7747873a915b..9a6182251a9c81bebadfdcf602dc6883ff1ec440 100644 (file)
@@ -41,7 +41,7 @@
  */
 
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "ExternalACL.h"
 #include "ExternalACLEntry.h"
 #include "auth/UserRequest.h"
@@ -1420,8 +1420,7 @@ externalAclStats(StoreEntry * sentry)
 static void
 externalAclRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("external_acl",
+    Mgr::RegisterAction("external_acl",
                    "External ACL stats",
                    externalAclStats, 0, 1);
 }
index 6e0a46be09812c149c411ee30ecd544631b9c385..3be71918389bb803723d4afaf61e195cf8a2f6e3 100644 (file)
@@ -50,6 +50,7 @@
 #include "icmp/net_db.h"
 #include "ip/Intercept.h"
 #include "ip/tools.h"
+#include "mgr/Registration.h"
 
 static PSC fwdStartCompleteWrapper;
 static PF fwdServerClosedWrapper;
@@ -1280,8 +1281,7 @@ FwdState::initModule()
 void
 FwdState::RegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
+    Mgr::RegisterAction("forward", "Request Forwarding Statistics", fwdStats, 0, 1);
 }
 
 void
index f00da301d6c9e5eeeded7f02aaca4434651076b1..b7344d8cbcf9011ed1b37f2f827cbca64afdccb5 100644 (file)
@@ -35,7 +35,7 @@
 #include "squid.h"
 #include "cbdata.h"
 #include "event.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "wordlist.h"
@@ -586,8 +586,7 @@ fqdncache_nbgethostbyaddr(const Ip::Address &addr, FQDNH * handler, void *handle
 static void
 fqdncacheRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("fqdncache", "FQDN Cache Stats and Contents",
+    Mgr::RegisterAction("fqdncache", "FQDN Cache Stats and Contents",
                    fqdnStats, 0, 1);
 
 }
index fed69cb180bc1a53f8767f94b463c5b8fcd3b4b0..5367bc67d381e8a5fdcc99f3b499ebebd45b3dad 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "StoreFileSystem.h"
 #include "StoreFScoss.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "CossSwapDir.h"
 #include "store_coss.h"
@@ -86,7 +86,7 @@ StoreFScoss::setup()
 void
 StoreFScoss::registerWithCacheManager()
 {
-    CacheManager::GetInstance()->registerAction("coss", "COSS Stats", Stats, 0, 1);
+    Mgr::RegisterAction("coss", "COSS Stats", Stats, 0, 1);
 }
 
 void
index 836a4eee3a33ffab0296a69034b4b684a2a285ab..016800d80761c45b90af3a7350e414e0e3ffb16f 100644 (file)
@@ -43,7 +43,7 @@
 #include "log/File.h"
 #include "cbdata.h"
 #include "event.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "SwapDir.h"
 #include "HttpRequest.h"
@@ -882,8 +882,7 @@ netdbExchangeDone(void *data)
 static void
 netdbRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("netdb", "Network Measurement Database", netdbDump, 0, 1);
+    Mgr::RegisterAction("netdb", "Network Measurement Database", netdbDump, 0, 1);
 }
 
 #endif /* USE_ICMP */
index 0f2eac99757a924859f61364d9bf3332777f072a..02c66fd1b5ec9ac5ed878cc63276556fde316e03 100644 (file)
@@ -7,10 +7,16 @@
 
 
 #include "config.h"
+#include "base/TextException.h"
+#include "CacheManager.h"
 #include "comm.h"
 #include "ipc/Coordinator.h"
 #include "ipc/FdNotes.h"
 #include "ipc/SharedListen.h"
+#include "mgr/Inquirer.h"
+#include "mgr/Request.h"
+#include "mgr/Response.h"
+#include "mgr/StoreToCommWriter.h"
 
 
 CBDATA_NAMESPACED_CLASS_INIT(Ipc, Coordinator);
@@ -29,8 +35,8 @@ void Ipc::Coordinator::start()
 
 Ipc::StrandCoord* Ipc::Coordinator::findStrand(int kidId)
 {
-    typedef Strands::iterator SI;
-    for (SI iter = strands.begin(); iter != strands.end(); ++iter) {
+    typedef StrandCoords::iterator SI;
+    for (SI iter = strands_.begin(); iter != strands_.end(); ++iter) {
         if (iter->kidId == kidId)
             return &(*iter);
     }
@@ -42,7 +48,7 @@ void Ipc::Coordinator::registerStrand(const StrandCoord& strand)
     if (StrandCoord* found = findStrand(strand.kidId))
         *found = strand;
     else
-        strands.push_back(strand);
+        strands_.push_back(strand);
 }
 
 void Ipc::Coordinator::receive(const TypedMsgHdr& message)
@@ -58,6 +64,16 @@ void Ipc::Coordinator::receive(const TypedMsgHdr& message)
         handleSharedListenRequest(SharedListenRequest(message));
         break;
 
+    case mtCacheMgrRequest:
+        debugs(54, 6, HERE << "Cache manager request");
+        handleCacheMgrRequest(Mgr::Request(message));
+        break;
+
+    case mtCacheMgrResponse:
+        debugs(54, 6, HERE << "Cache manager response");
+        handleCacheMgrResponse(Mgr::Response(message));
+        break;
+
     default:
         debugs(54, 1, HERE << "Unhandled message type: " << message.type());
         break;
@@ -94,6 +110,29 @@ Ipc::Coordinator::handleSharedListenRequest(const SharedListenRequest& request)
     SendMessage(MakeAddr(strandAddrPfx, request.requestorId), message);
 }
 
+void
+Ipc::Coordinator::handleCacheMgrRequest(const Mgr::Request& request)
+{
+    debugs(54, 4, HERE);
+
+    // Let the strand know that we are now responsible for handling the request
+    Mgr::Response response(request.requestId);
+    TypedMsgHdr message;
+    response.pack(message);
+    SendMessage(MakeAddr(strandAddrPfx, request.requestorId), message);
+
+    Mgr::Action::Pointer action =
+        CacheManager::GetInstance()->createRequestedAction(request.params);
+    AsyncJob::Start(new Mgr::Inquirer(action,
+        Mgr::ImportHttpFdIntoComm(request.fd), request, strands_));
+}
+
+void
+Ipc::Coordinator::handleCacheMgrResponse(const Mgr::Response& response)
+{
+    Mgr::Inquirer::HandleRemoteAck(response);
+}
+
 int
 Ipc::Coordinator::openListenSocket(const SharedListenRequest& request,
                                    int &errNo)
@@ -120,8 +159,8 @@ Ipc::Coordinator::openListenSocket(const SharedListenRequest& request,
 
 void Ipc::Coordinator::broadcastSignal(int sig) const
 {
-    typedef Strands::const_iterator SCI;
-    for (SCI iter = strands.begin(); iter != strands.end(); ++iter) {
+    typedef StrandCoords::const_iterator SCI;
+    for (SCI iter = strands_.begin(); iter != strands_.end(); ++iter) {
         debugs(54, 5, HERE << "signal " << sig << " to kid" << iter->kidId <<
                ", PID=" << iter->pid);
         kill(iter->pid, sig);
@@ -137,3 +176,9 @@ Ipc::Coordinator* Ipc::Coordinator::Instance()
     // Strands do not re-register, even process death would be pointless.
     return TheInstance;
 }
+
+const Ipc::StrandCoords&
+Ipc::Coordinator::strands() const
+{
+    return strands_;
+}
index f508205eb0c33c97a6f1203b5a92e56316bc1378..11856b1d3e2d0f7a0ca956668bab6d4c988e7682 100644 (file)
 
 
 #include "Array.h"
-#include <map>
-#include "ipc/Port.h"
 #include "ipc/Messages.h"
+#include "ipc/Port.h"
 #include "ipc/SharedListen.h"
+#include "ipc/StrandCoords.h"
+#include "mgr/forward.h"
+
+#include <map>
 
 namespace Ipc
 {
@@ -29,6 +32,8 @@ public:
 
     void broadcastSignal(int sig) const; ///< send sig to registered strands
 
+    const StrandCoords &strands() const; ///< currently registered strands
+
 protected:
     virtual void start(); // Port (AsyncJob) API
     virtual void receive(const TypedMsgHdr& message); // Port API
@@ -39,13 +44,14 @@ protected:
 
     /// returns cached socket or calls openListenSocket()
     void handleSharedListenRequest(const SharedListenRequest& request);
+    void handleCacheMgrRequest(const Mgr::Request& request);
+    void handleCacheMgrResponse(const Mgr::Response& response);
 
     /// calls comm_open_listener()
     int openListenSocket(const SharedListenRequest& request, int &errNo);
 
 private:
-    typedef Vector<StrandCoord> Strands; ///< unsorted strands
-    Strands strands; ///< registered processes and threads
+    StrandCoords strands_; ///< registered processes and threads
 
     typedef std::map<OpenListenerParams, int> Listeners; ///< params:fd map
     Listeners listeners; ///< cached comm_open_listener() results
index c81662c48298f22cd163e491384020d6612a0802..e2d13504d9dc99754ad79ca8a6c9c9fea4a93635 100644 (file)
@@ -10,10 +10,12 @@ libipc_la_SOURCES = \
        Kid.h \
        Kids.cc \
        Kids.h \
-       Messages.cc \
        Messages.h \
        StartListening.cc \
        StartListening.h \
+       StrandCoord.cc \
+       StrandCoord.h \
+       StrandCoords.h \
        SharedListen.cc \
        SharedListen.h \
        TypedMsgHdr.cc \
@@ -25,6 +27,8 @@ libipc_la_SOURCES = \
        Port.cc \
        Port.h \
        Strand.cc \
-       Strand.h
+       Strand.h \
+       \
+       forward.h
 
 DEFS += -DDEFAULT_PREFIX=\"$(prefix)\"
index 7d0e370ac0ceb99eb97d4d1a545f7758d5283d50..57ae03632d05cc325c6048052a83f5f7fb8f0a25 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef SQUID_IPC_MESSAGES_H
 #define SQUID_IPC_MESSAGES_H
 
+#include "ipc/forward.h"
 #include <sys/types.h>
 
 /** Declarations used by varios IPC messages */
 namespace Ipc
 {
 
-class TypedMsgHdr;
-
 /// message class identifier
 typedef enum { mtNone = 0, mtRegistration,
-               mtSharedListenRequest, mtSharedListenResponse
+               mtSharedListenRequest, mtSharedListenResponse,
+               mtCacheMgrRequest, mtCacheMgrResponse
              } MessageType;
 
-/// Strand location details
-class StrandCoord
-{
-public:
-    StrandCoord(); ///< unknown location
-    StrandCoord(int akidId, pid_t aPid); ///< from registrant
-    explicit StrandCoord(const TypedMsgHdr &hdrMsg); ///< from recvmsg()
-    void pack(TypedMsgHdr &hdrMsg) const; ///< prepare for sendmsg()
-
-public:
-    int kidId; ///< internal Squid process number
-    pid_t pid; ///< OS process or thread identifier
-};
-
 } // namespace Ipc;
 
 
index ffe791ad3c4b2be70ecd4dc7cf9f93cd08da84db..a2d69b52b502ce7ee3eb407220cccaaa76aab921 100644 (file)
@@ -22,11 +22,10 @@ class Port: public UdsOp
 {
 public:
     Port(const String &aListenAddr);
-
-protected:
     /// calculates IPC message address for strand #id at path
     static String MakeAddr(const char *path, int id);
 
+protected:
     virtual void start() = 0; // UdsOp (AsyncJob) API; has body
     virtual bool doneAll() const; // UdsOp (AsyncJob) API
 
index 77e2e1c2247a157a9def2d8bbd261d5fc8ed8271..6b76b96acf5893b24b1fc45d2bb4eca12b81686b 100644 (file)
@@ -71,12 +71,14 @@ Ipc::SharedListenRequest::SharedListenRequest(): requestorId(-1), mapId(-1)
 
 Ipc::SharedListenRequest::SharedListenRequest(const TypedMsgHdr &hdrMsg)
 {
-    hdrMsg.getData(mtSharedListenRequest, this, sizeof(*this));
+    hdrMsg.checkType(mtSharedListenRequest);
+    hdrMsg.getPod(*this);
 }
 
 void Ipc::SharedListenRequest::pack(TypedMsgHdr &hdrMsg) const
 {
-    hdrMsg.putData(mtSharedListenRequest, this, sizeof(*this));
+    hdrMsg.setType(mtSharedListenRequest);
+    hdrMsg.putPod(*this);
 }
 
 
@@ -88,13 +90,15 @@ Ipc::SharedListenResponse::SharedListenResponse(int aFd, int anErrNo, int aMapId
 Ipc::SharedListenResponse::SharedListenResponse(const TypedMsgHdr &hdrMsg):
         fd(-1), errNo(0), mapId(-1)
 {
-    hdrMsg.getData(mtSharedListenResponse, this, sizeof(*this));
+    hdrMsg.checkType(mtSharedListenResponse);
+    hdrMsg.getPod(*this);
     fd = hdrMsg.getFd();
 }
 
 void Ipc::SharedListenResponse::pack(TypedMsgHdr &hdrMsg) const
 {
-    hdrMsg.putData(mtSharedListenResponse, this, sizeof(*this));
+    hdrMsg.setType(mtSharedListenResponse);
+    hdrMsg.putPod(*this);
     hdrMsg.putFd(fd);
 }
 
index 384e44794f4b601399ec24a5f06152edcd1e7a7b..a1e9f59c5dc69b54b451de1fc031185c18a57cb7 100644 (file)
@@ -8,9 +8,14 @@
 #include "config.h"
 #include "base/TextException.h"
 #include "ipc/Strand.h"
+#include "ipc/StrandCoord.h"
 #include "ipc/Messages.h"
 #include "ipc/SharedListen.h"
 #include "ipc/Kids.h"
+#include "mgr/Request.h"
+#include "mgr/Response.h"
+#include "mgr/Forwarder.h"
+#include "CacheManager.h"
 
 
 CBDATA_NAMESPACED_CLASS_INIT(Ipc, Strand);
@@ -51,6 +56,14 @@ void Ipc::Strand::receive(const TypedMsgHdr &message)
         SharedListenJoined(SharedListenResponse(message));
         break;
 
+    case mtCacheMgrRequest:
+        handleCacheMgrRequest(Mgr::Request(message));
+        break;
+
+    case mtCacheMgrResponse:
+        handleCacheMgrResponse(Mgr::Response(message));
+        break;
+
     default:
         debugs(54, 1, HERE << "Unhandled message type: " << message.type());
         break;
@@ -70,6 +83,18 @@ void Ipc::Strand::handleRegistrationResponse(const StrandCoord &strand)
     }
 }
 
+void Ipc::Strand::handleCacheMgrRequest(const Mgr::Request& request)
+{
+    Mgr::Action::Pointer action =
+        CacheManager::GetInstance()->createRequestedAction(request.params);
+    action->respond(request);
+}
+
+void Ipc::Strand::handleCacheMgrResponse(const Mgr::Response& response)
+{
+    Mgr::Forwarder::HandleRemoteAck(response.requestId);
+}
+
 void Ipc::Strand::timedout()
 {
     debugs(54, 6, HERE << isRegistered);
index 899c348783fb7260af18d3b4d5ec753a411fc0c3..d01cf2b7f29d7aab08a0c48f615637765e0dd179 100644 (file)
@@ -9,13 +9,13 @@
 #define SQUID_IPC_STRAND_H
 
 #include "ipc/Port.h"
+#include "mgr/forward.h"
 
 
 namespace Ipc
 {
 
 class StrandCoord;
-class Descriptor;
 
 /// Receives coordination messages on behalf of its process or thread
 class Strand: public Port
@@ -32,7 +32,8 @@ protected:
 private:
     void registerSelf(); /// let Coordinator know this strand exists
     void handleRegistrationResponse(const StrandCoord &strand);
-    void putDescriptor(const Descriptor &message);
+    void handleCacheMgrRequest(const Mgr::Request& request);
+    void handleCacheMgrResponse(const Mgr::Response& response);
 
 private:
     bool isRegistered; ///< whether Coordinator ACKed registration (unused)
similarity index 73%
rename from src/ipc/Messages.cc
rename to src/ipc/StrandCoord.cc
index 5526db7fed16d0e06b7071f6db00b27471d828f0..3fdf45a9fc7c9c203cd06d44ebb2ff70c19324cc 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "config.h"
 #include "ipc/Messages.h"
+#include "ipc/StrandCoord.h"
 #include "ipc/TypedMsgHdr.h"
 
 
@@ -21,10 +22,12 @@ Ipc::StrandCoord::StrandCoord(int aKidId, pid_t aPid): kidId(aKidId), pid(aPid)
 
 Ipc::StrandCoord::StrandCoord(const TypedMsgHdr &hdrMsg): kidId(-1), pid(0)
 {
-    hdrMsg.getData(mtRegistration, this, sizeof(*this));
+    hdrMsg.checkType(mtRegistration);
+    hdrMsg.getPod(*this);
 }
 
 void Ipc::StrandCoord::pack(TypedMsgHdr &hdrMsg) const
 {
-    hdrMsg.putData(mtRegistration, this, sizeof(*this));
+    hdrMsg.setType(mtRegistration);
+    hdrMsg.putPod(*this);
 }
diff --git a/src/ipc/StrandCoord.h b/src/ipc/StrandCoord.h
new file mode 100644 (file)
index 0000000..02f2056
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * $Id$
+ *
+ */
+
+#ifndef SQUID_IPC_STRAND_COORD_H
+#define SQUID_IPC_STRAND_COORD_H
+
+#include "ipc/forward.h"
+#include <sys/types.h>
+
+namespace Ipc
+{
+
+/// Strand location details
+class StrandCoord
+{
+public:
+    StrandCoord(); ///< unknown location
+    StrandCoord(int akidId, pid_t aPid); ///< from registrant
+    explicit StrandCoord(const TypedMsgHdr &hdrMsg); ///< from recvmsg()
+    void pack(TypedMsgHdr &hdrMsg) const; ///< prepare for sendmsg()
+
+public:
+    int kidId; ///< internal Squid process number
+    pid_t pid; ///< OS process or thread identifier
+};
+
+} // namespace Ipc;
+
+#endif /* SQUID_IPC_STRAND_COORD_H */
diff --git a/src/ipc/StrandCoords.h b/src/ipc/StrandCoords.h
new file mode 100644 (file)
index 0000000..2d83f71
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * $Id$
+ *
+ */
+
+#ifndef SQUID_IPC_STRAND_COORDS_H
+#define SQUID_IPC_STRAND_COORDS_H
+
+#include "ipc/StrandCoord.h"
+#include <vector>
+
+namespace Ipc {
+
+/// a collection of strand coordinates; the order, if any, is owner-dependent
+typedef std::vector<StrandCoord> StrandCoords;
+
+}; // namespace Ipc
+
+#endif /* SQUID_IPC_STRAND_COORDS_H */
index 622e142dbbbde20cbc6a4a4673f334ea553b36f2..b38954c3e91dc0d7820b023278458ca7cab788a3 100644 (file)
@@ -57,6 +57,7 @@ void Ipc::TypedMsgHdr::sync()
     } else {
         Must(!msg_controllen && !msg_control);
     }
+    offset = 0;
 }
 
 
@@ -78,21 +79,98 @@ Ipc::TypedMsgHdr::address(const struct sockaddr_un& addr)
 }
 
 void
-Ipc::TypedMsgHdr::getData(int destType, void *raw, size_t size) const
+Ipc::TypedMsgHdr::checkType(int destType) const
 {
     Must(type() == destType);
-    Must(size == data.size);
-    xmemcpy(raw, data.raw, size);
 }
 
 void
-Ipc::TypedMsgHdr::putData(int aType, const void *raw, size_t size)
+Ipc::TypedMsgHdr::setType(int aType)
 {
-    Must(size <= sizeof(data.raw));
-    allocData();
-    data.type_ = aType;
-    data.size = size;
-    xmemcpy(data.raw, raw, size);
+    if (data.type_) {
+        Must(data.type_ == aType);
+    } else {
+        allocData();
+        data.type_ = aType;
+    }
+}
+
+int
+Ipc::TypedMsgHdr::getInt() const
+{
+    int n = 0;
+    getPod(n);
+    return n;
+}
+
+void
+Ipc::TypedMsgHdr::putInt(const int n)
+{
+    putPod(n);
+}
+
+void
+Ipc::TypedMsgHdr::getString(String &s) const
+{
+    const int length = getInt();
+    Must(length >= 0);
+    // String uses memcpy uncoditionally; TODO: SBuf eliminates this check
+    if (!length) {
+        s.clean();
+        return;
+    }
+
+    Must(length <= maxSize);
+    // TODO: use SBuf.reserve() instead of a temporary buffer
+    char buf[length];
+    getRaw(&buf, length);
+    s.limitInit(buf, length);
+}
+
+void
+Ipc::TypedMsgHdr::putString(const String &s)
+{
+    Must(s.psize() <= maxSize);
+    putInt(s.psize());
+    putRaw(s.rawBuf(), s.psize());
+}
+
+void
+Ipc::TypedMsgHdr::getFixed(void *raw, size_t size) const
+{
+    // no need to load size because it is constant
+    getRaw(raw, size);
+}
+
+void
+Ipc::TypedMsgHdr::putFixed(const void *raw, size_t size)
+{
+    // no need to store size because it is constant
+    putRaw(raw, size);
+}
+
+/// low-level loading of exactly size bytes of raw data
+void
+Ipc::TypedMsgHdr::getRaw(void *raw, size_t size) const
+{
+    Must(size >= 0);
+    if (size > 0) {
+        Must(size <= data.size - offset);
+        xmemcpy(raw, data.raw + offset, size);
+        offset += size;
+    }
+}
+
+/// low-level storage of exactly size bytes of raw data
+void
+Ipc::TypedMsgHdr::putRaw(const void *raw, size_t size)
+{
+    Must(size >= 0);
+    if (size > 0) {
+        Must(size <= sizeof(data.raw) - data.size);
+        xmemcpy(data.raw + data.size, raw, size);
+        data.size += size;
+    }
 }
 
 void
index 79b60ab5e8008de77ca3463773b6ec0e46039a31..17468a8cafc6b6c1b22e33c9973319852d46473d 100644 (file)
 #include <sys/un.h>
 #endif
 
+class String;
+
 namespace Ipc
 {
 
 /// struct msghdr with a known type, fixed-size I/O and control buffers
 class TypedMsgHdr: public msghdr
 {
+public:
+    enum {maxSize = 4096};
+
 public:
     TypedMsgHdr();
     TypedMsgHdr(const TypedMsgHdr &tmh);
     TypedMsgHdr &operator =(const TypedMsgHdr &tmh);
 
-    // type-safe access to message details
+    void address(const struct sockaddr_un &addr); ///< sets [dest.] address
+
+    /* message type manipulation; these must be called before put/get*() */
+    void setType(int aType); ///< sets message type; use MessageType enum
+    void checkType(int aType) const; ///< throws if stored type is not aType
     int type() const; ///< returns stored type or zero if none
-    void address(const struct sockaddr_un& addr); ///< sets [dest.] address
-    void getData(int ofType, void *raw, size_t size) const; ///< checks type
-    void putData(int aType, const void *raw, size_t size); ///< stores type
+
+    /* access for Plain Old Data (POD)-based message parts */
+    template <class Pod>
+    void getPod(Pod &pod) const { getFixed(&pod, sizeof(pod)); } ///< load POD
+    template <class Pod>
+    void putPod(const Pod &pod) { putFixed(&pod, sizeof(pod)); } ///< store POD
+
+    /* access to message parts for selected commonly-used part types */
+    void getString(String &s) const; ///< load variable-length string
+    void putString(const String &s); ///< store variable-length string
+    int getInt() const; ///< load an integer
+    void putInt(int n); ///< store an integer
+    void getFixed(void *raw, size_t size) const; ///< always load size bytes
+    void putFixed(const void *raw, size_t size); ///< always store size bytes
+
+    /// returns true if there is data to extract; handy for optional parts
+    bool hasMoreData() const { return offset < data.size; }
+
+    /* access to a "file" descriptor that can be passed between processes */
     void putFd(int aFd); ///< stores descriptor
     int getFd() const; ///< returns descriptor
 
-    /// raw, type-independent access for I/O
+    /* raw, type-independent access for I/O */
     void prepForReading(); ///< reset and provide all buffers
     char *raw() { return reinterpret_cast<char*>(this); }
     const char *raw() const { return reinterpret_cast<const char*>(this); }
@@ -51,6 +76,10 @@ private:
     void allocName();
     void allocControl();
 
+    /* raw, type-independent manipulation used by type-specific methods */
+    void getRaw(void *raw, size_t size) const;
+    void putRaw(const void *raw, size_t size);
+
 private:
     struct sockaddr_un name; ///< same as .msg_name
 
@@ -59,12 +88,15 @@ private:
     struct DataBuffer {
         int type_; ///< Message kind, uses MessageType values
         size_t size; ///< actual raw data size (for sanity checks)
-        char raw[250]; ///< buffer with type-specific data
+        char raw[maxSize]; ///< buffer with type-specific data
     } data; ///< same as .msg_iov[0].iov_base
 
     struct CtrlBuffer {
         char raw[CMSG_SPACE(sizeof(int))]; ///< control buffer space for one fd
     } ctrl; ///< same as .msg_control
+
+    /// data offset for the next get/put*() to start with
+    mutable unsigned int offset; 
 };
 
 } // namespace Ipc
diff --git a/src/ipc/forward.h b/src/ipc/forward.h
new file mode 100644 (file)
index 0000000..d517307
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 54    Interprocess Communication
+ *
+ */
+
+#ifndef SQUID_IPC_FORWARD_H
+#define SQUID_IPC_FORWARD_H
+
+#include "config.h"
+
+namespace Ipc
+{
+
+class TypedMsgHdr;
+class StrandCoord;
+
+} // namespace Ipc
+
+#endif /* SQUID_IPC_FORWARD_H */
index de31059a962484a7c269fdb50b24cc3ddae1ce53..44ff00f498f0d0c8ca0d493ede95ee564da68549 100644 (file)
  */
 
 #include "squid.h"
-#include "CacheManager.h"
 #include "cbdata.h"
 #include "event.h"
 #include "ip/Address.h"
 #include "ip/tools.h"
+#include "mgr/Registration.h"
 #include "SquidTime.h"
 #include "Store.h"
 #include "wordlist.h"
@@ -700,8 +700,7 @@ ipcache_nbgethostbyname(const char *name, IPH * handler, void *handlerData)
 static void
 ipcacheRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("ipcache",
+    Mgr::RegisterAction("ipcache",
                    "IP Cache Stats and Contents",
                    stat_ipcache_get, 0, 1);
 }
index 8eb8982e44cdd4c6689ac4592fec850d72a70595..b1e8efa9c85223dfaba15faf62edd9e63c0f38a1 100644 (file)
@@ -42,7 +42,7 @@
 #include "errorpage.h"
 #include "err_detail_type.h"
 #include "acl/Checklist.h"
-#include "CacheManager.h"
+#include "errorpage.h"
 #if USE_SQUID_EUI
 #include "eui/Eui48.h"
 #include "eui/Eui64.h"
@@ -52,6 +52,7 @@
 #include "HttpRequest.h"
 #include "log/File.h"
 #include "MemBuf.h"
+#include "mgr/Registration.h"
 #include "rfc1738.h"
 #include "SquidTime.h"
 
@@ -2290,9 +2291,8 @@ fvdbInit(void)
 static void
 fvdbRegisterWithCacheManager(void)
 {
-    CacheManager *manager=CacheManager::GetInstance();
-    manager->registerAction("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
-    manager->registerAction("forw_headers", "X-Forwarded-For Request Headers",
+    Mgr::RegisterAction("via_headers", "Via Request Headers", fvdbDumpVia, 0, 1);
+    Mgr::RegisterAction("forw_headers", "X-Forwarded-For Request Headers",
                             fvdbDumpForw, 0, 1);
 }
 
index 00ab2d2551d208583c430a782cc63761a58cef9f..9970cd39b5466dd0ad5a052c33697bf0a7aa3139 100644 (file)
@@ -34,7 +34,7 @@
 
 #include "squid.h"
 #include "event.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "ClientInfo.h"
 #include "Mem.h"
 #include "memMeter.h"
@@ -455,8 +455,7 @@ Mem::Report()
 void
 Mem::RegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->registerAction("mem", "Memory Utilization",
-            Mem::Stats, 0, 1);
+    Mgr::RegisterAction("mem", "Memory Utilization", Mem::Stats, 0, 1);
 }
 
 mem_type &operator++ (mem_type &aMem)
diff --git a/src/mgr/Action.cc b/src/mgr/Action.cc
new file mode 100644 (file)
index 0000000..5adce85
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "HttpReply.h"
+#include "ipc/Port.h"
+#include "mgr/ActionCreator.h"
+#include "mgr/Action.h"
+#include "mgr/ActionParams.h"
+#include "mgr/ActionProfile.h"
+#include "mgr/Command.h"
+#include "mgr/Request.h"
+#include "mgr/Response.h"
+#include "SquidTime.h"
+#include "Store.h"
+
+
+Mgr::Action::Action(const Command::Pointer &aCmd): cmd(aCmd)
+{
+    Must(cmd != NULL);
+    Must(cmd->profile != NULL);
+}
+
+Mgr::Action::~Action()
+{
+}
+
+const Mgr::Command &
+Mgr::Action::command() const
+{
+    Must(cmd != NULL);
+    return *cmd;
+}
+
+bool
+Mgr::Action::atomic() const
+{
+    return command().profile->isAtomic;
+}
+
+const char*
+Mgr::Action::name() const
+{
+    return command().profile->name;
+}
+
+StoreEntry*
+Mgr::Action::createStoreEntry() const
+{
+    const ActionParams &params = command().params;
+    const char *uri = params.httpUri.termedBuf();
+    return storeCreateEntry(uri, uri, params.httpFlags, params.httpMethod);
+}
+
+void
+Mgr::Action::add(const Action& action)
+{
+}
+
+void
+Mgr::Action::respond(const Request& request)
+{
+    debugs(16, 5, HERE);
+
+    // Assume most kid classes are fully aggregatable (i.e., they do not dump
+    // local info at all). Do not import the remote HTTP fd into our Comm
+    // space; collect and send an IPC msg with collected info to Coordinator.
+    ::close(request.fd);
+    collect();
+    sendResponse(request.requestId);
+}
+
+void
+Mgr::Action::sendResponse(unsigned int requestId)
+{
+    Response response(requestId, this);
+    Ipc::TypedMsgHdr message;
+    response.pack(message);
+    Ipc::SendMessage(Ipc::coordinatorAddr, message);
+}
+
+void
+Mgr::Action::run(StoreEntry* entry, bool writeHttpHeader)
+{
+    debugs(16, 5, HERE);
+    collect();
+    fillEntry(entry, writeHttpHeader);
+}
+
+void
+Mgr::Action::fillEntry(StoreEntry* entry, bool writeHttpHeader)
+{
+    debugs(16, 5, HERE);
+    entry->buffer();
+
+    if (writeHttpHeader) {
+        HttpReply *rep = new HttpReply;
+        rep->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
+        entry->replaceHttpReply(rep);
+    }
+
+    dump(entry);
+
+    entry->flush();
+
+    if (atomic())
+        entry->complete();
+}
diff --git a/src/mgr/Action.h b/src/mgr/Action.h
new file mode 100644 (file)
index 0000000..5e4e14f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_ACTION_H
+#define SQUID_MGR_ACTION_H
+
+#include "ipc/forward.h"
+#include "mgr/forward.h"
+
+class StoreEntry;
+
+namespace Mgr
+{
+
+/// Base API for organizing the processing of a compiled cache manager command.
+/// Not a job because all methods are synchronous (but they may start jobs).
+class Action: public RefCountable
+{
+public:
+    typedef RefCount<Action> Pointer;
+
+public:
+    Action(const CommandPointer &aCmd);
+    virtual ~Action();
+
+
+    /* for local Cache Manager use */
+
+    /// collect + fillEntry: collect local information and fill the store entry
+    void run(StoreEntry *entry, bool writeHttpHeader);
+
+    /// prepare store entry, dump info, close store entry (if possible)
+    void fillEntry(StoreEntry *entry, bool writeHttpHeader);
+
+
+    /* for global Coordinator use */
+
+    /// incrementally merge in remote information (of the same action type)
+    virtual void add(const Action &action);
+
+
+    /* global-local communication */
+
+    /// respond to Coordinator request; default is to collect and sendResponse
+    virtual void respond(const Request &request);
+
+    /// pack collected action info into a message to be sent to Coordinator
+    virtual void pack(Ipc::TypedMsgHdr &msg) const {}
+    /// unpack action info from the message received by Coordinator
+    virtual void unpack(const Ipc::TypedMsgHdr &msg) {}
+
+    /// notify Coordinator that this action is done with local processing
+    void sendResponse(unsigned int requestId);
+
+
+    /* Action properties */
+
+    /// whether at least some local kid info can be combined and, hence, the
+    /// combined data should be written at the end of the coordinated response
+    virtual bool aggregatable() const { return true; } // most kid classes are
+
+    bool atomic() const; ///< dump() call writes everything before returning
+    const char *name() const; ///< label as seen in the cache manager menu
+    const Command &command() const; ///< the cause of this action
+
+    StoreEntry *createStoreEntry() const; ///< creates store entry from params
+
+protected:
+    /// calculate and keep local action-specific information
+    virtual void collect() {}
+
+    /** start writing action-specific info to Store entry; 
+     * may collect info during dump, especially if collect() did nothing
+     * non-atomic() actions may continue writing asynchronously after returning
+     */
+    virtual void dump(StoreEntry *entry) {}
+
+
+private:
+    const CommandPointer cmd; ///< the command that caused this action
+
+
+private:
+    Action(const Action &); // not implemented
+    Action &operator= (const Action &); // not implemented
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_ACTION_H */
diff --git a/src/mgr/ActionCreator.h b/src/mgr/ActionCreator.h
new file mode 100644 (file)
index 0000000..c4f2461
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_ACTION_CREATOR_H
+#define SQUID_MGR_ACTION_CREATOR_H
+
+#include "mgr/forward.h"
+
+namespace Mgr
+{
+
+/** Creates objects of the right Action class, parameterized with Command.
+ * A part of the Action profile that allows Cache Manager be ignorant about
+ * specific Action classes (\see Mgr::ActionProfile).
+ */
+class ActionCreator: public RefCountable
+{
+public:
+    typedef RefCount<ActionCreator> Pointer;
+
+    virtual ~ActionCreator() {}
+
+    /// returns a pointer to the new Action object for cmd; never nil
+    virtual ActionPointer create(const CommandPointer &cmd) const = 0;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_ACTION_CREATOR_H */
diff --git a/src/mgr/ActionParams.cc b/src/mgr/ActionParams.cc
new file mode 100644 (file)
index 0000000..5dea7e5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/ActionParams.h"
+
+Mgr::ActionParams::ActionParams(): httpMethod(METHOD_NONE) {
+}
+
+Mgr::ActionParams::ActionParams(const Ipc::TypedMsgHdr &msg)
+{
+    msg.getString(httpUri);
+
+    const int m = msg.getInt();
+    Must(METHOD_NONE <= m && m < METHOD_ENUM_END);
+    httpMethod = static_cast<_method_t>(m);
+
+    msg.getPod(httpFlags);
+
+    msg.getString(actionName);
+    msg.getString(userName);
+    msg.getString(password);
+}
+
+void
+Mgr::ActionParams::pack(Ipc::TypedMsgHdr &msg) const
+{
+    msg.putString(httpUri);
+    msg.putInt(httpMethod);
+    msg.putPod(httpFlags);
+
+    msg.putString(actionName);
+    msg.putString(userName);
+    msg.putString(password);
+}
diff --git a/src/mgr/ActionParams.h b/src/mgr/ActionParams.h
new file mode 100644 (file)
index 0000000..4287a53
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_ACTION_PARAMS_H
+#define SQUID_MGR_ACTION_PARAMS_H
+
+#include "HttpRequestMethod.h"
+#include "ipc/forward.h"
+
+namespace Mgr
+{
+
+/// Cache Manager Action parameters extracted from the user request
+class ActionParams
+{
+public:
+    ActionParams();
+
+    explicit ActionParams(const Ipc::TypedMsgHdr &msg); ///< load from msg
+    void pack(Ipc::TypedMsgHdr &msg) const; ///< store into msg
+
+public:
+    /* details of the client HTTP request that caused the action */
+    String httpUri; ///< HTTP request URI
+    _method_t httpMethod; ///< HTTP request method
+    request_flags httpFlags; ///< HTTP request flags
+
+    /* action parameters extracted from the client HTTP request */
+    String actionName; ///< action name (and credentials realm)
+    String userName; ///< user login name; currently only used for logging
+    String password; ///< user password; used for acceptance check and cleared
+
+};
+
+} // namespace Mgr
+
+std::ostream &operator <<(std::ostream &os, const Mgr::ActionParams &params);
+
+#endif /* SQUID_MGR_ACTION_PARAMS_H */
diff --git a/src/mgr/ActionProfile.h b/src/mgr/ActionProfile.h
new file mode 100644 (file)
index 0000000..e0acfe7
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_ACTION_PROFILE_H
+#define SQUID_MGR_ACTION_PROFILE_H
+
+#include "mgr/ActionCreator.h"
+#include "mgr/forward.h"
+
+namespace Mgr
+{
+
+/// hard-coded Cache Manager action configuration, including Action creator
+class ActionProfile: public RefCountable
+{
+public:
+    typedef RefCount<ActionProfile> Pointer;
+
+public:
+    ActionProfile(const char* aName, const char* aDesc, bool aPwReq,
+        bool anAtomic, const ActionCreatorPointer &aCreator):
+        name(aName), desc(aDesc), isPwReq(aPwReq), isAtomic(anAtomic),
+        creator(aCreator)
+    {
+    }
+
+public:
+    const char *name; ///< action label to uniquely identify this action
+    const char *desc; ///< action description to build an action menu list
+    bool isPwReq; ///< whether password is required to perform the action
+    bool isAtomic; ///< whether action dumps everything in one dump() call
+    ActionCreatorPointer creator; ///< creates Action objects with this profile
+};
+
+} // namespace Mgr
+
+inline std::ostream &
+operator <<(std::ostream &os, const Mgr::ActionProfile &profile)
+{
+    return os << profile.name;
+}
+
+#endif /* SQUID_MGR_ACTION_PROFILE_H */
diff --git a/src/mgr/ActionWriter.cc b/src/mgr/ActionWriter.cc
new file mode 100644 (file)
index 0000000..18e0dcc
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "mgr/ActionWriter.h"
+#include "Store.h"
+
+
+CBDATA_NAMESPACED_CLASS_INIT(Mgr, ActionWriter);
+
+Mgr::ActionWriter::ActionWriter(const Action::Pointer &anAction, int aFd):
+    StoreToCommWriter(aFd, anAction->createStoreEntry()),
+    action(anAction)
+{
+    debugs(16, 5, HERE << "FD " << aFd << " action: " << action);
+}
+
+void
+Mgr::ActionWriter::start()
+{
+    debugs(16, 5, HERE);
+    Must(action != NULL);
+
+    StoreToCommWriter::start();
+    action->fillEntry(entry, false);
+}
diff --git a/src/mgr/ActionWriter.h b/src/mgr/ActionWriter.h
new file mode 100644 (file)
index 0000000..25a4bd2
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_ACTION_WRITER_H
+#define SQUID_MGR_ACTION_WRITER_H
+
+#include "HttpRequestMethod.h"
+#include "mgr/StoreToCommWriter.h"
+
+
+namespace Mgr
+{
+
+/// Creates Store entry, fills it using action's fillEntry(), and
+/// Comm-writes it using parent StoreToCommWriter.
+class ActionWriter: public StoreToCommWriter
+{
+public:
+    ActionWriter(const Action::Pointer &anAction, int aFd);
+
+protected:
+    /* AsyncJob API */
+    virtual void start();
+
+private:
+    Action::Pointer action; ///< action that fills the entry
+
+    CBDATA_CLASS2(ActionWriter);
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_ACTION_WRITER_H */
diff --git a/src/mgr/BasicActions.cc b/src/mgr/BasicActions.cc
new file mode 100644 (file)
index 0000000..012e914
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CacheManager.h"
+#include "mgr/ActionCreator.h"
+#include "mgr/ActionProfile.h"
+#include "mgr/BasicActions.h"
+#include "mgr/Registration.h"
+#include "Store.h"
+
+
+Mgr::MenuAction::Pointer
+Mgr::MenuAction::Create(const Command::Pointer &cmd)
+{
+    return new MenuAction(cmd);
+}
+
+Mgr::MenuAction::MenuAction(const Command::Pointer &cmd): Action(cmd)
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::MenuAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+
+    typedef CacheManager::Menu::const_iterator Iterator;
+    const CacheManager::Menu& menu = CacheManager::GetInstance()->menu();
+
+    for (Iterator a = menu.begin(); a != menu.end(); ++a) {
+        storeAppendPrintf(entry, " %-22s\t%-32s\t%s\n",
+                          (*a)->name, (*a)->desc,
+                          CacheManager::GetInstance()->ActionProtection(*a));
+    }
+}
+
+Mgr::ShutdownAction::Pointer
+Mgr::ShutdownAction::Create(const Command::Pointer &cmd)
+{
+    return new ShutdownAction(cmd);
+}
+
+Mgr::ShutdownAction::ShutdownAction(const Command::Pointer &cmd): Action(cmd)
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::ShutdownAction::dump(StoreEntry* entry)
+{
+    debugs(16, DBG_CRITICAL, "Shutdown by Cache Manager command.");
+    shut_down(SIGTERM);
+}
+
+Mgr::ReconfigureAction::Pointer
+Mgr::ReconfigureAction::Create(const Command::Pointer &cmd)
+{
+    return new ReconfigureAction(cmd);
+}
+
+Mgr::ReconfigureAction::ReconfigureAction(const Command::Pointer &cmd):
+    Action(cmd)
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::ReconfigureAction::dump(StoreEntry* entry)
+{
+    debugs(16, DBG_IMPORTANT, "Reconfigure by Cache Manager command.");
+    storeAppendPrintf(entry, "Reconfiguring Squid Process ....");
+    reconfigure(SIGHUP);
+}
+
+Mgr::RotateAction::Pointer
+Mgr::RotateAction::Create(const Command::Pointer &cmd)
+{
+    return new RotateAction(cmd);
+}
+
+Mgr::RotateAction::RotateAction(const Command::Pointer &cmd): Action(cmd)
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::RotateAction::dump(StoreEntry* entry)
+{
+    debugs(16, DBG_IMPORTANT, "Rotate Logs by Cache Manager command.");
+    storeAppendPrintf(entry, "Rotating Squid Process Logs ....");
+#ifdef _SQUID_LINUX_THREADS_
+    rotate_logs(SIGQUIT);
+#else
+    rotate_logs(SIGUSR1);
+#endif
+}
+
+Mgr::OfflineToggleAction::Pointer
+Mgr::OfflineToggleAction::Create(const Command::Pointer &cmd)
+{
+    return new OfflineToggleAction(cmd);
+}
+
+Mgr::OfflineToggleAction::OfflineToggleAction(const Command::Pointer &cmd):
+    Action(cmd)
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::OfflineToggleAction::dump(StoreEntry* entry)
+{
+    Config.onoff.offline = !Config.onoff.offline;
+    debugs(16, DBG_IMPORTANT, "offline_mode now " << (Config.onoff.offline ? "ON" : "OFF") << " by Cache Manager request.");
+
+    storeAppendPrintf(entry, "offline_mode is now %s\n",
+                      Config.onoff.offline ? "ON" : "OFF");
+}
+
+void
+Mgr::RegisterBasics()
+{
+    RegisterAction("offline_toggle", "Toggle offline_mode setting", &Mgr::OfflineToggleAction::Create, 1, 1);
+    RegisterAction("shutdown", "Shut Down the Squid Process", &Mgr::ShutdownAction::Create, 1, 1);
+    RegisterAction("reconfigure", "Reconfigure Squid", &Mgr::ReconfigureAction::Create, 1, 1);
+    RegisterAction("rotate", "Rotate Squid Logs", &Mgr::RotateAction::Create, 1, 1);
+    RegisterAction("menu", "Cache Manager Menu", &Mgr::MenuAction::Create, 0, 1);
+}
diff --git a/src/mgr/BasicActions.h b/src/mgr/BasicActions.h
new file mode 100644 (file)
index 0000000..ffe8008
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_BASIC_ACTIONS_H
+#define SQUID_MGR_BASIC_ACTIONS_H
+
+#include "mgr/Action.h"
+
+/* a collection of simple, mostly stateless actions */
+
+
+namespace Mgr
+{
+
+/// returns available Cache Manager actions and their access requirements
+class MenuAction: public Action
+{
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void dump(StoreEntry *entry);
+
+protected:
+    MenuAction(const CommandPointer &cmd);
+};
+
+
+/// shuts Squid down
+class ShutdownAction: public Action
+{
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void dump(StoreEntry *entry);
+
+protected:
+    ShutdownAction(const CommandPointer &cmd);
+};
+
+/// reconfigures Squid
+class ReconfigureAction: public Action
+{
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void dump(StoreEntry *entry);
+
+protected:
+    ReconfigureAction(const CommandPointer &cmd);
+};
+
+/// starts log rotation
+class RotateAction: public Action
+{
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void dump(StoreEntry *entry);
+
+protected:
+    RotateAction(const CommandPointer &cmd);
+};
+
+/// changes offline mode
+class OfflineToggleAction: public Action
+{
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void dump(StoreEntry *entry);
+
+protected:
+    OfflineToggleAction(const CommandPointer &cmd);
+};
+
+/// Registeres profiles for the actions above; \todo move elsewhere?
+void RegisterBasics();
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_BASIC_ACTIONS_H */
diff --git a/src/mgr/Command.cc b/src/mgr/Command.cc
new file mode 100644 (file)
index 0000000..2d57b2d
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "mgr/ActionProfile.h"
+#include "mgr/Command.h"
+
+std::ostream &
+operator <<(std::ostream &os, const Mgr::Command &cmd)
+{
+    if (cmd.profile != NULL)
+        return os << *cmd.profile;
+    return os << "undef";
+}
diff --git a/src/mgr/Command.h b/src/mgr/Command.h
new file mode 100644 (file)
index 0000000..d73395e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_COMMAND_H
+#define SQUID_MGR_COMMAND_H
+
+#include "mgr/ActionParams.h"
+#include "mgr/forward.h"
+
+namespace Mgr
+{
+
+/// combined hard-coded action profile with user-supplied action parameters
+class Command: public RefCountable {
+public:
+    typedef RefCount<Command> Pointer;
+
+public:
+    ActionProfilePointer profile; ///< hard-coded action specification
+    ActionParams params; ///< user-supplied action arguments
+};
+
+} // namespace Mgr
+
+std::ostream &operator <<(std::ostream &os, const Mgr::Command &cmd);
+
+#endif /* SQUID_MGR_COMMAND_H */
diff --git a/src/mgr/CountersAction.cc b/src/mgr/CountersAction.cc
new file mode 100644 (file)
index 0000000..e780fa4
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/CountersAction.h"
+#include "SquidTime.h"
+#include "Store.h"
+
+
+extern void GetCountersStats(Mgr::CountersActionData& stats);
+extern void DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry);
+
+Mgr::CountersActionData::CountersActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+Mgr::CountersActionData&
+Mgr::CountersActionData::operator += (const CountersActionData& stats)
+{
+    if (timercmp(&sample_time, &stats.sample_time, <))
+        sample_time = stats.sample_time;
+    client_http_requests += stats.client_http_requests;
+    client_http_hits += stats.client_http_hits;
+    client_http_errors += stats.client_http_errors;
+    client_http_kbytes_in += stats.client_http_kbytes_in;
+    client_http_kbytes_out += stats.client_http_kbytes_out;
+    client_http_hit_kbytes_out += stats.client_http_hit_kbytes_out;
+    server_all_requests += stats.server_all_requests;
+    server_all_errors += stats.server_all_errors;
+    server_all_kbytes_in += stats.server_all_kbytes_in;
+    server_all_kbytes_out += stats.server_all_kbytes_out;
+    server_http_requests += stats.server_http_requests;
+    server_http_errors += stats.server_http_errors;
+    server_http_kbytes_in += stats.server_http_kbytes_in;
+    server_http_kbytes_out += stats.server_http_kbytes_out;
+    server_ftp_requests += stats.server_ftp_requests;
+    server_ftp_errors += stats.server_ftp_errors;
+    server_ftp_kbytes_in += stats.server_ftp_kbytes_in;
+    server_ftp_kbytes_out += stats.server_ftp_kbytes_out;
+    server_other_requests += stats.server_other_requests;
+    server_other_errors += stats.server_other_errors;
+    server_other_kbytes_in += stats.server_other_kbytes_in;
+    server_other_kbytes_out += stats.server_other_kbytes_out;
+    icp_pkts_sent += stats.icp_pkts_sent;
+    icp_pkts_recv += stats.icp_pkts_recv;
+    icp_queries_sent += stats.icp_queries_sent;
+    icp_replies_sent += stats.icp_replies_sent;
+    icp_queries_recv += stats.icp_queries_recv;
+    icp_replies_recv += stats.icp_replies_recv;
+    icp_replies_queued += stats.icp_replies_queued;
+    icp_query_timeouts += stats.icp_query_timeouts;
+    icp_kbytes_sent += stats.icp_kbytes_sent;
+    icp_kbytes_recv += stats.icp_kbytes_recv;
+    icp_q_kbytes_sent += stats.icp_q_kbytes_sent;
+    icp_r_kbytes_sent += stats.icp_r_kbytes_sent;
+    icp_q_kbytes_recv += stats.icp_q_kbytes_recv;
+    icp_r_kbytes_recv += stats.icp_r_kbytes_recv;
+#if USE_CACHE_DIGESTS
+    icp_times_used += stats.icp_times_used;
+    cd_times_used += stats.cd_times_used;
+    cd_msgs_sent += stats.cd_msgs_sent;
+    cd_msgs_recv += stats.cd_msgs_recv;
+    cd_memory += stats.cd_memory;
+    cd_local_memory += stats.cd_local_memory;
+    cd_kbytes_sent += stats.cd_kbytes_sent;
+    cd_kbytes_recv += stats.cd_kbytes_recv;
+#endif
+    unlink_requests += stats.unlink_requests;
+    page_faults += stats.page_faults;
+    select_loops += stats.select_loops;
+    cpu_time += stats.cpu_time;
+    wall_time += stats.wall_time;
+    swap_outs += stats.swap_outs;
+    swap_ins += stats.swap_ins;
+    swap_files_cleaned += stats.swap_files_cleaned;
+    aborted_requests += stats.aborted_requests;
+
+    return *this;
+}
+
+Mgr::CountersAction::Pointer
+Mgr::CountersAction::Create(const CommandPointer &cmd)
+{
+    return new CountersAction(cmd);
+}
+
+Mgr::CountersAction::CountersAction(const CommandPointer &cmd):
+    Action(cmd), data()
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::CountersAction::add(const Action& action)
+{
+    debugs(16, 5, HERE);
+    data += dynamic_cast<const CountersAction&>(action).data;
+}
+
+void
+Mgr::CountersAction::collect()
+{
+    debugs(16, 5, HERE);
+    GetCountersStats(data);
+}
+
+void
+Mgr::CountersAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+    DumpCountersStats(data, entry);
+}
+
+void
+Mgr::CountersAction::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(data);
+}
+
+void
+Mgr::CountersAction::unpack(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(data);
+}
diff --git a/src/mgr/CountersAction.h b/src/mgr/CountersAction.h
new file mode 100644 (file)
index 0000000..447bb8b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_COUNTERS_ACTION_H
+#define SQUID_MGR_COUNTERS_ACTION_H
+
+#include "mgr/Action.h"
+#include <sys/time.h>
+
+
+namespace Mgr
+{
+
+/// store traffic and resource counters
+class CountersActionData
+{
+public:
+    CountersActionData();
+    CountersActionData& operator += (const CountersActionData& stats);
+
+public:
+    struct timeval sample_time;
+    double client_http_requests;
+    double client_http_hits;
+    double client_http_errors;
+    double client_http_kbytes_in;
+    double client_http_kbytes_out;
+    double client_http_hit_kbytes_out;
+    double server_all_requests;
+    double server_all_errors;
+    double server_all_kbytes_in;
+    double server_all_kbytes_out;
+    double server_http_requests;
+    double server_http_errors;
+    double server_http_kbytes_in;
+    double server_http_kbytes_out;
+    double server_ftp_requests;
+    double server_ftp_errors;
+    double server_ftp_kbytes_in;
+    double server_ftp_kbytes_out;
+    double server_other_requests;
+    double server_other_errors;
+    double server_other_kbytes_in;
+    double server_other_kbytes_out;
+    double icp_pkts_sent;
+    double icp_pkts_recv;
+    double icp_queries_sent;
+    double icp_replies_sent;
+    double icp_queries_recv;
+    double icp_replies_recv;
+    double icp_replies_queued;
+    double icp_query_timeouts;
+    double icp_kbytes_sent;
+    double icp_kbytes_recv;
+    double icp_q_kbytes_sent;
+    double icp_r_kbytes_sent;
+    double icp_q_kbytes_recv;
+    double icp_r_kbytes_recv;
+#if USE_CACHE_DIGESTS
+    double icp_times_used;
+    double cd_times_used;
+    double cd_msgs_sent;
+    double cd_msgs_recv;
+    double cd_memory;
+    double cd_local_memory;
+    double cd_kbytes_sent;
+    double cd_kbytes_recv;
+#endif
+    double unlink_requests;
+    double page_faults;
+    double select_loops;
+    double cpu_time;
+    double wall_time;
+    double swap_outs;
+    double swap_ins;
+    double swap_files_cleaned;
+    double aborted_requests;
+};
+
+/// implement aggregated 'counters' action
+class CountersAction: public Action
+{
+protected:
+    CountersAction(const CommandPointer &cmd);
+
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void add(const Action& action);
+    virtual void pack(Ipc::TypedMsgHdr& msg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& msg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    CountersActionData data;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_COUNTERS_ACTION_H */
diff --git a/src/mgr/Filler.cc b/src/mgr/Filler.cc
new file mode 100644 (file)
index 0000000..8646cd8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "mgr/Filler.h"
+#include "mgr/Response.h"
+#include "Store.h"
+
+
+CBDATA_NAMESPACED_CLASS_INIT(Mgr, Filler);
+
+Mgr::Filler::Filler(const Action::Pointer &anAction, int aFd,
+                    unsigned int aRequestId):
+    StoreToCommWriter(aFd, anAction->createStoreEntry()),
+    action(anAction),
+    requestId(aRequestId)
+{
+    debugs(16, 5, HERE << "FD " << aFd << " action: " << action);
+}
+
+void
+Mgr::Filler::start()
+{
+    debugs(16, 5, HERE);
+    Must(requestId != 0);
+    Must(action != NULL);
+
+    StoreToCommWriter::start();
+    action->run(entry, false);
+}
+
+void
+Mgr::Filler::swanSong()
+{
+    debugs(16, 5, HERE);
+    action->sendResponse(requestId);
+    StoreToCommWriter::swanSong();
+}
diff --git a/src/mgr/Filler.h b/src/mgr/Filler.h
new file mode 100644 (file)
index 0000000..e6c7ba1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_FILLER_H
+#define SQUID_MGR_FILLER_H
+
+#include "HttpRequestMethod.h"
+#include "mgr/Action.h"
+#include "mgr/StoreToCommWriter.h"
+
+namespace Mgr
+{
+
+/// provides Coordinator with a local cache manager response
+class Filler: public StoreToCommWriter
+{
+public:
+    Filler(const Action::Pointer &anAction, int aFd, unsigned int aRequestId);
+
+protected:
+    /* AsyncJob API */
+    virtual void start();
+    virtual void swanSong();
+
+private:
+    Action::Pointer action; ///< action that will run() and sendResponse()
+    unsigned int requestId; ///< the ID of the Request we are responding to
+
+    CBDATA_CLASS2(Filler);
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_FILLER_H */
diff --git a/src/mgr/Forwarder.cc b/src/mgr/Forwarder.cc
new file mode 100644 (file)
index 0000000..02a6178
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/AsyncJobCalls.h"
+#include "base/TextException.h"
+#include "CommCalls.h"
+#include "errorpage.h"
+#include "HttpReply.h"
+#include "HttpRequest.h"
+#include "ipc/Port.h"
+#include "mgr/Forwarder.h"
+#include "mgr/Request.h"
+#include "SquidTime.h"
+#include "Store.h"
+
+
+CBDATA_NAMESPACED_CLASS_INIT(Mgr, Forwarder);
+
+Mgr::Forwarder::RequestsMap Mgr::Forwarder::TheRequestsMap;
+unsigned int Mgr::Forwarder::LastRequestId = 0;
+
+Mgr::Forwarder::Forwarder(int aFd, const ActionParams &aParams,
+    HttpRequest* aRequest, StoreEntry* anEntry):
+    AsyncJob("Mgr::Forwarder"),
+    params(aParams),
+    request(aRequest), entry(anEntry), fd(aFd), requestId(0), closer(NULL)
+{
+    debugs(16, 5, HERE << "FD " << aFd);
+    Must(fd >= 0);
+    Must(request != NULL);
+    Must(entry != NULL);
+
+    HTTPMSGLOCK(request);
+    entry->lock();
+    EBIT_SET(entry->flags, ENTRY_FWD_HDR_WAIT);
+
+    closer = asyncCall(16, 5, "Mgr::Forwarder::noteCommClosed",
+        CommCbMemFunT<Forwarder, CommCloseCbParams>(this, &Forwarder::noteCommClosed));
+    comm_add_close_handler(fd, closer);
+}
+
+Mgr::Forwarder::~Forwarder()
+{
+    debugs(16, 5, HERE);
+    Must(request != NULL);
+    Must(entry != NULL);
+    Must(requestId == 0);
+
+    HTTPMSGUNLOCK(request);
+    entry->unregisterAbort();
+    entry->unlock();
+    close();
+}
+
+/// closes our copy of the client HTTP connection socket
+void
+Mgr::Forwarder::close() {
+    if (fd >= 0) {
+        if (closer != NULL) {
+            comm_remove_close_handler(fd, closer);
+            closer = NULL;
+        }
+        comm_close(fd);
+        fd = -1;
+    }
+}
+
+void
+Mgr::Forwarder::start()
+{
+    debugs(16, 3, HERE);
+    entry->registerAbort(&Forwarder::Abort, this);
+
+        typedef NullaryMemFunT<Mgr::Forwarder> Dialer;
+        AsyncCall::Pointer callback = JobCallback(16, 5, Dialer, this,
+                                                  Forwarder::handleRemoteAck);
+        if (++LastRequestId == 0) // don't use zero value as requestId
+            ++LastRequestId;
+        requestId = LastRequestId;
+        TheRequestsMap[requestId] = callback;
+        Request mgrRequest(KidIdentifier, requestId, fd, params);
+        Ipc::TypedMsgHdr message;
+
+    try {
+        mgrRequest.pack(message);
+    } 
+    catch (...) {
+        // assume the pack() call failed because the message did not fit
+        // TODO: add a more specific exception?
+        debugs(16, DBG_CRITICAL, "ERROR: uri " << entry->url() << " exceeds buffer size");
+        quitOnError("long URI", errorCon(ERR_INVALID_URL, HTTP_REQUEST_URI_TOO_LARGE, request));
+    }
+
+        Ipc::SendMessage(Ipc::coordinatorAddr, message);
+        const double timeout = 10; // in seconds
+        eventAdd("Mgr::Forwarder::requestTimedOut", &Forwarder::RequestTimedOut,
+            this, timeout, 0, false);
+}
+
+void
+Mgr::Forwarder::swanSong()
+{
+    debugs(16, 5, HERE);
+    removeTimeoutEvent();
+    if (requestId > 0) {
+        DequeueRequest(requestId);
+        requestId = 0;
+    }
+    close();
+}
+
+bool
+Mgr::Forwarder::doneAll() const
+{
+    debugs(16, 5, HERE);
+    return requestId == 0;
+}
+
+/// called when the client socket gets closed by some external force
+void
+Mgr::Forwarder::noteCommClosed(const CommCloseCbParams& params)
+{
+    debugs(16, 5, HERE);
+    Must(fd == params.fd);
+    fd = -1;
+    mustStop("commClosed");
+}
+
+/// called when Coordinator starts processing the request
+void
+Mgr::Forwarder::handleRemoteAck()
+{
+    debugs(16, 3, HERE);
+    Must(entry != NULL);
+
+    requestId = 0;
+    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+    entry->complete();
+}
+
+/// Mgr::Forwarder::requestTimedOut wrapper
+void
+Mgr::Forwarder::RequestTimedOut(void* param)
+{
+    debugs(16, 3, HERE);
+    Must(param != NULL);
+    Forwarder* mgrFwdr = static_cast<Forwarder*>(param);
+    // use async call to enable job call protection that time events lack
+    CallJobHere(16, 5, mgrFwdr, Mgr::Forwarder, requestTimedOut);
+}
+
+/// called when Coordinator fails to start processing the request [in time]
+void
+Mgr::Forwarder::requestTimedOut()
+{
+    debugs(16, 3, HERE);
+    quitOnError("timeout", errorCon(ERR_LIFETIME_EXP, HTTP_REQUEST_TIMEOUT, request));
+}
+
+/// terminate with an error
+void
+Mgr::Forwarder::quitOnError(const char *reason, ErrorState *error)
+{
+    debugs(16, 3, HERE);
+    Must(reason != NULL);
+    Must(error != NULL);
+    Must(entry != NULL);
+    Must(request != NULL);
+
+    EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT);
+    entry->buffer();
+    entry->replaceHttpReply(error->BuildHttpReply());
+    entry->expires = squid_curtime;
+    errorStateFree(error);
+    entry->flush();
+    entry->complete();
+
+    mustStop(reason);
+}
+
+void
+Mgr::Forwarder::callException(const std::exception& e)
+{
+    try {
+        if (entry != NULL && request != NULL && fd >= 0)
+            quitOnError("exception", errorCon(ERR_INVALID_RESP, HTTP_INTERNAL_SERVER_ERROR, request));
+    } catch (const std::exception& ex) {
+        debugs(16, DBG_CRITICAL, HERE << ex.what());
+    }
+    AsyncJob::callException(e);
+}
+
+/// returns and forgets the right Forwarder callback for the request
+AsyncCall::Pointer
+Mgr::Forwarder::DequeueRequest(unsigned int requestId)
+{
+    debugs(16, 3, HERE);
+    Must(requestId != 0);
+    AsyncCall::Pointer call;
+    RequestsMap::iterator request = TheRequestsMap.find(requestId);
+    if (request != TheRequestsMap.end()) {
+        call = request->second;
+        Must(call != NULL);
+        TheRequestsMap.erase(request);
+    }
+    return call;
+}
+
+/// called when we are no longer waiting for Coordinator to respond
+void
+Mgr::Forwarder::removeTimeoutEvent()
+{
+    if (eventFind(&Forwarder::RequestTimedOut, this))
+        eventDelete(&Forwarder::RequestTimedOut, this);
+}
+
+void
+Mgr::Forwarder::HandleRemoteAck(unsigned int requestId)
+{
+    debugs(16, 3, HERE);
+    Must(requestId != 0);
+
+    AsyncCall::Pointer call = DequeueRequest(requestId);
+    if (call != NULL)
+        ScheduleCallHere(call);
+}
+
+/// called when something goes wrong with the Store entry
+void
+Mgr::Forwarder::Abort(void* param)
+{
+    Forwarder* mgrFwdr = static_cast<Forwarder*>(param);
+    if (mgrFwdr->fd >= 0)
+        comm_close(mgrFwdr->fd);
+}
diff --git a/src/mgr/Forwarder.h b/src/mgr/Forwarder.h
new file mode 100644 (file)
index 0000000..21f2427
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_FORWARDER_H
+#define SQUID_MGR_FORWARDER_H
+
+#include "base/AsyncJob.h"
+#include "mgr/ActionParams.h"
+#include <map>
+
+
+class CommCloseCbParams;
+class HttpRequest;
+class StoreEntry;
+class ErrorState;
+
+namespace Mgr
+{
+
+/** Forwards a single client cache manager request to Coordinator.
+ * Waits for an ACK from Coordinator while holding the Store entry.
+ * Fills the store entry with an error response if forwarding fails.
+ */
+class Forwarder: public AsyncJob
+{
+public:
+    Forwarder(int aFd, const ActionParams &aParams, HttpRequest* aRequest,
+        StoreEntry* anEntry);
+    virtual ~Forwarder();
+
+    /// finds and calls the right Forwarder upon Coordinator's response
+    static void HandleRemoteAck(unsigned int requestId);
+
+    /* has-to-be-public AsyncJob API */
+    virtual void callException(const std::exception& e);
+
+protected:
+    /* AsyncJob API */
+    virtual void start();
+    virtual void swanSong();
+    virtual bool doneAll() const;
+
+private:
+    void handleRemoteAck();
+    static void RequestTimedOut(void* param);
+    void requestTimedOut();
+    void quitOnError(const char *reason, ErrorState *error);
+    void noteCommClosed(const CommCloseCbParams& params);
+    void removeTimeoutEvent();
+    static AsyncCall::Pointer DequeueRequest(unsigned int requestId);
+    static void Abort(void* param);
+    void close();
+
+private:
+    ActionParams params; ///< action parameters to pass to the other side
+    HttpRequest* request; ///< HTTP client request for detailing errors
+    StoreEntry* entry; ///< Store entry expecting the response
+    int fd; ///< HTTP client connection descriptor
+    unsigned int requestId; ///< request id
+    AsyncCall::Pointer closer; ///< comm_close handler for the HTTP connection
+
+    /// maps requestId to Forwarder::handleRemoteAck callback
+    typedef std::map<unsigned int, AsyncCall::Pointer> RequestsMap;
+    static RequestsMap TheRequestsMap; ///< pending Coordinator requests
+
+    static unsigned int LastRequestId; ///< last requestId used
+
+    CBDATA_CLASS2(Forwarder);
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_FORWARDER_H */
diff --git a/src/mgr/FunAction.cc b/src/mgr/FunAction.cc
new file mode 100644 (file)
index 0000000..e7f11d8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "mgr/Command.h"
+#include "mgr/Filler.h"
+#include "mgr/FunAction.h"
+#include "mgr/Request.h"
+#include "Store.h"
+
+
+Mgr::FunAction::Pointer
+Mgr::FunAction::Create(const Command::Pointer &aCmd, OBJH* aHandler)
+{
+    return new FunAction(aCmd, aHandler);
+}
+
+Mgr::FunAction::FunAction(const Command::Pointer &aCmd, OBJH* aHandler):
+    Action(aCmd), handler(aHandler)
+{
+    Must(handler != NULL);
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::FunAction::respond(const Request& request)
+{
+    debugs(16, 5, HERE);
+    const int fd = ImportHttpFdIntoComm(request.fd);
+    Must(fd >= 0);
+    Must(request.requestId != 0);
+    AsyncJob::Start(new Mgr::Filler(this, fd, request.requestId));
+}
+
+void
+Mgr::FunAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+    if (UsingSmp() && IamWorkerProcess())
+        storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier);
+    handler(entry);
+    if (atomic() && UsingSmp() && IamWorkerProcess())
+        storeAppendPrintf(entry, "} by kid%d\n\n", KidIdentifier);
+}
diff --git a/src/mgr/FunAction.h b/src/mgr/FunAction.h
new file mode 100644 (file)
index 0000000..2b70e0b
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_FUN_ACTION_H
+#define SQUID_MGR_FUN_ACTION_H
+
+#include "mgr/Action.h"
+#include "mgr/ActionCreator.h"
+
+
+namespace Mgr
+{
+
+/// function-based cache manager Action; a wrapper for so called legacy actions
+/// that do everything using a single OBJH function
+class FunAction: public Action
+{
+protected:
+    FunAction(const CommandPointer &cmd, OBJH *aHandler);
+
+public:
+    static Pointer Create(const CommandPointer &cmd, OBJH *aHandler);
+
+    /* Action API */
+    virtual void respond(const Request& request);
+    // we cannot aggregate because we do not even know what the handler does
+    virtual bool aggregatable() const { return false; }
+
+protected:
+    /* Action API */
+    virtual void dump(StoreEntry *entry);
+
+private:
+    OBJH *handler; ///< legacy function that collects and dumps info
+};
+
+
+/// creates FunAction using ActionCreator API
+class FunActionCreator: public ActionCreator
+{
+public:
+    explicit FunActionCreator(OBJH *aHandler): handler(aHandler) {}
+
+    /* ActionCreator API */
+    virtual Action::Pointer create(const CommandPointer &cmd) const
+    {
+        return FunAction::Create(cmd, handler);
+    }
+
+private:
+    OBJH *handler; ///< legacy function to pass to the FunAction wrapper
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_FUN_ACTION_H */
diff --git a/src/mgr/InfoAction.cc b/src/mgr/InfoAction.cc
new file mode 100644 (file)
index 0000000..1f93cc4
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "HttpReply.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/Filler.h"
+#include "mgr/InfoAction.h"
+#include "mgr/Request.h"
+#include "mgr/Response.h"
+#include "SquidTime.h"
+#include "Store.h"
+
+
+extern void GetInfo(Mgr::InfoActionData& stats);
+extern void DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry);
+extern void DumpMallocStatistics(StoreEntry* sentry);
+
+Mgr::InfoActionData::InfoActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+Mgr::InfoActionData&
+Mgr::InfoActionData::operator += (const InfoActionData& stats)
+{
+    if (!timerisset(&squid_start) || timercmp(&squid_start, &stats.squid_start, >))
+        squid_start = stats.squid_start;
+    if (timercmp(&current_time, &stats.current_time, <))
+        current_time = stats.current_time;
+    client_http_clients += stats.client_http_clients;
+    client_http_requests += stats.client_http_requests;
+    icp_pkts_recv += stats.icp_pkts_recv;
+    icp_pkts_sent += stats.icp_pkts_sent;
+    icp_replies_queued += stats.icp_replies_queued;
+#if USE_HTCP
+    htcp_pkts_recv += stats.htcp_pkts_recv;
+    htcp_pkts_sent += stats.htcp_pkts_sent;
+#endif
+    request_failure_ratio += stats.request_failure_ratio;
+    avg_client_http_requests += stats.avg_client_http_requests;
+    avg_icp_messages += stats.avg_icp_messages;
+    select_loops += stats.select_loops;
+    avg_loop_time += stats.avg_loop_time;
+    request_hit_ratio5 += stats.request_hit_ratio5;
+    request_hit_ratio60 += stats.request_hit_ratio60;
+    byte_hit_ratio5 += stats.byte_hit_ratio5;
+    byte_hit_ratio60 += stats.byte_hit_ratio60;
+    request_hit_mem_ratio5 += stats.request_hit_mem_ratio5;
+    request_hit_mem_ratio60 += stats.request_hit_mem_ratio60;
+    request_hit_disk_ratio5 += stats.request_hit_disk_ratio5;
+    request_hit_disk_ratio60 += stats.request_hit_disk_ratio60;
+    store_swap_size += stats.store_swap_size;
+    store_swap_max_size += stats.store_swap_max_size;
+    store_mem_size += stats.store_mem_size;
+    store_pages_max += stats.store_pages_max;
+    store_mem_used += stats.store_mem_used;
+    objects_size += stats.objects_size;
+    unlink_requests += stats.unlink_requests;
+    http_requests5 += stats.http_requests5;
+    http_requests60 += stats.http_requests60;
+    cache_misses5 += stats.cache_misses5;
+    cache_misses60 += stats.cache_misses60;
+    cache_hits5 += stats.cache_hits5;
+    cache_hits60 += stats.cache_hits60;
+    near_hits5 += stats.near_hits5;
+    near_hits60 += stats.near_hits60;
+    not_modified_replies5 += stats.not_modified_replies5;
+    not_modified_replies60 += stats.not_modified_replies60;
+    dns_lookups5 += stats.dns_lookups5;
+    dns_lookups60 += stats.dns_lookups60;
+    icp_queries5 += stats.icp_queries5;
+    icp_queries60 += stats.icp_queries60;
+    if (stats.up_time > up_time)
+        up_time = stats.up_time;
+    cpu_time += stats.cpu_time;
+    cpu_usage += stats.cpu_usage;
+    cpu_usage5 += stats.cpu_usage5;
+    cpu_usage60 += stats.cpu_usage60;
+#if HAVE_SBRK
+    proc_data_seg += stats.proc_data_seg;
+#endif
+    maxrss += stats.maxrss;
+    page_faults += stats.page_faults;
+#if HAVE_MSTATS && HAVE_GNUMALLOC_H
+    ms_bytes_total += stats.ms_bytes_total;
+    ms_bytes_free += stats.ms_bytes_free;
+#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+    mp_arena += stats.mp_arena;
+    mp_uordblks += stats.mp_uordblks;
+    mp_ordblks += stats.mp_ordblks;
+    mp_usmblks += stats.mp_usmblks;
+    mp_smblks += stats.mp_smblks;
+    mp_hblkhd += stats.mp_hblkhd;
+    mp_hblks += stats.mp_hblks;
+    mp_fsmblks += stats.mp_fsmblks;
+    mp_fordblks += stats.mp_fordblks;
+#if HAVE_STRUCT_MALLINFO_MXFAST
+    mp_mxfast += stats.mp_mxfast;
+    mp_nlblks += stats.mp_nlblks;
+    mp_grain += stats.mp_grain;
+    mp_uordbytes += stats.mp_uordbytes;
+    mp_allocated += stats.mp_allocated;
+    mp_treeoverhead += stats.mp_treeoverhead;
+#endif
+#endif
+    total_accounted += stats.total_accounted;
+#if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+    mem_pool_allocated += stats.mem_pool_allocated;
+#endif
+    gb_saved_count += stats.gb_saved_count;
+    gb_freed_count += stats.gb_freed_count;
+    max_fd += stats.max_fd;
+    biggest_fd += stats.biggest_fd;
+    number_fd += stats.number_fd;
+    opening_fd += stats.opening_fd;
+    num_fd_free += stats.num_fd_free;
+    reserved_fd += stats.reserved_fd;
+    store_open_disk_fd += stats.store_open_disk_fd;
+    store_entries += stats.store_entries;
+    store_mem_entries += stats.store_mem_entries;
+    hot_obj_count += stats.hot_obj_count;
+    n_disk_objects += stats.n_disk_objects;
+    ++count;
+
+    return *this;
+}
+
+Mgr::InfoAction::Pointer
+Mgr::InfoAction::Create(const CommandPointer &cmd)
+{
+    return new InfoAction(cmd);
+}
+
+Mgr::InfoAction::InfoAction(const CommandPointer &cmd):
+    Action(cmd), data()
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::InfoAction::add(const Action& action)
+{
+    debugs(16, 5, HERE);
+    data += dynamic_cast<const InfoAction&>(action).data;
+}
+
+void
+Mgr::InfoAction::respond(const Request& request)
+{
+    debugs(16, 5, HERE);
+    int fd = ImportHttpFdIntoComm(request.fd);
+    Must(fd >= 0);
+    Must(request.requestId != 0);
+    AsyncJob::Start(new Mgr::Filler(this, fd, request.requestId));
+}
+
+void
+Mgr::InfoAction::collect()
+{
+    GetInfo(data);
+}
+
+void
+Mgr::InfoAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+
+#if XMALLOC_STATISTICS
+    if (UsingSmp() && IamWorkerProcess())
+        storeAppendPrintf(entry, "by kid%d {\n", KidIdentifier);
+    DumpMallocStatistics(entry);
+    if (UsingSmp() && IamWorkerProcess())
+        storeAppendPrintf(entry, "} by kid%d\n\n", KidIdentifier);
+#endif
+    if (IamPrimaryProcess())
+        DumpInfo(data, entry);
+}
+
+void
+Mgr::InfoAction::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(data);
+}
+
+void
+Mgr::InfoAction::unpack(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(data);
+}
diff --git a/src/mgr/InfoAction.h b/src/mgr/InfoAction.h
new file mode 100644 (file)
index 0000000..25721e0
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_INFO_ACTION_H
+#define SQUID_MGR_INFO_ACTION_H
+
+#include "mgr/Action.h"
+#include <sys/time.h>
+
+
+namespace Mgr
+{
+
+/// store general runtime information
+/// and memory usage
+class InfoActionData
+{
+public:
+    InfoActionData();
+    InfoActionData& operator += (const InfoActionData& stats);
+
+public:
+    struct timeval squid_start;
+    struct timeval current_time;
+    double client_http_clients;
+    double client_http_requests;
+    double icp_pkts_recv;
+    double icp_pkts_sent;
+    double icp_replies_queued;
+#if USE_HTCP
+    double htcp_pkts_recv;
+    double htcp_pkts_sent;
+#endif
+    double request_failure_ratio;
+    double avg_client_http_requests;
+    double avg_icp_messages;
+    double select_loops;
+    double avg_loop_time;
+    double request_hit_ratio5;
+    double request_hit_ratio60;
+    double byte_hit_ratio5;
+    double byte_hit_ratio60;
+    double request_hit_mem_ratio5;
+    double request_hit_mem_ratio60;
+    double request_hit_disk_ratio5;
+    double request_hit_disk_ratio60;
+    double store_swap_size;
+    double store_swap_max_size;
+    double store_mem_size;
+    double store_pages_max;
+    double store_mem_used;
+    double objects_size;
+    double unlink_requests;
+    double http_requests5;
+    double http_requests60;
+    double cache_misses5;
+    double cache_misses60;
+    double cache_hits5;
+    double cache_hits60;
+    double near_hits5;
+    double near_hits60;
+    double not_modified_replies5;
+    double not_modified_replies60;
+    double dns_lookups5;
+    double dns_lookups60;
+    double icp_queries5;
+    double icp_queries60;
+    double up_time;
+    double cpu_time;
+    double cpu_usage;
+    double cpu_usage5;
+    double cpu_usage60;
+#if HAVE_SBRK
+    double proc_data_seg;
+#endif
+    double maxrss;
+    double page_faults;
+#if HAVE_MSTATS && HAVE_GNUMALLOC_H
+    double ms_bytes_total;
+    double ms_bytes_free;
+#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+    double mp_arena;
+    double mp_uordblks;
+    double mp_ordblks;
+    double mp_usmblks;
+    double mp_smblks;
+    double mp_hblkhd;
+    double mp_hblks;
+    double mp_fsmblks;
+    double mp_fordblks;
+#if HAVE_STRUCT_MALLINFO_MXFAST
+    double mp_mxfast;
+    double mp_nlblks;
+    double mp_grain;
+    double mp_uordbytes;
+    double mp_allocated;
+    double mp_treeoverhead;
+#endif
+#endif
+    double total_accounted;
+#if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+    double mem_pool_allocated;
+#endif
+    double gb_saved_count;
+    double gb_freed_count;
+    double max_fd;
+    double biggest_fd;
+    double number_fd;
+    double opening_fd;
+    double num_fd_free;
+    double reserved_fd;
+    double store_open_disk_fd;
+    double store_entries;
+    double store_mem_entries;
+    double hot_obj_count;
+    double n_disk_objects;
+    unsigned int count;
+};
+
+/// implement aggregated 'info' action
+class InfoAction: public Action
+{
+protected:
+    InfoAction(const CommandPointer &cmd);
+
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void add(const Action& action);
+    virtual void respond(const Request& request);
+    virtual void pack(Ipc::TypedMsgHdr& msg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& msg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    InfoActionData data;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_INFO_ACTION_H */
diff --git a/src/mgr/Inquirer.cc b/src/mgr/Inquirer.cc
new file mode 100644 (file)
index 0000000..bd36180
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CommCalls.h"
+#include "HttpReply.h"
+#include "ipc/Coordinator.h"
+#include "mgr/ActionWriter.h"
+#include "mgr/Command.h"
+#include "mgr/Inquirer.h"
+#include "mgr/Request.h"
+#include "mgr/Response.h"
+#include "SquidTime.h"
+#include <memory>
+#include <algorithm>
+
+
+CBDATA_NAMESPACED_CLASS_INIT(Mgr, Inquirer);
+
+Mgr::Inquirer::RequestsMap Mgr::Inquirer::TheRequestsMap;
+unsigned int Mgr::Inquirer::LastRequestId = 0;
+
+/// compare Ipc::StrandCoord using kidId, for std::sort() below
+static bool
+LesserStrandByKidId(const Ipc::StrandCoord &c1, const Ipc::StrandCoord &c2) {
+    return c1.kidId < c2.kidId;
+}
+
+Mgr::Inquirer::Inquirer(Action::Pointer anAction, int aFd, 
+    const Request &aCause, const Ipc::StrandCoords &coords):
+    AsyncJob("Mgr::Inquirer"),
+    aggrAction(anAction),
+    cause(aCause),
+    fd(aFd),
+    strands(coords), pos(strands.begin()),
+    requestId(0), closer(NULL), timeout(aggrAction->atomic() ? 10 : 100)
+{
+    debugs(16, 5, HERE << "FD " << aFd << " action: " << aggrAction);
+
+    // order by ascending kid IDs; useful for non-aggregatable stats
+    std::sort(strands.begin(), strands.end(), LesserStrandByKidId);
+
+    closer = asyncCall(16, 5, "Mgr::Inquirer::noteCommClosed",
+        CommCbMemFunT<Inquirer, CommCloseCbParams>(this, &Inquirer::noteCommClosed));
+    comm_add_close_handler(fd, closer);
+}
+
+Mgr::Inquirer::~Inquirer()
+{
+    debugs(16, 5, HERE);
+    close();
+}
+
+/// closes our copy of the client HTTP connection socket
+void
+Mgr::Inquirer::close() {
+    if (fd >= 0) {
+        removeCloseHandler();
+        comm_close(fd);
+        fd = -1;
+    }
+}
+
+void
+Mgr::Inquirer::removeCloseHandler()
+{
+    if (closer != NULL) {
+        comm_remove_close_handler(fd, closer);
+        closer = NULL;
+    }
+}
+
+void
+Mgr::Inquirer::start()
+{
+    debugs(16, 5, HERE);
+    Must(fd >= 0);
+    Must(aggrAction != NULL);
+
+    std::auto_ptr<HttpReply> reply(new HttpReply);
+    reply->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
+    reply->header.putStr(HDR_CONNECTION, "close"); // until we chunk response
+    std::auto_ptr<MemBuf> replyBuf(reply->pack());
+    writer = asyncCall(16, 5, "Mgr::Inquirer::noteWroteHeader",
+        CommCbMemFunT<Inquirer, CommIoCbParams>(this, &Inquirer::noteWroteHeader));
+    comm_write_mbuf(fd, replyBuf.get(), writer);
+}
+
+/// called when we wrote the response header
+void
+Mgr::Inquirer::noteWroteHeader(const CommIoCbParams& params)
+{
+    debugs(16, 5, HERE);
+    writer = NULL;
+    Must(params.flag == COMM_OK);
+    Must(params.fd == fd);
+    Must(params.size != 0);
+    // start inquiries at the initial pos
+    inquire();
+}
+
+void
+Mgr::Inquirer::inquire()
+{
+    if (pos == strands.end()) {
+        Must(done());
+        return;
+    }
+
+    Must(requestId == 0);
+    AsyncCall::Pointer callback = asyncCall(16, 5, "Mgr::Inquirer::handleRemoteAck",
+        HandleAckDialer(this, &Inquirer::handleRemoteAck, Response()));
+    if (++LastRequestId == 0) // don't use zero value as requestId
+        ++LastRequestId;
+    requestId = LastRequestId;
+    const int kidId = pos->kidId;
+    debugs(16, 4, HERE << "inquire kid: " << kidId << status());
+    TheRequestsMap[requestId] = callback;
+    Request mgrRequest(KidIdentifier, requestId, fd,
+        aggrAction->command().params);
+    Ipc::TypedMsgHdr message;
+    mgrRequest.pack(message);
+    Ipc::SendMessage(Ipc::Port::MakeAddr(Ipc::strandAddrPfx, kidId), message);
+    eventAdd("Mgr::Inquirer::requestTimedOut", &Inquirer::RequestTimedOut,
+        this, timeout, 0, false);
+}
+
+/// called when a strand is done writing its output
+void
+Mgr::Inquirer::handleRemoteAck(const Response& response)
+{
+    debugs(16, 4, HERE << status());
+    requestId = 0;
+    removeTimeoutEvent();
+    if (response.hasAction())
+        aggrAction->add(response.getAction());
+    Must(!done()); // or we should not be called
+    ++pos; // advance after a successful inquiry
+    inquire();
+}
+
+/// called when the HTTP client or some external force closed our socket
+void
+Mgr::Inquirer::noteCommClosed(const CommCloseCbParams& params)
+{
+    debugs(16, 5, HERE);
+    Must(fd < 0 || fd == params.fd);
+    fd = -1;
+    mustStop("commClosed");
+}
+
+void
+Mgr::Inquirer::swanSong()
+{
+    debugs(16, 5, HERE);
+    removeTimeoutEvent();
+    if (requestId > 0) {
+        DequeueRequest(requestId);
+        requestId = 0;
+    }
+    if (aggrAction->aggregatable()) {
+        removeCloseHandler();
+        AsyncJob::Start(new ActionWriter(aggrAction, fd));
+        fd = -1; // should not close fd because we passed it to ActionWriter
+    }
+    close();
+}
+
+bool
+Mgr::Inquirer::doneAll() const
+{
+    return !writer && pos == strands.end();
+}
+
+/// returns and forgets the right Inquirer callback for strand request
+AsyncCall::Pointer
+Mgr::Inquirer::DequeueRequest(unsigned int requestId)
+{
+    debugs(16, 3, HERE << " requestId " << requestId);
+    Must(requestId != 0);
+    AsyncCall::Pointer call;
+    RequestsMap::iterator request = TheRequestsMap.find(requestId);
+    if (request != TheRequestsMap.end()) {
+        call = request->second;
+        Must(call != NULL);
+        TheRequestsMap.erase(request);
+    }
+    return call;
+}
+
+void
+Mgr::Inquirer::HandleRemoteAck(const Mgr::Response& response)
+{
+    Must(response.requestId != 0);
+    AsyncCall::Pointer call = DequeueRequest(response.requestId);
+    if (call != NULL) {
+        HandleAckDialer* dialer = dynamic_cast<HandleAckDialer*>(call->getDialer());
+        Must(dialer);
+        dialer->arg1 = response;
+        ScheduleCallHere(call);
+    }
+}
+
+/// called when we are no longer waiting for the strand to respond
+void
+Mgr::Inquirer::removeTimeoutEvent()
+{
+    if (eventFind(&Inquirer::RequestTimedOut, this))
+        eventDelete(&Inquirer::RequestTimedOut, this);
+}
+
+/// Mgr::Inquirer::requestTimedOut wrapper
+void
+Mgr::Inquirer::RequestTimedOut(void* param)
+{
+    debugs(16, 3, HERE);
+    Must(param != NULL);
+    Inquirer* cmi = static_cast<Inquirer*>(param);
+    // use async call to enable job call protection that time events lack
+    CallJobHere(16, 5, cmi, Mgr::Inquirer, requestTimedOut);
+}
+
+/// called when the strand failed to respond (or finish responding) in time
+void
+Mgr::Inquirer::requestTimedOut()
+{
+    debugs(16, 3, HERE);
+    if (requestId != 0) {
+        DequeueRequest(requestId);
+        requestId = 0;
+        Must(!done()); // or we should not be called
+        ++pos; // advance after a failed inquiry
+        inquire();
+    }
+}
+
+const char*
+Mgr::Inquirer::status() const
+{
+    static MemBuf buf;
+    buf.reset();
+    buf.Printf(" [FD %d, requestId %u]", fd, requestId);
+    buf.terminate();
+    return buf.content();
+}
diff --git a/src/mgr/Inquirer.h b/src/mgr/Inquirer.h
new file mode 100644 (file)
index 0000000..c59530d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_INQUIRER_H
+#define SQUID_MGR_INQUIRER_H
+
+#include "base/AsyncJobCalls.h"
+#include "base/AsyncJob.h"
+#include "ipc/StrandCoords.h"
+#include "MemBuf.h"
+#include "mgr/Action.h"
+#include "mgr/Request.h"
+#include <map>
+
+class CommIoCbParams;
+class CommCloseCbParams;
+
+namespace Mgr
+{
+
+/// Coordinator's job that sends a cache manage request to each strand,
+/// aggregating individual strand responses and dumping the result if needed
+class Inquirer: public AsyncJob
+{
+public:
+    Inquirer(Action::Pointer anAction, int aFd, const Request &aCause,
+        const Ipc::StrandCoords &coords);
+    virtual ~Inquirer();
+
+    /// finds and calls the right Inquirer upon strand's response
+    static void HandleRemoteAck(const Mgr::Response& response);
+
+protected:
+    /* AsyncJob API */
+    virtual void start();
+    virtual void swanSong();
+    virtual bool doneAll() const;
+    virtual const char *status() const;
+
+private:
+    typedef UnaryMemFunT<Inquirer, Response, const Response&> HandleAckDialer;
+
+    void inquire();
+    void noteWroteHeader(const CommIoCbParams& params);
+    void noteCommClosed(const CommCloseCbParams& params);
+
+    void handleRemoteAck(const Response& response);
+
+    static AsyncCall::Pointer DequeueRequest(unsigned int requestId);
+
+    static void RequestTimedOut(void* param);
+    void requestTimedOut();
+    void removeTimeoutEvent();
+
+    void close();
+    void removeCloseHandler();
+
+private:
+    Action::Pointer aggrAction; //< action to aggregate
+
+    Request cause; ///< cache manager request received from HTTP client
+    int fd; ///< HTTP client socket descriptor
+
+    Ipc::StrandCoords strands; ///< all strands we want to query, in order
+    Ipc::StrandCoords::const_iterator pos; ///< strand we should query now
+
+    unsigned int requestId; ///< ID of our outstanding request to strand
+    AsyncCall::Pointer writer; ///< comm_write callback
+    AsyncCall::Pointer closer; ///< comm_close handler
+    const double timeout; ///< number of seconds to wait for strand response
+
+    /// maps requestId to Inquirer::handleRemoteAck callback
+    typedef std::map<unsigned int, AsyncCall::Pointer> RequestsMap;
+    static RequestsMap TheRequestsMap; ///< pending strand requests
+
+    static unsigned int LastRequestId; ///< last requestId used
+
+    CBDATA_CLASS2(Inquirer);
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_INQUIRER_H */
diff --git a/src/mgr/IntervalAction.cc b/src/mgr/IntervalAction.cc
new file mode 100644 (file)
index 0000000..3c8d5dd
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/IntervalAction.h"
+#include "SquidMath.h"
+#include "Store.h"
+
+
+extern void GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours);
+extern void DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry);
+
+Mgr::IntervalActionData::IntervalActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+Mgr::IntervalActionData&
+Mgr::IntervalActionData::operator += (const IntervalActionData& stats)
+{
+    if (!timerisset(&sample_start_time) || timercmp(&sample_start_time, &stats.sample_start_time, >))
+        sample_start_time = stats.sample_start_time;
+    if (timercmp(&sample_end_time, &stats.sample_end_time, <))
+        sample_end_time = stats.sample_end_time;
+    client_http_requests += stats.client_http_requests;
+    client_http_hits += stats.client_http_hits;
+    client_http_errors += stats.client_http_errors;
+    client_http_kbytes_in += stats.client_http_kbytes_in;
+    client_http_kbytes_out += stats.client_http_kbytes_out;
+    client_http_all_median_svc_time += stats.client_http_all_median_svc_time;
+    client_http_miss_median_svc_time += stats.client_http_miss_median_svc_time;
+    client_http_nm_median_svc_time += stats.client_http_nm_median_svc_time;
+    client_http_nh_median_svc_time += stats.client_http_nh_median_svc_time;
+    client_http_hit_median_svc_time += stats.client_http_hit_median_svc_time;
+    server_all_requests += stats.server_all_requests;
+    server_all_errors += stats.server_all_errors;
+    server_all_kbytes_in += stats.server_all_kbytes_in;
+    server_all_kbytes_out += stats.server_all_kbytes_out;
+    server_http_requests += stats.server_http_requests;
+    server_http_errors += stats.server_http_errors;
+    server_http_kbytes_in += stats.server_http_kbytes_in;
+    server_http_kbytes_out += stats.server_http_kbytes_out;
+    server_ftp_requests += stats.server_ftp_requests;
+    server_ftp_errors += stats.server_ftp_errors;
+    server_ftp_kbytes_in += stats.server_ftp_kbytes_in;
+    server_ftp_kbytes_out += stats.server_ftp_kbytes_out;
+    server_other_requests += stats.server_other_requests;
+    server_other_errors += stats.server_other_errors;
+    server_other_kbytes_in += stats.server_other_kbytes_in;
+    server_other_kbytes_out += stats.server_other_kbytes_out;
+    icp_pkts_sent += stats.icp_pkts_sent;
+    icp_pkts_recv += stats.icp_pkts_recv;
+    icp_queries_sent += stats.icp_queries_sent;
+    icp_replies_sent += stats.icp_replies_sent;
+    icp_queries_recv += stats.icp_queries_recv;
+    icp_replies_recv += stats.icp_replies_recv;
+    icp_replies_queued += stats.icp_replies_queued;
+    icp_query_timeouts += stats.icp_query_timeouts;
+    icp_kbytes_sent += stats.icp_kbytes_sent;
+    icp_kbytes_recv += stats.icp_kbytes_recv;
+    icp_q_kbytes_sent += stats.icp_q_kbytes_sent;
+    icp_r_kbytes_sent += stats.icp_r_kbytes_sent;
+    icp_q_kbytes_recv += stats.icp_q_kbytes_recv;
+    icp_r_kbytes_recv += stats.icp_r_kbytes_recv;
+    icp_query_median_svc_time += stats.icp_query_median_svc_time;
+    icp_reply_median_svc_time += stats.icp_reply_median_svc_time;
+    dns_median_svc_time += stats.dns_median_svc_time;
+    unlink_requests += stats.unlink_requests;
+    page_faults += stats.page_faults;
+    select_loops += stats.select_loops;
+    select_fds += stats.select_fds;
+    average_select_fd_period += stats.average_select_fd_period;
+    median_select_fds += stats.median_select_fds;
+    swap_outs += stats.swap_outs;
+    swap_ins += stats.swap_ins;
+    swap_files_cleaned += stats.swap_files_cleaned;
+    aborted_requests += stats.aborted_requests;
+    syscalls_disk_opens += stats.syscalls_disk_opens;
+    syscalls_disk_closes += stats.syscalls_disk_closes;
+    syscalls_disk_reads += stats.syscalls_disk_reads;
+    syscalls_disk_writes += stats.syscalls_disk_writes;
+    syscalls_disk_seeks += stats.syscalls_disk_seeks;
+    syscalls_disk_unlinks += stats.syscalls_disk_unlinks;
+    syscalls_sock_accepts += stats.syscalls_sock_accepts;
+    syscalls_sock_sockets += stats.syscalls_sock_sockets;
+    syscalls_sock_connects += stats.syscalls_sock_connects;
+    syscalls_sock_binds += stats.syscalls_sock_binds;
+    syscalls_sock_closes += stats.syscalls_sock_closes;
+    syscalls_sock_reads += stats.syscalls_sock_reads;
+    syscalls_sock_writes += stats.syscalls_sock_writes;
+    syscalls_sock_recvfroms += stats.syscalls_sock_recvfroms;
+    syscalls_sock_sendtos += stats.syscalls_sock_sendtos;
+    syscalls_selects += stats.syscalls_selects;
+    cpu_time += stats.cpu_time;
+    wall_time += stats.wall_time;
+    ++count;
+
+    return *this;
+}
+
+Mgr::IntervalAction::Pointer
+Mgr::IntervalAction::Create5min(const CommandPointer &cmd)
+{
+    return new IntervalAction(cmd, 5, 0);
+}
+
+Mgr::IntervalAction::Pointer
+Mgr::IntervalAction::Create60min(const CommandPointer &cmd)
+{
+    return new IntervalAction(cmd, 60, 0);
+}
+
+Mgr::IntervalAction::IntervalAction(const CommandPointer &cmd, int aMinutes, int aHours):
+    Action(cmd), minutes(aMinutes), hours(aHours), data()
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::IntervalAction::add(const Action& action)
+{
+    debugs(16, 5, HERE);
+    data += dynamic_cast<const IntervalAction&>(action).data;
+}
+
+void
+Mgr::IntervalAction::collect()
+{
+    GetAvgStat(data, minutes, hours);
+}
+
+void
+Mgr::IntervalAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+    DumpAvgStat(data, entry);
+}
+
+void
+Mgr::IntervalAction::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(data);
+}
+
+void
+Mgr::IntervalAction::unpack(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(data);
+}
diff --git a/src/mgr/IntervalAction.h b/src/mgr/IntervalAction.h
new file mode 100644 (file)
index 0000000..fb1b80d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_INTERVAL_ACTION_H
+#define SQUID_MGR_INTERVAL_ACTION_H
+
+#include "mgr/Action.h"
+#include <sys/time.h>
+
+
+namespace Mgr
+{
+
+/// auxiliary class which store stats computed
+/// from StatCounters for specified interval
+class IntervalActionData
+{
+public:
+    IntervalActionData();
+    IntervalActionData& operator += (const IntervalActionData& stats);
+
+public:
+    struct timeval sample_start_time;
+    struct timeval sample_end_time;
+    double client_http_requests;
+    double client_http_hits;
+    double client_http_errors;
+    double client_http_kbytes_in;
+    double client_http_kbytes_out;
+    double client_http_all_median_svc_time;
+    double client_http_miss_median_svc_time;
+    double client_http_nm_median_svc_time;
+    double client_http_nh_median_svc_time;
+    double client_http_hit_median_svc_time;
+    double server_all_requests;
+    double server_all_errors;
+    double server_all_kbytes_in;
+    double server_all_kbytes_out;
+    double server_http_requests;
+    double server_http_errors;
+    double server_http_kbytes_in;
+    double server_http_kbytes_out;
+    double server_ftp_requests;
+    double server_ftp_errors;
+    double server_ftp_kbytes_in;
+    double server_ftp_kbytes_out;
+    double server_other_requests;
+    double server_other_errors;
+    double server_other_kbytes_in;
+    double server_other_kbytes_out;
+    double icp_pkts_sent;
+    double icp_pkts_recv;
+    double icp_queries_sent;
+    double icp_replies_sent;
+    double icp_queries_recv;
+    double icp_replies_recv;
+    double icp_replies_queued;
+    double icp_query_timeouts;
+    double icp_kbytes_sent;
+    double icp_kbytes_recv;
+    double icp_q_kbytes_sent;
+    double icp_r_kbytes_sent;
+    double icp_q_kbytes_recv;
+    double icp_r_kbytes_recv;
+    double icp_query_median_svc_time;
+    double icp_reply_median_svc_time;
+    double dns_median_svc_time;
+    double unlink_requests;
+    double page_faults;
+    double select_loops;
+    double select_fds;
+    double average_select_fd_period;
+    double median_select_fds;
+    double swap_outs;
+    double swap_ins;
+    double swap_files_cleaned;
+    double aborted_requests;
+    double syscalls_disk_opens;
+    double syscalls_disk_closes;
+    double syscalls_disk_reads;
+    double syscalls_disk_writes;
+    double syscalls_disk_seeks;
+    double syscalls_disk_unlinks;
+    double syscalls_sock_accepts;
+    double syscalls_sock_sockets;
+    double syscalls_sock_connects;
+    double syscalls_sock_binds;
+    double syscalls_sock_closes;
+    double syscalls_sock_reads;
+    double syscalls_sock_writes;
+    double syscalls_sock_recvfroms;
+    double syscalls_sock_sendtos;
+    double syscalls_selects;
+    double cpu_time;
+    double wall_time;
+    unsigned int count;
+};
+
+/// implement aggregated interval actions
+class IntervalAction: public Action
+{
+protected:
+    IntervalAction(const CommandPointer &cmd, int aMinutes, int aHours);
+
+public:
+    static Pointer Create5min(const CommandPointer &cmd);
+    static Pointer Create60min(const CommandPointer &cmd);
+    /* Action API */
+    virtual void add(const Action& action);
+    virtual void pack(Ipc::TypedMsgHdr& msg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& msg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    int minutes;
+    int hours;
+    IntervalActionData data;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_INTERVAL_ACTION_H */
diff --git a/src/mgr/IoAction.cc b/src/mgr/IoAction.cc
new file mode 100644 (file)
index 0000000..87ab792
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/IoAction.h"
+#include "SquidMath.h"
+#include "Store.h"
+
+
+extern void GetIoStats(Mgr::IoActionData& stats);
+extern void DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry);
+
+Mgr::IoActionData::IoActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+Mgr::IoActionData&
+Mgr::IoActionData::operator += (const IoActionData& stats)
+{
+    http_reads += stats.http_reads;
+    for (int i = 0; i < _iostats::histSize; ++i)
+        http_read_hist[i] += stats.http_read_hist[i];
+    ftp_reads += stats.ftp_reads;
+    for (int i = 0; i < _iostats::histSize; ++i)
+        ftp_read_hist[i] += stats.ftp_read_hist[i];
+    gopher_reads += stats.gopher_reads;
+    for (int i = 0; i < _iostats::histSize; ++i)
+        gopher_read_hist[i] += stats.gopher_read_hist[i];
+
+    return *this;
+}
+
+Mgr::IoAction::Pointer
+Mgr::IoAction::Create(const CommandPointer &cmd)
+{
+    return new IoAction(cmd);
+}
+
+Mgr::IoAction::IoAction(const CommandPointer &cmd):
+    Action(cmd), data()
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::IoAction::add(const Action& action)
+{
+    debugs(16, 5, HERE);
+    data += dynamic_cast<const IoAction&>(action).data;
+}
+
+void
+Mgr::IoAction::collect()
+{
+    GetIoStats(data);
+}
+
+void
+Mgr::IoAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+    DumpIoStats(data, entry);
+}
+
+void
+Mgr::IoAction::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(data);
+}
+
+void
+Mgr::IoAction::unpack(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(data);
+}
diff --git a/src/mgr/IoAction.h b/src/mgr/IoAction.h
new file mode 100644 (file)
index 0000000..812eda6
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_IO_ACTION_H
+#define SQUID_MGR_IO_ACTION_H
+
+#include "mgr/Action.h"
+#include "structs.h" /* _iostats::histSize */
+
+namespace Mgr
+{
+
+/// store server-side network read() size histograms
+class IoActionData
+{
+public:
+    IoActionData();
+    IoActionData& operator += (const IoActionData& stats);
+
+public:
+    double http_reads;
+    double ftp_reads;
+    double gopher_reads;
+    double http_read_hist[_iostats::histSize];
+    double ftp_read_hist[_iostats::histSize];
+    double gopher_read_hist[_iostats::histSize];
+};
+
+/// implement aggregated 'io' action
+class IoAction: public Action
+{
+protected:
+    IoAction(const CommandPointer &cmd);
+
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void add(const Action& action);
+    virtual void pack(Ipc::TypedMsgHdr& msg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& msg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    IoActionData data;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_IO_ACTION_H */
diff --git a/src/mgr/Makefile.am b/src/mgr/Makefile.am
new file mode 100644 (file)
index 0000000..2d7d543
--- /dev/null
@@ -0,0 +1,47 @@
+include $(top_srcdir)/src/Common.am
+include $(top_srcdir)/src/TestHeaders.am
+
+noinst_LTLIBRARIES = libmgr.la
+
+libmgr_la_SOURCES = \
+       Action.cc \
+       ActionCreator.h \
+       Action.h \
+       ActionParams.cc \
+       ActionParams.h \
+       ActionProfile.h \
+       ActionWriter.cc \
+       ActionWriter.h \
+       BasicActions.cc \
+       BasicActions.h \
+       Command.cc \
+       Command.h \
+       CountersAction.cc \
+       CountersAction.h \
+       Filler.cc \
+       Filler.h \
+       Forwarder.cc \
+       Forwarder.h \
+       forward.h \
+       FunAction.cc \
+       FunAction.h \
+       InfoAction.cc \
+       InfoAction.h \
+       Inquirer.cc \
+       Inquirer.h \
+       IntervalAction.cc \
+       IntervalAction.h \
+       IoAction.cc \
+       IoAction.h \
+       Registration.cc \
+       Registration.h \
+       Request.cc \
+       Request.h \
+       Response.cc \
+       Response.h \
+       ServiceTimesAction.cc \
+       ServiceTimesAction.h \
+       StoreIoAction.cc \
+       StoreIoAction.h \
+       StoreToCommWriter.cc \
+       StoreToCommWriter.h
diff --git a/src/mgr/Registration.cc b/src/mgr/Registration.cc
new file mode 100644 (file)
index 0000000..e6da0e7
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "CacheManager.h"
+#include "mgr/Registration.h"
+
+void
+Mgr::RegisterAction(char const * action, char const * desc,
+    OBJH * handler,
+    int pw_req_flag, int atomic)
+{
+    CacheManager::GetInstance()->registerProfile(action, desc, handler,
+        pw_req_flag, atomic);
+}
+
+void
+Mgr::RegisterAction(char const * action, char const * desc,
+    ClassActionCreationHandler *handler,
+    int pw_req_flag, int atomic)
+{
+    CacheManager::GetInstance()->registerProfile(action, desc, handler,
+        pw_req_flag, atomic);
+}
diff --git a/src/mgr/Registration.h b/src/mgr/Registration.h
new file mode 100644 (file)
index 0000000..caaa10e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_REGISTRATION_H
+#define SQUID_MGR_REGISTRATION_H
+
+#include "mgr/forward.h"
+#include "typedefs.h"   /* for OBJH */
+
+namespace Mgr
+{
+
+void RegisterAction(char const * action, char const * desc,
+    OBJH * handler,
+       int pw_req_flag, int atomic);
+
+void RegisterAction(char const * action, char const * desc,
+    ClassActionCreationHandler *handler,
+    int pw_req_flag, int atomic);
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_REGISTRATION_H */
diff --git a/src/mgr/Request.cc b/src/mgr/Request.cc
new file mode 100644 (file)
index 0000000..b80ad19
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/Messages.h"
+#include "mgr/ActionParams.h"
+#include "mgr/Request.h"
+
+
+Mgr::Request::Request(int aRequestorId, unsigned int aRequestId, int aFd,
+    const ActionParams &aParams):
+    requestorId(aRequestorId), requestId(aRequestId),
+    fd(aFd), params(aParams)
+{
+    Must(requestorId > 0);
+    Must(requestId != 0);
+}
+
+Mgr::Request::Request(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrRequest);
+    msg.getPod(requestorId);
+    msg.getPod(requestId);
+    params = ActionParams(msg);
+
+    fd = msg.getFd();
+}
+
+void
+Mgr::Request::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrRequest);
+    msg.putPod(requestorId);
+    msg.putPod(requestId);
+    params.pack(msg);
+
+    msg.putFd(fd);
+}
diff --git a/src/mgr/Request.h b/src/mgr/Request.h
new file mode 100644 (file)
index 0000000..edeaaf4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_REQUEST_H
+#define SQUID_MGR_REQUEST_H
+
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/ActionParams.h"
+
+
+namespace Mgr
+{
+
+/// cache manager request 
+class Request
+{
+public:
+    Request(int aRequestorId, unsigned int aRequestId, int aFd,
+        const ActionParams &aParams);
+
+    explicit Request(const Ipc::TypedMsgHdr& msg); ///< from recvmsg()
+    void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg()
+
+public:
+    int requestorId; ///< kidId of the requestor; used for response destination
+    unsigned int requestId; ///< unique for sender; matches request w/ response
+    int fd; ///< HTTP client connection descriptor
+
+    ActionParams params; ///< action name and parameters
+};
+
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_REQUEST_H */
diff --git a/src/mgr/Response.cc b/src/mgr/Response.cc
new file mode 100644 (file)
index 0000000..1462e6c
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CacheManager.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/ActionCreator.h"
+#include "mgr/ActionProfile.h"
+#include "mgr/Response.h"
+
+
+std::ostream& Mgr::operator << (std::ostream &os, const Response& response)
+{
+    os << "response: {requestId: " << response.requestId << '}';
+    return os;
+}
+
+Mgr::Response::Response(unsigned int aRequestId, Action::Pointer anAction):
+    requestId(aRequestId), action(anAction)
+{
+    Must(!action || action->name()); // if there is an action, it must be named
+}
+
+Mgr::Response::Response(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(requestId);
+    Must(requestId != 0);
+
+    if (msg.hasMoreData()) {
+        String actionName;
+        msg.getString(actionName);
+        action = CacheManager::GetInstance()->createNamedAction(actionName.termedBuf());
+        Must(hasAction());
+        action->unpack(msg);
+    }
+}
+
+void
+Mgr::Response::pack(Ipc::TypedMsgHdr& msg) const
+{
+    Must(requestId != 0);
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(requestId);
+    if (hasAction()) {
+        msg.putString(action->name());
+        action->pack(msg);
+    }
+}
+
+bool
+Mgr::Response::hasAction() const
+{
+    return action != NULL;
+}
+
+const Mgr::Action&
+Mgr::Response::getAction() const
+{
+    Must(hasAction());
+    return *action;
+}
diff --git a/src/mgr/Response.h b/src/mgr/Response.h
new file mode 100644 (file)
index 0000000..7b75992
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_RESPONSE_H
+#define SQUID_MGR_RESPONSE_H
+
+#include "mgr/Action.h"
+
+
+namespace Mgr
+{
+
+/// A response to Mgr::Request.
+/// May carry strand action data to be aggregated with data from other strands.
+class Response
+{
+public:
+    Response(unsigned int aRequestId = 0, Action::Pointer anAction = NULL);
+
+    explicit Response(const Ipc::TypedMsgHdr& msg); ///< from recvmsg()
+    void pack(Ipc::TypedMsgHdr& msg) const; ///< prepare for sendmsg()
+    bool hasAction() const; ///< whether response contain action object
+    const Action& getAction() const; ///< returns action object
+
+public:
+    unsigned int requestId; ///< ID of request we are responding to
+    Action::Pointer action; ///< action relating to response
+};
+
+extern std::ostream& operator <<(std::ostream &os, const Response &response);
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_RESPONSE_H */
diff --git a/src/mgr/ServiceTimesAction.cc b/src/mgr/ServiceTimesAction.cc
new file mode 100644 (file)
index 0000000..3c083c3
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/ServiceTimesAction.h"
+#include "Store.h"
+
+
+extern void GetServiceTimesStats(Mgr::ServiceTimesActionData& stats);
+extern void DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry);
+
+Mgr::ServiceTimesActionData::ServiceTimesActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+Mgr::ServiceTimesActionData&
+Mgr::ServiceTimesActionData::operator += (const ServiceTimesActionData& stats)
+{
+    for (int i = 0; i < seriesSize; ++i) {
+        http_requests5[i] += stats.http_requests5[i];
+        http_requests60[i] += stats.http_requests60[i];
+
+        cache_misses5[i] += stats.cache_misses5[i];
+        cache_misses60[i] += stats.cache_misses60[i];
+
+        cache_hits5[i] += stats.cache_hits5[i];
+        cache_hits60[i] += stats.cache_hits60[i];
+
+        near_hits5[i] += stats.near_hits5[i];
+        near_hits60[i] += stats.near_hits60[i];
+
+        not_modified_replies5[i] += stats.not_modified_replies5[i];
+        not_modified_replies60[i] += stats.not_modified_replies60[i];
+
+        dns_lookups5[i] += stats.dns_lookups5[i];
+        dns_lookups60[i] += stats.dns_lookups60[i];
+
+        icp_queries5[i] += stats.icp_queries5[i];
+        icp_queries60[i] += stats.icp_queries60[i];
+    }
+    ++count;
+
+    return *this;
+}
+
+Mgr::ServiceTimesAction::Pointer
+Mgr::ServiceTimesAction::Create(const CommandPointer &cmd)
+{
+    return new ServiceTimesAction(cmd);
+}
+
+Mgr::ServiceTimesAction::ServiceTimesAction(const CommandPointer &cmd):
+    Action(cmd), data()
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::ServiceTimesAction::add(const Action& action)
+{
+    debugs(16, 5, HERE);
+    data += dynamic_cast<const ServiceTimesAction&>(action).data;
+}
+
+void
+Mgr::ServiceTimesAction::collect()
+{
+    debugs(16, 5, HERE);
+    GetServiceTimesStats(data);
+}
+
+void
+Mgr::ServiceTimesAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+    DumpServiceTimesStats(data, entry);
+}
+
+void
+Mgr::ServiceTimesAction::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(data);
+}
+
+void
+Mgr::ServiceTimesAction::unpack(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(data);
+}
diff --git a/src/mgr/ServiceTimesAction.h b/src/mgr/ServiceTimesAction.h
new file mode 100644 (file)
index 0000000..f8191a3
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_SERVICE_TIMES_ACTION_H
+#define SQUID_MGR_SERVICE_TIMES_ACTION_H
+
+#include "mgr/Action.h"
+
+
+namespace Mgr
+{
+
+/// store service times for 5 and 60 min
+class ServiceTimesActionData
+{
+public:
+    enum { seriesSize = 19 };
+
+public:
+    ServiceTimesActionData();
+    ServiceTimesActionData& operator += (const ServiceTimesActionData& stats);
+
+public:
+    double http_requests5[seriesSize];
+    double http_requests60[seriesSize];
+    double cache_misses5[seriesSize];
+    double cache_misses60[seriesSize];
+    double cache_hits5[seriesSize];
+    double cache_hits60[seriesSize];
+    double near_hits5[seriesSize];
+    double near_hits60[seriesSize];
+    double not_modified_replies5[seriesSize];
+    double not_modified_replies60[seriesSize];
+    double dns_lookups5[seriesSize];
+    double dns_lookups60[seriesSize];
+    double icp_queries5[seriesSize];
+    double icp_queries60[seriesSize];
+    unsigned int count;
+};
+
+/// implement aggregated 'service_times' action
+class ServiceTimesAction: public Action
+{
+protected:
+    ServiceTimesAction(const CommandPointer &cmd);
+
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void add(const Action& action);
+    virtual void pack(Ipc::TypedMsgHdr& msg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& msg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    ServiceTimesActionData data;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_SERVICE_TIMES_ACTION_H */
diff --git a/src/mgr/StoreIoAction.cc b/src/mgr/StoreIoAction.cc
new file mode 100644 (file)
index 0000000..41866c4
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "ipc/Messages.h"
+#include "ipc/TypedMsgHdr.h"
+#include "mgr/StoreIoAction.h"
+#include "Store.h"
+
+
+Mgr::StoreIoActionData::StoreIoActionData()
+{
+    xmemset(this, 0, sizeof(*this));
+}
+
+Mgr::StoreIoActionData&
+Mgr::StoreIoActionData::operator += (const StoreIoActionData& stats)
+{
+    create_calls += stats.create_calls;
+    create_select_fail += stats.create_select_fail;
+    create_create_fail += stats.create_create_fail;
+    create_success += stats.create_success;
+
+    return *this;
+}
+
+Mgr::StoreIoAction::Pointer
+Mgr::StoreIoAction::Create(const CommandPointer &cmd)
+{
+    return new StoreIoAction(cmd);
+}
+
+Mgr::StoreIoAction::StoreIoAction(const CommandPointer &cmd):
+    Action(cmd), data()
+{
+    debugs(16, 5, HERE);
+}
+
+void
+Mgr::StoreIoAction::add(const Action& action)
+{
+    debugs(16, 5, HERE);
+    data += dynamic_cast<const StoreIoAction&>(action).data;
+}
+
+void
+Mgr::StoreIoAction::collect()
+{
+    data.create_calls = store_io_stats.create.calls;
+    data.create_select_fail = store_io_stats.create.select_fail;
+    data.create_create_fail = store_io_stats.create.create_fail;
+    data.create_success = store_io_stats.create.success;
+}
+
+void
+Mgr::StoreIoAction::dump(StoreEntry* entry)
+{
+    debugs(16, 5, HERE);
+    Must(entry != NULL);
+    storeAppendPrintf(entry, "Store IO Interface Stats\n");
+    storeAppendPrintf(entry, "create.calls %.0f\n", data.create_calls);
+    storeAppendPrintf(entry, "create.select_fail %.0f\n", data.create_select_fail);
+    storeAppendPrintf(entry, "create.create_fail %.0f\n", data.create_create_fail);
+    storeAppendPrintf(entry, "create.success %.0f\n", data.create_success);
+}
+
+void
+Mgr::StoreIoAction::pack(Ipc::TypedMsgHdr& msg) const
+{
+    msg.setType(Ipc::mtCacheMgrResponse);
+    msg.putPod(data);
+}
+
+void
+Mgr::StoreIoAction::unpack(const Ipc::TypedMsgHdr& msg)
+{
+    msg.checkType(Ipc::mtCacheMgrResponse);
+    msg.getPod(data);
+}
diff --git a/src/mgr/StoreIoAction.h b/src/mgr/StoreIoAction.h
new file mode 100644 (file)
index 0000000..c9c2db4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_STORE_IO_ACTION_H
+#define SQUID_MGR_STORE_IO_ACTION_H
+
+#include "mgr/Action.h"
+
+
+namespace Mgr
+{
+
+/// Store IO interface data
+class StoreIoActionData
+{
+public:
+    StoreIoActionData();
+    StoreIoActionData& operator += (const StoreIoActionData& stats);
+
+public:
+    double create_calls;
+    double create_select_fail;
+    double create_create_fail;
+    double create_success;
+};
+
+/// implement aggregated 'store_io' action
+class StoreIoAction: public Action
+{
+protected:
+    StoreIoAction(const CommandPointer &cmd);
+
+public:
+    static Pointer Create(const CommandPointer &cmd);
+    /* Action API */
+    virtual void add(const Action& action);
+    virtual void pack(Ipc::TypedMsgHdr& msg) const;
+    virtual void unpack(const Ipc::TypedMsgHdr& msg);
+
+protected:
+    /* Action API */
+    virtual void collect();
+    virtual void dump(StoreEntry* entry);
+
+private:
+    StoreIoActionData data;
+};
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_STORE_IO_ACTION_H */
diff --git a/src/mgr/StoreToCommWriter.cc b/src/mgr/StoreToCommWriter.cc
new file mode 100644 (file)
index 0000000..b659f40
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#include "config.h"
+#include "base/TextException.h"
+#include "CommCalls.h"
+#include "ipc/FdNotes.h"
+#include "mgr/StoreToCommWriter.h"
+#include "StoreClient.h"
+#include "Store.h"
+
+
+CBDATA_NAMESPACED_CLASS_INIT(Mgr, StoreToCommWriter);
+
+
+Mgr::StoreToCommWriter::StoreToCommWriter(int aFd, StoreEntry* anEntry):
+    AsyncJob("Mgr::StoreToCommWriter"),
+    fd(aFd), entry(anEntry), sc(NULL), writeOffset(0), closer(NULL)
+{
+    debugs(16, 6, HERE << "FD " << fd);
+    closer = asyncCall(16, 5, "Mgr::StoreToCommWriter::noteCommClosed",
+        CommCbMemFunT<StoreToCommWriter, CommCloseCbParams>(this, &StoreToCommWriter::noteCommClosed));
+    comm_add_close_handler(fd, closer);
+}
+
+Mgr::StoreToCommWriter::~StoreToCommWriter()
+{
+    debugs(16, 6, HERE);
+    assert(!entry);
+    assert(!sc);
+    close();
+}
+
+/// closes our copy of the client HTTP connection socket
+void
+Mgr::StoreToCommWriter::close()
+{
+    if (fd >= 0) {
+        if (closer != NULL) {
+            comm_remove_close_handler(fd, closer);
+            closer = NULL;
+        }
+        comm_close(fd);
+        fd = -1;
+    }
+}
+
+void
+Mgr::StoreToCommWriter::start()
+{
+    debugs(16, 6, HERE);
+    Must(fd >= 0);
+    Must(entry != NULL);
+    entry->registerAbort(&StoreToCommWriter::Abort, this);
+    sc = storeClientListAdd(entry, this);
+    Must(sc != NULL);
+
+    // initiate the receive-from-store, write-to-comm sequence
+    scheduleStoreCopy();
+}
+
+void
+Mgr::StoreToCommWriter::scheduleStoreCopy()
+{
+    debugs(16, 6, HERE);
+    Must(entry != NULL);
+    Must(sc != NULL);
+    StoreIOBuffer readBuf(sizeof(buffer), writeOffset, buffer);
+    storeClientCopy(sc, entry, readBuf, &NoteStoreCopied, this);
+}
+
+void
+Mgr::StoreToCommWriter::NoteStoreCopied(void* data, StoreIOBuffer ioBuf)
+{
+    Must(data != NULL);
+    // make sync Store call async to get async call protections and features
+    StoreToCommWriter* writer = static_cast<StoreToCommWriter*>(data);
+    typedef UnaryMemFunT<StoreToCommWriter, StoreIOBuffer> MyDialer;
+    AsyncCall::Pointer call =
+        asyncCall(16, 5, "Mgr::StoreToCommWriter::noteStoreCopied",
+            MyDialer(writer, &StoreToCommWriter::noteStoreCopied, ioBuf));
+    ScheduleCallHere(call);
+}
+
+void
+Mgr::StoreToCommWriter::noteStoreCopied(StoreIOBuffer ioBuf)
+{
+    debugs(16, 6, HERE);
+    Must(!ioBuf.flags.error);
+    if (ioBuf.length > 0)
+        scheduleCommWrite(ioBuf); // write received action results to client
+    else
+        Must(doneAll()); // otherwise, why would Store call us with no data?
+}
+
+void
+Mgr::StoreToCommWriter::scheduleCommWrite(const StoreIOBuffer& ioBuf)
+{
+    debugs(16, 6, HERE);
+    Must(fd >= 0);
+    Must(ioBuf.data != NULL);
+    // write filled buffer
+    typedef CommCbMemFunT<StoreToCommWriter, CommIoCbParams> MyDialer;
+    AsyncCall::Pointer writer =
+        asyncCall(16, 5, "Mgr::StoreToCommWriter::noteCommWrote",
+            MyDialer(this, &StoreToCommWriter::noteCommWrote));
+    comm_write(fd, ioBuf.data, ioBuf.length, writer);
+}
+
+void
+Mgr::StoreToCommWriter::noteCommWrote(const CommIoCbParams& params)
+{
+    debugs(16, 6, HERE);
+    Must(params.flag == COMM_OK);
+    Must(params.fd == fd);
+    Must(params.size != 0);
+    writeOffset += params.size;
+    if (!doneAll())
+        scheduleStoreCopy(); // retrieve the next data portion
+}
+
+void
+Mgr::StoreToCommWriter::noteCommClosed(const CommCloseCbParams& params)
+{
+    debugs(16, 6, HERE);
+    Must(fd == params.fd);
+    fd = -1;
+    mustStop("commClosed");
+}
+
+void
+Mgr::StoreToCommWriter::swanSong()
+{
+    debugs(16, 6, HERE);
+    if (entry != NULL) {
+        if (sc != NULL) {
+            storeUnregister(sc, entry, this);
+            sc = NULL;
+        }
+        entry->unregisterAbort();
+        entry->unlock();
+        entry = NULL;
+    }
+    close();
+}
+
+bool
+Mgr::StoreToCommWriter::doneAll() const
+{
+    return entry &&
+        entry->store_status == STORE_OK && // the action is over
+        writeOffset >= entry->objectLen(); // we wrote all the results
+}
+
+void
+Mgr::StoreToCommWriter::Abort(void* param)
+{
+    StoreToCommWriter* mgrWriter = static_cast<StoreToCommWriter*>(param);
+    if (mgrWriter->fd >= 0)
+        comm_close(mgrWriter->fd);
+}
+
+
+int
+Mgr::ImportHttpFdIntoComm(int fd)
+{
+    struct sockaddr_in addr;
+    socklen_t len = sizeof(addr);
+    if (getsockname(fd, reinterpret_cast<sockaddr*>(&addr), &len) == 0) {
+        Ip::Address ipAddr(addr);
+        struct addrinfo* addr_info = NULL;
+        ipAddr.GetAddrInfo(addr_info);
+        addr_info->ai_socktype = SOCK_STREAM;
+        addr_info->ai_protocol = IPPROTO_TCP;
+        comm_import_opened(fd, ipAddr, COMM_NONBLOCKING, Ipc::FdNote(Ipc::fdnHttpSocket), addr_info);
+        ipAddr.FreeAddrInfo(addr_info);
+    } else {
+        debugs(16, DBG_CRITICAL, HERE << "ERROR: FD " << fd << ' ' << xstrerror());
+        ::close(fd);
+        fd = -1;
+    }
+    return fd;
+}
diff --git a/src/mgr/StoreToCommWriter.h b/src/mgr/StoreToCommWriter.h
new file mode 100644 (file)
index 0000000..116ffdb
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_STORE_TO_COMM_WRITER_H
+#define SQUID_MGR_STORE_TO_COMM_WRITER_H
+
+#include "base/AsyncJob.h"
+#include "mgr/Action.h"
+#include "StoreIOBuffer.h"
+
+
+class store_client;
+class CommIoCbParams;
+class CommCloseCbParams;
+
+namespace Mgr
+{
+
+/// manages receive-from-store, write-to-comm, receive-... sequence
+/// for the given StoreEntry and client FD
+class StoreToCommWriter: public AsyncJob
+{
+public:
+    StoreToCommWriter(int aFd, StoreEntry *anEntry);
+    virtual ~StoreToCommWriter();
+
+protected:
+    /* AsyncJob API */
+    virtual void start();
+    virtual void swanSong();
+    virtual bool doneAll() const;
+
+    /// request more action results from the store
+    void scheduleStoreCopy();
+    /// receive some action results from the store
+    void noteStoreCopied(StoreIOBuffer ioBuf);
+    static void NoteStoreCopied(void* data, StoreIOBuffer ioBuf);
+    /// called by Store if the entry is no longer usable
+    static void Abort(void* param);
+
+    /// tell Comm to write action results
+    void scheduleCommWrite(const StoreIOBuffer& ioBuf);
+    /// called by Comm after the action results are written
+    void noteCommWrote(const CommIoCbParams& params);
+    /// called by Comm if the client socket got closed
+    void noteCommClosed(const CommCloseCbParams& params);
+
+    /// closes the local connection to the HTTP client, if any
+    void close();
+
+protected:
+    int fd; ///< HTTP client descriptor
+
+    StoreEntry* entry; ///< store entry with the cache manager response
+    store_client* sc; ///< our registration with the store
+    int64_t writeOffset; ///< number of bytes written to the client
+
+    AsyncCall::Pointer closer; ///< comm_close handler
+    char buffer[HTTP_REQBUF_SZ]; ///< action results; Store fills, Comm writes
+
+    CBDATA_CLASS2(StoreToCommWriter);
+};
+
+/// import HTTP socket fd from another strand into our Comm state
+extern int ImportHttpFdIntoComm(int fd);
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_STORE_TO_COMM_WRITER_H */
diff --git a/src/mgr/forward.h b/src/mgr/forward.h
new file mode 100644 (file)
index 0000000..ecf303a
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * $Id$
+ *
+ * DEBUG: section 16    Cache Manager API
+ *
+ */
+
+#ifndef SQUID_MGR_FORWARD_H
+#define SQUID_MGR_FORWARD_H
+
+#include "RefCount.h"
+
+namespace Mgr
+{
+
+class Action;
+class ActionCreator;
+class ActionProfile;
+class ActionWriter;
+class Command;
+class Request;
+class Response;
+
+typedef RefCount<Action> ActionPointer;
+typedef RefCount<ActionProfile> ActionProfilePointer;
+typedef RefCount<ActionCreator> ActionCreatorPointer;
+typedef RefCount<Command> CommandPointer;
+
+typedef ActionPointer (ClassActionCreationHandler)(const CommandPointer &cmd);
+
+} // namespace Mgr
+
+#endif /* SQUID_MGR_FORWARD_H */
index 0a636a8ca1cd325b7f2e325003652cbca0420068..55e8ab772550e25ea0588ef343334deaf7fcc893 100644 (file)
@@ -34,7 +34,6 @@
 #include "ProtoPort.h"
 #include "acl/FilledChecklist.h"
 #include "event.h"
-#include "CacheManager.h"
 #include "htcp.h"
 #include "HttpRequest.h"
 #include "ICP.h"
@@ -48,6 +47,7 @@
 #include "icmp/net_db.h"
 #include "ip/Address.h"
 #include "ip/tools.h"
+#include "mgr/Registration.h"
 
 /* count mcast group peers every 15 minutes */
 #define MCAST_COUNT_RATE 900
@@ -541,13 +541,12 @@ neighborRemove(peer * target)
 static void
 neighborsRegisterWithCacheManager()
 {
-    CacheManager *manager = CacheManager::GetInstance();
-    manager->registerAction("server_list",
+    Mgr::RegisterAction("server_list",
                             "Peer Cache Statistics",
                             neighborDumpPeers, 0, 1);
 
     if (theInIcpConnection >= 0) {
-        manager->registerAction("non_peers",
+        Mgr::RegisterAction("non_peers",
                                 "List of Unknown sites sending ICP messages",
                                 neighborDumpNonPeers, 0, 1);
     }
index 414b9c1d4eab8f35cf90d80ad50cda9fa3ab97ac..d024c383310128e7d0fde741b6f94629d3592e5a 100644 (file)
@@ -33,7 +33,7 @@
  */
 
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "comm.h"
 #include "pconn.h"
@@ -361,8 +361,7 @@ PconnModule::GetInstance()
 void
 PconnModule::registerWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("pconn",
+    Mgr::RegisterAction("pconn",
                    "Persistent Connection Utilization Histograms",
                    DumpWrapper, 0, 1);
 }
index fd524acfe41fdc0dd069e548b5a224ac9b16ee02..fb21b321bc0c40d2fefef26c50a93c1bc83e8cca 100644 (file)
@@ -35,9 +35,9 @@
  */
 
 #include "squid.h"
-#include "CacheManager.h"
 #include "Store.h"
 #include "HttpRequest.h"
+#include "mgr/Registration.h"
 
 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
 
@@ -157,8 +157,7 @@ peerSourceHashInit(void)
 static void
 peerSourceHashRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("sourcehash", "peer sourcehash information",
+    Mgr::RegisterAction("sourcehash", "peer sourcehash information",
                    peerSourceHashCachemgr, 0, 1);
 }
 
index b966336c4a659b84a717950d987516de6a342e95..f189cefdef1a3f5618c1eb5e8c08c13a64b1011b 100644 (file)
@@ -35,7 +35,7 @@
  */
 
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "HttpRequest.h"
 #include "auth/UserRequest.h"
@@ -159,8 +159,7 @@ peerUserHashInit(void)
 static void
 peerUserHashRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("userhash", "peer userhash information", peerUserHashCachemgr,
+    Mgr::RegisterAction("userhash", "peer userhash information", peerUserHashCachemgr,
                    0, 1);
 }
 
index 43c884a9bb5637d86114429cac39332de87b5e95..999474b5350d44bbc468eca273c02e4c4ad63829 100644 (file)
@@ -35,7 +35,7 @@
 
 #include "squid.h"
 #include "auth/UserRequest.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "fde.h"
 #include "client_side_request.h"
@@ -179,8 +179,7 @@ redirectStart(ClientHttpRequest * http, RH * handler, void *data)
 static void
 redirectRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("redirector", "URL Redirector Stats", redirectStats, 0, 1);
+    Mgr::RegisterAction("redirector", "URL Redirector Stats", redirectStats, 0, 1);
 }
 
 void
index b977e226bdbcb61a13d964df7e79e068ca30d134..e4257f812dc200e09d8dadfb08408fe7b104a806 100644 (file)
@@ -38,7 +38,7 @@
 #endif
 
 #include "squid.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "MemObject.h"
 #include "HttpRequest.h"
@@ -610,8 +610,7 @@ refreshStats(StoreEntry * sentry)
 static void
 refreshRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
+    Mgr::RegisterAction("refresh", "Refresh Algorithm Statistics", refreshStats, 0, 1);
 }
 
 void
index f16f137b297bf77dca000489d24e6fd6bb7bc539..9527f7200099afa77d12ca5b62fbaaf5858c8305 100644 (file)
@@ -36,7 +36,7 @@
 #include "event.h"
 #include "StoreClient.h"
 #include "auth/UserRequest.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "HttpRequest.h"
 #include "MemObject.h"
 #include "MemBuf.h"
 #include "SquidMath.h"
 #include "SquidTime.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"
 
 /* these are included because they expose stats calls */
 /* TODO: provide a self registration mechanism for those classes
@@ -90,22 +96,29 @@ static void statCountersCopy(StatCounters * dest, const StatCounters * orig);
 static double statPctileSvc(double, int, int);
 static void statStoreEntry(MemBuf * mb, StoreEntry * e);
 static double statCPUUsage(int minutes);
-static OBJH stat_io_get;
 static OBJH stat_objects_get;
 static OBJH stat_vmobjects_get;
 #if DEBUG_OPENFD
 static OBJH statOpenfdObj;
 #endif
 static EVH statObjects;
-static OBJH info_get;
 static OBJH statCountersDump;
 static OBJH statPeerSelect;
 static OBJH statDigestBlob;
-static OBJH statAvg5min;
-static OBJH statAvg60min;
 static OBJH statUtilization;
 static OBJH statCountersHistograms;
 static OBJH statClientRequests;
+void GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours);
+void DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry);
+void GetInfo(Mgr::InfoActionData& stats);
+void DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry);
+void DumpMallocStatistics(StoreEntry* sentry);
+void GetCountersStats(Mgr::CountersActionData& stats);
+void DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry);
+void GetServiceTimesStats(Mgr::ServiceTimesActionData& stats);
+void DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry);
+void GetIoStats(Mgr::IoActionData& stats);
+void DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry);
 
 #if XMALLOC_STATISTICS
 static void info_get_mallstat(int, int, int, void *);
@@ -186,47 +199,71 @@ statUtilization(StoreEntry * e)
     statCountersDump(e);
 }
 
-static void
-stat_io_get(StoreEntry * sentry)
+void
+GetIoStats(Mgr::IoActionData& stats)
+{
+    int i;
+
+    stats.http_reads = IOStats.Http.reads;
+
+    for (i = 0; i < _iostats::histSize; i++) {
+        stats.http_read_hist[i] = IOStats.Http.read_hist[i];
+    }
+
+    stats.ftp_reads = IOStats.Ftp.reads;
+
+    for (i = 0; i < _iostats::histSize; i++) {
+        stats.ftp_read_hist[i] = IOStats.Ftp.read_hist[i];
+    }
+
+    stats.gopher_reads = IOStats.Gopher.reads;
+
+    for (i = 0; i < _iostats::histSize; i++) {
+        stats.gopher_read_hist[i] = IOStats.Gopher.read_hist[i];
+    }
+}
+
+void
+DumpIoStats(Mgr::IoActionData& stats, StoreEntry* sentry)
 {
     int i;
 
     storeAppendPrintf(sentry, "HTTP I/O\n");
-    storeAppendPrintf(sentry, "number of reads: %d\n", IOStats.Http.reads);
+    storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.http_reads);
     storeAppendPrintf(sentry, "Read Histogram:\n");
 
-    for (i = 0; i < 16; i++) {
-        storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%\n",
-                          i ? (1 << (i - 1)) + 1 : 1,
-                          1 << i,
-                          IOStats.Http.read_hist[i],
-                          Math::intPercent(IOStats.Http.read_hist[i], IOStats.Http.reads));
+    for (i = 0; i < _iostats::histSize; i++) {
+        storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
+            i ? (1 << (i - 1)) + 1 : 1,
+            1 << i,
+            stats.http_read_hist[i],
+            Math::doublePercent(stats.http_read_hist[i], stats.http_reads));
     }
 
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "FTP I/O\n");
-    storeAppendPrintf(sentry, "number of reads: %d\n", IOStats.Ftp.reads);
+    storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.ftp_reads);
     storeAppendPrintf(sentry, "Read Histogram:\n");
 
-    for (i = 0; i < 16; i++) {
-        storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%\n",
-                          i ? (1 << (i - 1)) + 1 : 1,
-                          1 << i,
-                          IOStats.Ftp.read_hist[i],
-                          Math::intPercent(IOStats.Ftp.read_hist[i], IOStats.Ftp.reads));
+    for (i = 0; i < _iostats::histSize; i++) {
+        storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
+            i ? (1 << (i - 1)) + 1 : 1,
+            1 << i,
+            stats.ftp_read_hist[i],
+            Math::doublePercent(stats.ftp_read_hist[i], stats.ftp_reads));
     }
 
     storeAppendPrintf(sentry, "\n");
     storeAppendPrintf(sentry, "Gopher I/O\n");
-    storeAppendPrintf(sentry, "number of reads: %d\n", IOStats.Gopher.reads);
+    storeAppendPrintf(sentry, "number of reads: %.0f\n", stats.gopher_reads);
     storeAppendPrintf(sentry, "Read Histogram:\n");
 
-    for (i = 0; i < 16; i++) {
-        storeAppendPrintf(sentry, "%5d-%5d: %9d %2d%%\n",
-                          i ? (1 << (i - 1)) + 1 : 1,
-                          1 << i,
-                          IOStats.Gopher.read_hist[i],
-                          Math::intPercent(IOStats.Gopher.read_hist[i], IOStats.Gopher.reads));
+    for (i = 0; i < _iostats::histSize; i++) {
+        storeAppendPrintf(sentry, "%5d-%5d: %9.0f %2.0f%%\n",
+            i ? (1 << (i - 1)) + 1 : 1,
+            1 << i,
+            stats.gopher_read_hist[i],
+            Math::doublePercent(stats.gopher_read_hist[i], stats.gopher_reads));
     }
 
     storeAppendPrintf(sentry, "\n");
@@ -338,6 +375,8 @@ statObjects(void *data)
     StoreEntry *e;
 
     if (state->theSearch->isDone()) {
+        if (UsingSmp())
+            storeAppendPrintf(state->sentry, "} by kid%d\n\n", KidIdentifier);
         state->sentry->complete();
         state->sentry->unlock();
         cbdataFree(state);
@@ -438,8 +477,8 @@ info_get_mallstat(int size, int number, int oldnum, void *data)
 
 #endif
 
-static void
-info_get(StoreEntry * sentry)
+void
+GetInfo(Mgr::InfoActionData& stats)
 {
 
     struct rusage rusage;
@@ -451,7 +490,6 @@ info_get(StoreEntry * sentry)
 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
     struct mallinfo mp;
-    long t;
 #endif
 
     runtime = tvSubDsec(squid_start, current_time);
@@ -459,6 +497,175 @@ info_get(StoreEntry * sentry)
     if (runtime == 0.0)
         runtime = 1.0;
 
+    stats.squid_start = squid_start;
+
+    stats.current_time = current_time;
+
+    stats.client_http_clients = statCounter.client_http.clients;
+
+    stats.client_http_requests = statCounter.client_http.requests;
+
+    stats.icp_pkts_recv = statCounter.icp.pkts_recv;
+
+    stats.icp_pkts_sent = statCounter.icp.pkts_sent;
+
+    stats.icp_replies_queued = statCounter.icp.replies_queued;
+
+#if USE_HTCP
+
+    stats.htcp_pkts_recv = statCounter.htcp.pkts_recv;
+
+    stats.htcp_pkts_sent = statCounter.htcp.pkts_sent;
+
+#endif
+
+    stats.request_failure_ratio = request_failure_ratio;
+
+    stats.avg_client_http_requests = statCounter.client_http.requests / (runtime / 60.0);
+
+    stats.avg_icp_messages = (statCounter.icp.pkts_sent + statCounter.icp.pkts_recv) / (runtime / 60.0);
+
+    stats.select_loops = statCounter.select_loops;
+    stats.avg_loop_time = 1000.0 * runtime / statCounter.select_loops;
+
+    stats.request_hit_ratio5 = statRequestHitRatio(5);
+    stats.request_hit_ratio60 = statRequestHitRatio(60);
+
+    stats.byte_hit_ratio5 = statByteHitRatio(5);
+    stats.byte_hit_ratio60 = statByteHitRatio(60);
+
+    stats.request_hit_mem_ratio5 = statRequestHitMemoryRatio(5);
+    stats.request_hit_mem_ratio60 = statRequestHitMemoryRatio(60);
+
+    stats.request_hit_disk_ratio5 = statRequestHitDiskRatio(5);
+    stats.request_hit_disk_ratio60 = statRequestHitDiskRatio(60);
+
+    stats.store_swap_size = store_swap_size;
+    stats.store_swap_max_size = Store::Root().maxSize();
+
+    stats.store_mem_size = mem_node::StoreMemSize();
+    stats.store_pages_max = store_pages_max;
+    stats.store_mem_used = mem_node::InUseCount();
+
+    stats.objects_size = n_disk_objects ? (double) store_swap_size / n_disk_objects : 0.0;
+
+    stats.unlink_requests = statCounter.unlink.requests;
+
+    stats.http_requests5 = statPctileSvc(0.5, 5, PCTILE_HTTP);
+    stats.http_requests60 = statPctileSvc(0.5, 60, PCTILE_HTTP);
+
+    stats.cache_misses5 = statPctileSvc(0.5, 5, PCTILE_MISS);
+    stats.cache_misses60 = statPctileSvc(0.5, 60, PCTILE_MISS);
+
+    stats.cache_hits5 = statPctileSvc(0.5, 5, PCTILE_HIT);
+    stats.cache_hits60 = statPctileSvc(0.5, 60, PCTILE_HIT);
+
+    stats.near_hits5 = statPctileSvc(0.5, 5, PCTILE_NH);
+    stats.near_hits60 = statPctileSvc(0.5, 60, PCTILE_NH);
+
+    stats.not_modified_replies5 = statPctileSvc(0.5, 5, PCTILE_NM);
+    stats.not_modified_replies60 = statPctileSvc(0.5, 60, PCTILE_NM);
+
+    stats.dns_lookups5 = statPctileSvc(0.5, 5, PCTILE_DNS);
+    stats.dns_lookups60 = statPctileSvc(0.5, 60, PCTILE_DNS);
+
+    stats.icp_queries5 = statPctileSvc(0.5, 5, PCTILE_ICP_QUERY);
+    stats.icp_queries60 = statPctileSvc(0.5, 60, PCTILE_ICP_QUERY);
+
+    squid_getrusage(&rusage);
+    cputime = rusage_cputime(&rusage);
+
+    stats.up_time = runtime;
+    stats.cpu_time = cputime;
+    stats.cpu_usage = Math::doublePercent(cputime, runtime);
+    stats.cpu_usage5 = statCPUUsage(5);
+    stats.cpu_usage60 = statCPUUsage(60);
+
+#if HAVE_SBRK
+
+    stats.proc_data_seg = ((char *) sbrk(0) - (char *) sbrk_start);
+
+#endif
+
+    stats.maxrss = rusage_maxrss(&rusage);
+
+    stats.page_faults = rusage_pagefaults(&rusage);
+
+#if HAVE_MSTATS && HAVE_GNUMALLOC_H
+
+    ms = mstats();
+
+    stats.ms_bytes_total = ms.bytes_total;
+
+    stats.ms_bytes_free = ms.bytes_free;
+
+#elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+
+    mp = mallinfo();
+
+    stats.mp_arena = mp.arena;
+
+    stats.mp_uordblks = mp.uordblks;
+    stats.mp_ordblks = mp.ordblks;
+
+    stats.mp_usmblks = mp.usmblks;
+    stats.mp_smblks = mp.smblks;
+
+    stats.mp_hblkhd = mp.hblkhd;
+    stats.mp_hblks = mp.hblks;
+
+    stats.mp_fsmblks = mp.fsmblks;
+
+    stats.mp_fordblks = mp.fordblks;
+
+#if HAVE_STRUCT_MALLINFO_MXFAST
+
+    stats.mp_mxfast = mp.mxfast;
+
+    stats.mp_nlblks = mp.nlblks;
+
+    stats.mp_grain = mp.grain;
+
+    stats.mp_uordbytes = mp.uordbytes;
+
+    stats.mp_allocated = mp.allocated;
+
+    stats.mp_treeoverhead = mp.treeoverhead;
+
+#endif /* HAVE_STRUCT_MALLINFO_MXFAST */
+#endif /* HAVE_MALLINFO */
+
+    stats.total_accounted = statMemoryAccounted();
+
+    {
+        MemPoolGlobalStats mp_stats;
+        memPoolGetGlobalStats(&mp_stats);
+#if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
+
+        stats.mem_pool_allocated = mp_stats.TheMeter->alloc.level;
+#endif
+
+        stats.gb_freed_count = mp_stats.TheMeter->gb_saved.count;
+        stats.gb_freed_count = mp_stats.TheMeter->gb_freed.count;
+    }
+
+    stats.max_fd = Squid_MaxFD;
+    stats.biggest_fd = Biggest_FD;
+    stats.number_fd = Number_FD;
+    stats.opening_fd = Opening_FD;
+    stats.num_fd_free = fdNFree();
+    stats.reserved_fd = RESERVED_FD;
+    stats.store_open_disk_fd = store_open_disk_fd;
+
+    stats.store_entries = StoreEntry::inUseCount();
+    stats.store_mem_entries = MemObject::inUseCount();
+    stats.hot_obj_count = hot_obj_count;
+    stats.n_disk_objects = n_disk_objects;
+}
+
+void
+DumpInfo(Mgr::InfoActionData& stats, StoreEntry* sentry)
+{
     storeAppendPrintf(sentry, "Squid Object Cache: Version %s\n",
                       version_string);
 
@@ -474,222 +681,215 @@ info_get(StoreEntry * sentry)
 #endif
 
     storeAppendPrintf(sentry, "Start Time:\t%s\n",
-                      mkrfc1123(squid_start.tv_sec));
+                      mkrfc1123(stats.squid_start.tv_sec));
 
     storeAppendPrintf(sentry, "Current Time:\t%s\n",
-                      mkrfc1123(current_time.tv_sec));
+                      mkrfc1123(stats.current_time.tv_sec));
 
     storeAppendPrintf(sentry, "Connection information for %s:\n",APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tNumber of clients accessing cache:\t%u\n",
-                      statCounter.client_http.clients);
+    storeAppendPrintf(sentry, "\tNumber of clients accessing cache:\t%.0f\n",
+                      stats.client_http_clients);
 
-    storeAppendPrintf(sentry, "\tNumber of HTTP requests received:\t%u\n",
-                      statCounter.client_http.requests);
+    storeAppendPrintf(sentry, "\tNumber of HTTP requests received:\t%.0f\n",
+                      stats.client_http_requests);
 
-    storeAppendPrintf(sentry, "\tNumber of ICP messages received:\t%u\n",
-                      statCounter.icp.pkts_recv);
+    storeAppendPrintf(sentry, "\tNumber of ICP messages received:\t%.0f\n",
+                      stats.icp_pkts_recv);
 
-    storeAppendPrintf(sentry, "\tNumber of ICP messages sent:\t%u\n",
-                      statCounter.icp.pkts_sent);
+    storeAppendPrintf(sentry, "\tNumber of ICP messages sent:\t%.0f\n",
+                      stats.icp_pkts_sent);
 
-    storeAppendPrintf(sentry, "\tNumber of queued ICP replies:\t%u\n",
-                      statCounter.icp.replies_queued);
+    storeAppendPrintf(sentry, "\tNumber of queued ICP replies:\t%.0f\n",
+                      stats.icp_replies_queued);
 
 #if USE_HTCP
 
-    storeAppendPrintf(sentry, "\tNumber of HTCP messages received:\t%u\n",
-                      statCounter.htcp.pkts_recv);
+    storeAppendPrintf(sentry, "\tNumber of HTCP messages received:\t%.0f\n",
+                      stats.htcp_pkts_recv);
 
-    storeAppendPrintf(sentry, "\tNumber of HTCP messages sent:\t%u\n",
-                      statCounter.htcp.pkts_sent);
+    storeAppendPrintf(sentry, "\tNumber of HTCP messages sent:\t%.0f\n",
+                      stats.htcp_pkts_sent);
 
 #endif
 
+    double fct = stats.count > 1 ? stats.count : 1.0;
     storeAppendPrintf(sentry, "\tRequest failure ratio:\t%5.2f\n",
-                      request_failure_ratio);
+                      stats.request_failure_ratio / fct);
 
     storeAppendPrintf(sentry, "\tAverage HTTP requests per minute since start:\t%.1f\n",
-                      statCounter.client_http.requests / (runtime / 60.0));
+                      stats.avg_client_http_requests / fct);
 
     storeAppendPrintf(sentry, "\tAverage ICP messages per minute since start:\t%.1f\n",
-                      (statCounter.icp.pkts_sent + statCounter.icp.pkts_recv) / (runtime / 60.0));
+                      stats.avg_icp_messages / fct);
 
-    storeAppendPrintf(sentry, "\tSelect loop called: %ld times, %0.3f ms avg\n",
-                      statCounter.select_loops, 1000.0 * runtime / statCounter.select_loops);
+    storeAppendPrintf(sentry, "\tSelect loop called: %.0f times, %0.3f ms avg\n",
+                      stats.select_loops, stats.avg_loop_time / fct);
 
     storeAppendPrintf(sentry, "Cache information for %s:\n",APP_SHORTNAME);
 
     storeAppendPrintf(sentry, "\tHits as %% of all requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statRequestHitRatio(5),
-                      statRequestHitRatio(60));
+                      stats.request_hit_ratio5 / fct,
+                      stats.request_hit_ratio60 / fct);
 
     storeAppendPrintf(sentry, "\tHits as %% of bytes sent:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statByteHitRatio(5),
-                      statByteHitRatio(60));
+                      stats.byte_hit_ratio5 / fct,
+                      stats.byte_hit_ratio60 / fct);
 
     storeAppendPrintf(sentry, "\tMemory hits as %% of hit requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statRequestHitMemoryRatio(5),
-                      statRequestHitMemoryRatio(60));
+                      stats.request_hit_mem_ratio5 / fct,
+                      stats.request_hit_mem_ratio60 / fct);
 
     storeAppendPrintf(sentry, "\tDisk hits as %% of hit requests:\t5min: %3.1f%%, 60min: %3.1f%%\n",
-                      statRequestHitDiskRatio(5),
-                      statRequestHitDiskRatio(60));
+                      stats.request_hit_disk_ratio5 / fct,
+                      stats.request_hit_disk_ratio60 / fct);
 
-    storeAppendPrintf(sentry, "\tStorage Swap size:\t%lu KB\n",
-                      store_swap_size);
+    storeAppendPrintf(sentry, "\tStorage Swap size:\t%.0f KB\n",
+                      stats.store_swap_size / 1024);
 
     storeAppendPrintf(sentry, "\tStorage Swap capacity:\t%4.1f%% used, %4.1f%% free\n",
-                      Math::doublePercent(store_swap_size, Store::Root().maxSize()),
-                      Math::doublePercent((Store::Root().maxSize() - store_swap_size), Store::Root().maxSize()));
-
+                      Math::doublePercent(stats.store_swap_size, stats.store_swap_max_size),
+                      Math::doublePercent(stats.store_swap_max_size - stats.store_swap_size, stats.store_swap_max_size));
 
-    storeAppendPrintf(sentry, "\tStorage Mem size:\t%lu KB\n",
-                      (unsigned long)(mem_node::StoreMemSize() >> 10));
+    storeAppendPrintf(sentry, "\tStorage Mem size:\t%.0f KB\n",
+                      stats.store_mem_size / 1024);
 
-    double mFree = 0.0;
-    if (mem_node::InUseCount() <= store_pages_max)
-        mFree = Math::doublePercent((store_pages_max - mem_node::InUseCount()), store_pages_max);
+    const double mFree = max(0.0, stats.store_pages_max-stats.store_mem_used);
     storeAppendPrintf(sentry, "\tStorage Mem capacity:\t%4.1f%% used, %4.1f%% free\n",
-                      Math::doublePercent(mem_node::InUseCount(), store_pages_max),
-                      mFree);
+                      Math::doublePercent(stats.store_mem_used, stats.store_pages_max),
+                      Math::doublePercent(mFree, stats.store_pages_max));
 
     storeAppendPrintf(sentry, "\tMean Object Size:\t%0.2f KB\n",
-                      n_disk_objects ? (double) store_swap_size / n_disk_objects : 0.0);
+                      stats.objects_size / fct);
 
-    storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%ld\n",
-                      (long)statCounter.unlink.requests);
+    storeAppendPrintf(sentry, "\tRequests given to unlinkd:\t%.0f\n",
+                      stats.unlink_requests);
 
     storeAppendPrintf(sentry, "Median Service Times (seconds)  5 min    60 min:\n");
 
+    fct = stats.count > 1 ? stats.count * 1000.0 : 1000.0;
     storeAppendPrintf(sentry, "\tHTTP Requests (All):  %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_HTTP) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_HTTP) / 1000.0);
+                      stats.http_requests5 / fct,
+                      stats.http_requests60 / fct);
 
     storeAppendPrintf(sentry, "\tCache Misses:         %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_MISS) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_MISS) / 1000.0);
+                      stats.cache_misses5 / fct,
+                      stats.cache_misses60 / fct);
 
     storeAppendPrintf(sentry, "\tCache Hits:           %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_HIT) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_HIT) / 1000.0);
+                      stats.cache_hits5 / fct,
+                      stats.cache_hits60 / fct);
 
     storeAppendPrintf(sentry, "\tNear Hits:            %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_NH) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_NH) / 1000.0);
+                      stats.near_hits5 / fct,
+                      stats.near_hits60 / fct);
 
     storeAppendPrintf(sentry, "\tNot-Modified Replies: %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_NM) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_NM) / 1000.0);
+                      stats.not_modified_replies5 / fct,
+                      stats.not_modified_replies60 / fct);
 
     storeAppendPrintf(sentry, "\tDNS Lookups:          %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_DNS) / 1000.0,
-                      statPctileSvc(0.5, 60, PCTILE_DNS) / 1000.0);
+                      stats.dns_lookups5 / fct,
+                      stats.dns_lookups60 / fct);
 
+    fct = stats.count > 1 ? stats.count * 1000000.0 : 1000000.0;
     storeAppendPrintf(sentry, "\tICP Queries:          %8.5f %8.5f\n",
-                      statPctileSvc(0.5, 5, PCTILE_ICP_QUERY) / 1000000.0,
-                      statPctileSvc(0.5, 60, PCTILE_ICP_QUERY) / 1000000.0);
-
-    squid_getrusage(&rusage);
-
-    cputime = rusage_cputime(&rusage);
+                      stats.icp_queries5 / fct,
+                      stats.icp_queries60 / fct);
 
     storeAppendPrintf(sentry, "Resource usage for %s:\n", APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tUP Time:\t%.3f seconds\n", runtime);
+    storeAppendPrintf(sentry, "\tUP Time:\t%.3f seconds\n", stats.up_time);
 
-    storeAppendPrintf(sentry, "\tCPU Time:\t%.3f seconds\n", cputime);
+    storeAppendPrintf(sentry, "\tCPU Time:\t%.3f seconds\n", stats.cpu_time);
 
     storeAppendPrintf(sentry, "\tCPU Usage:\t%.2f%%\n",
-                      Math::doublePercent(cputime, runtime));
+                      stats.cpu_usage);
 
     storeAppendPrintf(sentry, "\tCPU Usage, 5 minute avg:\t%.2f%%\n",
-                      statCPUUsage(5));
+                      stats.cpu_usage5);
 
     storeAppendPrintf(sentry, "\tCPU Usage, 60 minute avg:\t%.2f%%\n",
-                      statCPUUsage(60));
+                      stats.cpu_usage60);
 
 #if HAVE_SBRK
 
-    storeAppendPrintf(sentry, "\tProcess Data Segment Size via sbrk(): %lu KB\n",
-                      (unsigned long) (((char *) sbrk(0) - (char *) sbrk_start) >> 10));
+    storeAppendPrintf(sentry, "\tProcess Data Segment Size via sbrk(): %.0f KB\n",
+                      stats.proc_data_seg / 1024);
 
 #endif
 
-    storeAppendPrintf(sentry, "\tMaximum Resident Size: %ld KB\n",
-                      (long)rusage_maxrss(&rusage));
+    storeAppendPrintf(sentry, "\tMaximum Resident Size: %.0f KB\n",
+                      stats.maxrss);
 
-    storeAppendPrintf(sentry, "\tPage faults with physical i/o: %ld\n",
-                      (long)rusage_pagefaults(&rusage));
+    storeAppendPrintf(sentry, "\tPage faults with physical i/o: %.0f\n",
+                      stats.page_faults);
 
 #if HAVE_MSTATS && HAVE_GNUMALLOC_H
 
-    ms = mstats();
-
     storeAppendPrintf(sentry, "Memory usage for %s via mstats():\n",APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tTotal space in arena:  %6ld KB\n",
-                      (long)(ms.bytes_total >> 10));
+    storeAppendPrintf(sentry, "\tTotal space in arena:  %6.0f KB\n",
+                      stats.ms_bytes_total / 1024);
 
-    storeAppendPrintf(sentry, "\tTotal free:            %6ld KB %d%%\n",
-                      (long)(ms.bytes_free >> 10), Math::intPercent(ms.bytes_free, ms.bytes_total));
+    storeAppendPrintf(sentry, "\tTotal free:            %6.0f KB %.0f%%\n",
+                      stats.ms_bytes_free / 1024,
+                      Math::doublePercent(stats.ms_bytes_free, stats.ms_bytes_total));
 
 #elif HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
-    mp = mallinfo();
-
     storeAppendPrintf(sentry, "Memory usage for %s via mallinfo():\n",APP_SHORTNAME);
 
-    storeAppendPrintf(sentry, "\tTotal space in arena:  %6ld KB\n",
-                      (long)(mp.arena >> 10));
+    storeAppendPrintf(sentry, "\tTotal space in arena:  %6.0f KB\n",
+                      stats.mp_arena / 1024);
 
-    storeAppendPrintf(sentry, "\tOrdinary blocks:       %6ld KB %6ld blks\n",
-                      (long)(mp.uordblks >> 10), (long)mp.ordblks);
+    storeAppendPrintf(sentry, "\tOrdinary blocks:       %6.0f KB %6.0f blks\n",
+                      stats.mp_uordblks / 1024, stats.mp_ordblks);
 
-    storeAppendPrintf(sentry, "\tSmall blocks:          %6ld KB %6ld blks\n",
-                      (long)(mp.usmblks >> 10), (long)mp.smblks);
+    storeAppendPrintf(sentry, "\tSmall blocks:          %6.0f KB %6.0f blks\n",
+                      stats.mp_usmblks / 1024, stats.mp_smblks);
 
-    storeAppendPrintf(sentry, "\tHolding blocks:        %6ld KB %6ld blks\n",
-                      (long)(mp.hblkhd >> 10), (long)mp.hblks);
+    storeAppendPrintf(sentry, "\tHolding blocks:        %6.0f KB %6.0f blks\n",
+                      stats.mp_hblkhd / 1024, stats.mp_hblks);
 
-    storeAppendPrintf(sentry, "\tFree Small blocks:     %6ld KB\n",
-                      (long)(mp.fsmblks >> 10));
+    storeAppendPrintf(sentry, "\tFree Small blocks:     %6.0f KB\n",
+                      stats.mp_fsmblks / 1024);
 
-    storeAppendPrintf(sentry, "\tFree Ordinary blocks:  %6ld KB\n",
-                      (long)(mp.fordblks >> 10));
+    storeAppendPrintf(sentry, "\tFree Ordinary blocks:  %6.0f KB\n",
+                      stats.mp_fordblks / 1024);
 
-    t = mp.uordblks + mp.usmblks + mp.hblkhd;
+    double t = stats.mp_fsmblks + stats.mp_fordblks;
 
-    storeAppendPrintf(sentry, "\tTotal in use:          %6ld KB %d%%\n",
-                      (long)(t >> 10), Math::intPercent(t, mp.arena + mp.hblkhd));
+    storeAppendPrintf(sentry, "\tTotal in use:          %6.0f KB %.0f%%\n",
+                      t / 1024, Math::doublePercent(t, stats.mp_arena + stats.mp_hblkhd));
 
-    t = mp.fsmblks + mp.fordblks;
+    t = stats.mp_fsmblks + stats.mp_fordblks;
 
-    storeAppendPrintf(sentry, "\tTotal free:            %6ld KB %d%%\n",
-                      (long)(t >> 10), Math::intPercent(t, mp.arena + mp.hblkhd));
+    storeAppendPrintf(sentry, "\tTotal free:            %6.0f KB %.0f%%\n",
+                      t / 1024, Math::doublePercent(t, stats.mp_arena + stats.mp_hblkhd));
 
-    t = mp.arena + mp.hblkhd;
+    t = stats.mp_arena + stats.mp_hblkhd;
 
-    storeAppendPrintf(sentry, "\tTotal size:            %6ld KB\n",
-                      (long)(t >> 10));
+    storeAppendPrintf(sentry, "\tTotal size:            %6.0f KB\n",
+                      t / 1024);
 
 #if HAVE_STRUCT_MALLINFO_MXFAST
 
-    storeAppendPrintf(sentry, "\tmax size of small blocks:\t%d\n", mp.mxfast);
+    storeAppendPrintf(sentry, "\tmax size of small blocks:\t%.0f\n", stats.mp_mxfast);
 
-    storeAppendPrintf(sentry, "\tnumber of small blocks in a holding block:\t%ld\n",
-                      (long)mp.nlblks);
+    storeAppendPrintf(sentry, "\tnumber of small blocks in a holding block:\t%.0f\n",
+                      stats.mp_nlblks);
 
-    storeAppendPrintf(sentry, "\tsmall block rounding factor:\t%ld\n", (long)mp.grain);
+    storeAppendPrintf(sentry, "\tsmall block rounding factor:\t%.0f\n", stats.mp_grain);
 
-    storeAppendPrintf(sentry, "\tspace (including overhead) allocated in ord. blks:\t%ld\n",
-                      (long)mp.uordbytes);
+    storeAppendPrintf(sentry, "\tspace (including overhead) allocated in ord. blks:\t%.0f\n"
+                      ,stats.mp_uordbytes);
 
-    storeAppendPrintf(sentry, "\tnumber of ordinary blocks allocated:\t%ld\n",
-                      (long)mp.allocated);
+    storeAppendPrintf(sentry, "\tnumber of ordinary blocks allocated:\t%.0f\n",
+                      stats.mp_allocated);
 
-    storeAppendPrintf(sentry, "\tbytes used in maintaining the free tree:\t%ld\n",
-                      (long)mp.treeoverhead);
+    storeAppendPrintf(sentry, "\tbytes used in maintaining the free tree:\t%.0f\n",
+                      stats.mp_treeoverhead);
 
 #endif /* HAVE_STRUCT_MALLINFO_MXFAST */
 #endif /* HAVE_MALLINFO */
@@ -698,13 +898,13 @@ info_get(StoreEntry * sentry)
 
 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
-    storeAppendPrintf(sentry, "\tTotal accounted:       %6ld KB %3d%%\n",
-                      (long)(statMemoryAccounted() >> 10), Math::intPercent(statMemoryAccounted(), t));
+    storeAppendPrintf(sentry, "\tTotal accounted:       %6.0f KB %3.0f%%\n",
+                      stats.total_accounted / 1024, Math::doublePercent(stats.total_accounted, t));
 
 #else
 
-    storeAppendPrintf(sentry, "\tTotal accounted:       %6ld KB\n",
-                      (long)(statMemoryAccounted() >> 10));
+    storeAppendPrintf(sentry, "\tTotal accounted:       %6.0f KB\n",
+                      stats.total_accounted / 1024);
 
 #endif
     {
@@ -712,49 +912,52 @@ info_get(StoreEntry * sentry)
         memPoolGetGlobalStats(&mp_stats);
 #if !(HAVE_MSTATS && HAVE_GNUMALLOC_H) && HAVE_MALLINFO && HAVE_STRUCT_MALLINFO
 
-        storeAppendPrintf(sentry, "\tmemPool accounted:     %6ld KB %3d%%\n",
-                          (long)(mp_stats.TheMeter->alloc.level >> 10),
-                          Math::intPercent(mp_stats.TheMeter->alloc.level, t));
+        storeAppendPrintf(sentry, "\tmemPool accounted:     %6.0f KB %3.0f%%\n",
+                          stats.mem_pool_allocated / 1024,
+                          Math::doublePercent(stats.mem_pool_allocated, t));
 
-        int iFree = 0;
-        if (t >= mp_stats.TheMeter->alloc.level)
-            iFree = Math::intPercent((t - mp_stats.TheMeter->alloc.level), t);
-        storeAppendPrintf(sentry, "\tmemPool unaccounted:   %6ld KB %3d%%\n",
-                          (long)((t - mp_stats.TheMeter->alloc.level) >> 10), iFree);
+        const double iFree = max(0.0, t - stats.mem_pool_allocated);
+        storeAppendPrintf(sentry, "\tmemPool unaccounted:   %6.0f KB %3.0f%%\n",
+                          (t - stats.mem_pool_allocated) / 1024,
+                          Math::doublePercent(iFree, t));
 #endif
 
         storeAppendPrintf(sentry, "\tmemPoolAlloc calls: %9.0f\n",
-                          mp_stats.TheMeter->gb_saved.count);
+                          stats.gb_saved_count);
         storeAppendPrintf(sentry, "\tmemPoolFree calls:  %9.0f\n",
-                          mp_stats.TheMeter->gb_freed.count);
+                          stats.gb_freed_count);
     }
 
     storeAppendPrintf(sentry, "File descriptor usage for %s:\n", APP_SHORTNAME);
-    storeAppendPrintf(sentry, "\tMaximum number of file descriptors:   %4d\n",
-                      Squid_MaxFD);
-    storeAppendPrintf(sentry, "\tLargest file desc currently in use:   %4d\n",
-                      Biggest_FD);
-    storeAppendPrintf(sentry, "\tNumber of file desc currently in use: %4d\n",
-                      Number_FD);
-    storeAppendPrintf(sentry, "\tFiles queued for open:                %4d\n",
-                      Opening_FD);
-    storeAppendPrintf(sentry, "\tAvailable number of file descriptors: %4d\n",
-                      fdNFree());
-    storeAppendPrintf(sentry, "\tReserved number of file descriptors:  %4d\n",
-                      RESERVED_FD);
-    storeAppendPrintf(sentry, "\tStore Disk files open:                %4d\n",
-                      store_open_disk_fd);
+    storeAppendPrintf(sentry, "\tMaximum number of file descriptors:   %4.0f\n",
+                      stats.max_fd);
+    storeAppendPrintf(sentry, "\tLargest file desc currently in use:   %4.0f\n",
+                      stats.biggest_fd);
+    storeAppendPrintf(sentry, "\tNumber of file desc currently in use: %4.0f\n",
+                      stats.number_fd);
+    storeAppendPrintf(sentry, "\tFiles queued for open:                %4.0f\n",
+                      stats.opening_fd);
+    storeAppendPrintf(sentry, "\tAvailable number of file descriptors: %4.0f\n",
+                      stats.num_fd_free);
+    storeAppendPrintf(sentry, "\tReserved number of file descriptors:  %4.0f\n",
+                      stats.reserved_fd);
+    storeAppendPrintf(sentry, "\tStore Disk files open:                %4.0f\n",
+                      stats.store_open_disk_fd);
 
     storeAppendPrintf(sentry, "Internal Data Structures:\n");
-    storeAppendPrintf(sentry, "\t%6lu StoreEntries\n",
-                      (unsigned long)StoreEntry::inUseCount());
-    storeAppendPrintf(sentry, "\t%6lu StoreEntries with MemObjects\n",
-                      (unsigned long)MemObject::inUseCount());
-    storeAppendPrintf(sentry, "\t%6ld Hot Object Cache Items\n",
-                      (long)hot_obj_count);
-    storeAppendPrintf(sentry, "\t%6ld on-disk objects\n",
-                      (long)n_disk_objects);
+    storeAppendPrintf(sentry, "\t%6.0f StoreEntries\n",
+                      stats.store_entries);
+    storeAppendPrintf(sentry, "\t%6.0f StoreEntries with MemObjects\n",
+                      stats.store_mem_entries);
+    storeAppendPrintf(sentry, "\t%6.0f Hot Object Cache Items\n",
+                      stats.hot_obj_count);
+    storeAppendPrintf(sentry, "\t%6.0f on-disk objects\n",
+                      stats.n_disk_objects);
+}
 
+void
+DumpMallocStatistics(StoreEntry* sentry)
+{
 #if XMALLOC_STATISTICS
 
     xm_deltat = current_dtime - xm_time;
@@ -765,64 +968,100 @@ info_get(StoreEntry * sentry)
 #endif
 }
 
-static void
-service_times(StoreEntry * sentry)
+void
+GetServiceTimesStats(Mgr::ServiceTimesActionData& stats)
+{
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
+        double p = (i + 1) * 5 / 100.0;
+        stats.http_requests5[i] = statPctileSvc(p, 5, PCTILE_HTTP);
+        stats.http_requests60[i] = statPctileSvc(p, 60, PCTILE_HTTP);
+
+        stats.cache_misses5[i] = statPctileSvc(p, 5, PCTILE_MISS);
+        stats.cache_misses60[i] = statPctileSvc(p, 60, PCTILE_MISS);
+
+        stats.cache_hits5[i] = statPctileSvc(p, 5, PCTILE_HIT);
+        stats.cache_hits60[i] = statPctileSvc(p, 60, PCTILE_HIT);
+
+        stats.near_hits5[i] = statPctileSvc(p, 5, PCTILE_NH);
+        stats.near_hits60[i] = statPctileSvc(p, 60, PCTILE_NH);
+
+        stats.not_modified_replies5[i] = statPctileSvc(p, 5, PCTILE_NM);
+        stats.not_modified_replies60[i] = statPctileSvc(p, 60, PCTILE_NM);
+
+        stats.dns_lookups5[i] = statPctileSvc(p, 5, PCTILE_DNS);
+        stats.dns_lookups60[i] = statPctileSvc(p, 60, PCTILE_DNS);
+
+        stats.icp_queries5[i] = statPctileSvc(p, 5, PCTILE_ICP_QUERY);
+        stats.icp_queries60[i] = statPctileSvc(p, 60, PCTILE_ICP_QUERY);
+    }
+}
+
+void
+DumpServiceTimesStats(Mgr::ServiceTimesActionData& stats, StoreEntry* sentry)
 {
-    int p;
     storeAppendPrintf(sentry, "Service Time Percentiles            5 min    60 min:\n");
-    for (p = 5; p < 100; p += 5) {
+    double fct = stats.count > 1 ? stats.count * 1000.0 : 1000.0;
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tHTTP Requests (All):  %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_HTTP) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_HTTP) / 1000.0);
+                          (i + 1) * 5,
+                          stats.http_requests5[i] / fct,
+                          stats.http_requests60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tCache Misses:         %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_MISS) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_MISS) / 1000.0);
+                          (i + 1) * 5,
+                          stats.cache_misses5[i] / fct,
+                          stats.cache_misses60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tCache Hits:           %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_HIT) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_HIT) / 1000.0);
+                          (i + 1) * 5,
+                          stats.cache_hits5[i] / fct,
+                          stats.cache_hits60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tNear Hits:            %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_NH) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_NH) / 1000.0);
+                          (i + 1) * 5,
+                          stats.near_hits5[i] / fct,
+                          stats.near_hits60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tNot-Modified Replies: %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_NM) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_NM) / 1000.0);
+                          (i + 1) * 5,
+                          stats.not_modified_replies5[i] / fct,
+                          stats.not_modified_replies60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tDNS Lookups:          %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_DNS) / 1000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_DNS) / 1000.0);
+                          (i + 1) * 5,
+                          stats.dns_lookups5[i] / fct,
+                          stats.dns_lookups60[i] / fct);
     }
-    for (p = 5; p < 100; p += 5) {
+    fct = stats.count > 1 ? stats.count * 1000000.0 : 1000000.0;
+    for (int i = 0; i < Mgr::ServiceTimesActionData::seriesSize; ++i) {
         storeAppendPrintf(sentry, "\tICP Queries:          %2d%%  %8.5f %8.5f\n",
-                          p,
-                          statPctileSvc((double) p / 100.0, 5, PCTILE_ICP_QUERY) / 1000000.0,
-                          statPctileSvc((double) p / 100.0, 60, PCTILE_ICP_QUERY) / 1000000.0);
+                          (i + 1) * 5,
+                          stats.icp_queries5[i] / fct,
+                          stats.icp_queries60[i] / fct);
     }
 }
 
-#define XAVG(X) (dt ? (double) (f->X - l->X) / dt : 0.0)
 static void
 statAvgDump(StoreEntry * sentry, int minutes, int hours)
+{
+    Mgr::IntervalActionData stats;
+    GetAvgStat(stats, minutes, hours);
+    DumpAvgStat(stats, sentry);
+}
+
+#define XAVG(X) (dt ? (double) (f->X - l->X) / dt : 0.0)
+void
+GetAvgStat(Mgr::IntervalActionData& stats, int minutes, int hours)
 {
     StatCounters *f;
     StatCounters *l;
     double dt;
     double ct;
-    double x;
     assert(N_COUNT_HIST > 1);
     assert(minutes > 0 || hours > 0);
     f = &CountHist[0];
@@ -850,211 +1089,295 @@ statAvgDump(StoreEntry * sentry, int minutes, int hours)
     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.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.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.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);
+    stats.syscalls_selects = XAVG(syscalls.selects);
+
+    stats.cpu_time = ct;
+    stats.wall_time = dt;
+}
+
+void
+DumpAvgStat(Mgr::IntervalActionData& stats, StoreEntry* sentry)
+{
     storeAppendPrintf(sentry, "sample_start_time = %d.%d (%s)\n",
-                      (int) l->timestamp.tv_sec,
-                      (int) l->timestamp.tv_usec,
-                      mkrfc1123(l->timestamp.tv_sec));
+                      (int)stats.sample_start_time.tv_sec,
+                      (int)stats.sample_start_time.tv_usec,
+                      mkrfc1123(stats.sample_start_time.tv_sec));
     storeAppendPrintf(sentry, "sample_end_time = %d.%d (%s)\n",
-                      (int) f->timestamp.tv_sec,
-                      (int) f->timestamp.tv_usec,
-                      mkrfc1123(f->timestamp.tv_sec));
+                      (int)stats.sample_end_time.tv_sec,
+                      (int)stats.sample_end_time.tv_usec,
+                      mkrfc1123(stats.sample_end_time.tv_sec));
 
     storeAppendPrintf(sentry, "client_http.requests = %f/sec\n",
-                      XAVG(client_http.requests));
+                      stats.client_http_requests);
     storeAppendPrintf(sentry, "client_http.hits = %f/sec\n",
-                      XAVG(client_http.hits));
+                      stats.client_http_hits);
     storeAppendPrintf(sentry, "client_http.errors = %f/sec\n",
-                      XAVG(client_http.errors));
+                      stats.client_http_errors);
     storeAppendPrintf(sentry, "client_http.kbytes_in = %f/sec\n",
-                      XAVG(client_http.kbytes_in.kb));
+                      stats.client_http_kbytes_in);
     storeAppendPrintf(sentry, "client_http.kbytes_out = %f/sec\n",
-                      XAVG(client_http.kbytes_out.kb));
+                      stats.client_http_kbytes_out);
 
-    x = statHistDeltaMedian(&l->client_http.all_svc_time,
-                            &f->client_http.all_svc_time);
+    double fct = stats.count > 1 ? stats.count : 1.0;
     storeAppendPrintf(sentry, "client_http.all_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.miss_svc_time,
-                            &f->client_http.miss_svc_time);
+                      stats.client_http_all_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.miss_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.nm_svc_time,
-                            &f->client_http.nm_svc_time);
+                      stats.client_http_miss_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.nm_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.nh_svc_time,
-                            &f->client_http.nh_svc_time);
+                      stats.client_http_nm_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.nh_median_svc_time = %f seconds\n",
-                      x / 1000.0);
-    x = statHistDeltaMedian(&l->client_http.hit_svc_time,
-                            &f->client_http.hit_svc_time);
+                      stats.client_http_nh_median_svc_time / fct);
     storeAppendPrintf(sentry, "client_http.hit_median_svc_time = %f seconds\n",
-                      x / 1000.0);
+                      stats.client_http_hit_median_svc_time / fct);
 
     storeAppendPrintf(sentry, "server.all.requests = %f/sec\n",
-                      XAVG(server.all.requests));
+                      stats.server_all_requests);
     storeAppendPrintf(sentry, "server.all.errors = %f/sec\n",
-                      XAVG(server.all.errors));
+                      stats.server_all_errors);
     storeAppendPrintf(sentry, "server.all.kbytes_in = %f/sec\n",
-                      XAVG(server.all.kbytes_in.kb));
+                      stats.server_all_kbytes_in);
     storeAppendPrintf(sentry, "server.all.kbytes_out = %f/sec\n",
-                      XAVG(server.all.kbytes_out.kb));
+                      stats.server_all_kbytes_out);
 
     storeAppendPrintf(sentry, "server.http.requests = %f/sec\n",
-                      XAVG(server.http.requests));
+                      stats.server_http_requests);
     storeAppendPrintf(sentry, "server.http.errors = %f/sec\n",
-                      XAVG(server.http.errors));
+                      stats.server_http_errors);
     storeAppendPrintf(sentry, "server.http.kbytes_in = %f/sec\n",
-                      XAVG(server.http.kbytes_in.kb));
+                      stats.server_http_kbytes_in);
     storeAppendPrintf(sentry, "server.http.kbytes_out = %f/sec\n",
-                      XAVG(server.http.kbytes_out.kb));
+                      stats.server_http_kbytes_out);
 
     storeAppendPrintf(sentry, "server.ftp.requests = %f/sec\n",
-                      XAVG(server.ftp.requests));
+                      stats.server_ftp_requests);
     storeAppendPrintf(sentry, "server.ftp.errors = %f/sec\n",
-                      XAVG(server.ftp.errors));
+                      stats.server_ftp_errors);
     storeAppendPrintf(sentry, "server.ftp.kbytes_in = %f/sec\n",
-                      XAVG(server.ftp.kbytes_in.kb));
+                      stats.server_ftp_kbytes_in);
     storeAppendPrintf(sentry, "server.ftp.kbytes_out = %f/sec\n",
-                      XAVG(server.ftp.kbytes_out.kb));
+                      stats.server_ftp_kbytes_out);
 
     storeAppendPrintf(sentry, "server.other.requests = %f/sec\n",
-                      XAVG(server.other.requests));
+                      stats.server_other_requests);
     storeAppendPrintf(sentry, "server.other.errors = %f/sec\n",
-                      XAVG(server.other.errors));
+                      stats.server_other_errors);
     storeAppendPrintf(sentry, "server.other.kbytes_in = %f/sec\n",
-                      XAVG(server.other.kbytes_in.kb));
+                      stats.server_other_kbytes_in);
     storeAppendPrintf(sentry, "server.other.kbytes_out = %f/sec\n",
-                      XAVG(server.other.kbytes_out.kb));
+                      stats.server_other_kbytes_out);
 
     storeAppendPrintf(sentry, "icp.pkts_sent = %f/sec\n",
-                      XAVG(icp.pkts_sent));
+                      stats.icp_pkts_sent);
     storeAppendPrintf(sentry, "icp.pkts_recv = %f/sec\n",
-                      XAVG(icp.pkts_recv));
+                      stats.icp_pkts_recv);
     storeAppendPrintf(sentry, "icp.queries_sent = %f/sec\n",
-                      XAVG(icp.queries_sent));
+                      stats.icp_queries_sent);
     storeAppendPrintf(sentry, "icp.replies_sent = %f/sec\n",
-                      XAVG(icp.replies_sent));
+                      stats.icp_replies_sent);
     storeAppendPrintf(sentry, "icp.queries_recv = %f/sec\n",
-                      XAVG(icp.queries_recv));
+                      stats.icp_queries_recv);
     storeAppendPrintf(sentry, "icp.replies_recv = %f/sec\n",
-                      XAVG(icp.replies_recv));
+                      stats.icp_replies_recv);
     storeAppendPrintf(sentry, "icp.replies_queued = %f/sec\n",
-                      XAVG(icp.replies_queued));
+                      stats.icp_replies_queued);
     storeAppendPrintf(sentry, "icp.query_timeouts = %f/sec\n",
-                      XAVG(icp.query_timeouts));
+                      stats.icp_query_timeouts);
     storeAppendPrintf(sentry, "icp.kbytes_sent = %f/sec\n",
-                      XAVG(icp.kbytes_sent.kb));
+                      stats.icp_kbytes_sent);
     storeAppendPrintf(sentry, "icp.kbytes_recv = %f/sec\n",
-                      XAVG(icp.kbytes_recv.kb));
+                      stats.icp_kbytes_recv);
     storeAppendPrintf(sentry, "icp.q_kbytes_sent = %f/sec\n",
-                      XAVG(icp.q_kbytes_sent.kb));
+                      stats.icp_q_kbytes_sent);
     storeAppendPrintf(sentry, "icp.r_kbytes_sent = %f/sec\n",
-                      XAVG(icp.r_kbytes_sent.kb));
+                      stats.icp_r_kbytes_sent);
     storeAppendPrintf(sentry, "icp.q_kbytes_recv = %f/sec\n",
-                      XAVG(icp.q_kbytes_recv.kb));
+                      stats.icp_q_kbytes_recv);
     storeAppendPrintf(sentry, "icp.r_kbytes_recv = %f/sec\n",
-                      XAVG(icp.r_kbytes_recv.kb));
-    x = statHistDeltaMedian(&l->icp.query_svc_time, &f->icp.query_svc_time);
+                      stats.icp_r_kbytes_recv);
     storeAppendPrintf(sentry, "icp.query_median_svc_time = %f seconds\n",
-                      x / 1000000.0);
-    x = statHistDeltaMedian(&l->icp.reply_svc_time, &f->icp.reply_svc_time);
+                      stats.icp_query_median_svc_time / fct);
     storeAppendPrintf(sentry, "icp.reply_median_svc_time = %f seconds\n",
-                      x / 1000000.0);
-    x = statHistDeltaMedian(&l->dns.svc_time, &f->dns.svc_time);
+                      stats.icp_reply_median_svc_time / fct);
     storeAppendPrintf(sentry, "dns.median_svc_time = %f seconds\n",
-                      x / 1000.0);
+                      stats.dns_median_svc_time / fct);
     storeAppendPrintf(sentry, "unlink.requests = %f/sec\n",
-                      XAVG(unlink.requests));
+                      stats.unlink_requests);
     storeAppendPrintf(sentry, "page_faults = %f/sec\n",
-                      XAVG(page_faults));
+                      stats.page_faults);
     storeAppendPrintf(sentry, "select_loops = %f/sec\n",
-                      XAVG(select_loops));
+                      stats.select_loops);
     storeAppendPrintf(sentry, "select_fds = %f/sec\n",
-                      XAVG(select_fds));
+                      stats.select_fds);
     storeAppendPrintf(sentry, "average_select_fd_period = %f/fd\n",
-                      f->select_fds > l->select_fds ?
-                      (f->select_time - l->select_time) / (f->select_fds - l->select_fds)
-                      : 0.0);
-    x = statHistDeltaMedian(&l->select_fds_hist, &f->select_fds_hist);
-    storeAppendPrintf(sentry, "median_select_fds = %f\n", x);
+                      stats.average_select_fd_period / fct);
+    storeAppendPrintf(sentry, "median_select_fds = %f\n",
+                      stats.median_select_fds / fct);
     storeAppendPrintf(sentry, "swap.outs = %f/sec\n",
-                      XAVG(swap.outs));
+                      stats.swap_outs);
     storeAppendPrintf(sentry, "swap.ins = %f/sec\n",
-                      XAVG(swap.ins));
+                      stats.swap_ins);
     storeAppendPrintf(sentry, "swap.files_cleaned = %f/sec\n",
-                      XAVG(swap.files_cleaned));
+                      stats.swap_files_cleaned);
     storeAppendPrintf(sentry, "aborted_requests = %f/sec\n",
-                      XAVG(aborted_requests));
+                      stats.aborted_requests);
 
 #if USE_POLL
-    storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", XAVG(syscalls.selects));
+    storeAppendPrintf(sentry, "syscalls.polls = %f/sec\n", stats.syscalls_selects);
 #elif defined(USE_SELECT) || defined(USE_SELECT_WIN32)
-    storeAppendPrintf(sentry, "syscalls.selects = %f/sec\n", XAVG(syscalls.selects));
+    storeAppendPrintf(sentry, "syscalls.selects = %f/sec\n", stats.syscalls_selects);
 #endif
 
-    storeAppendPrintf(sentry, "syscalls.disk.opens = %f/sec\n", XAVG(syscalls.disk.opens));
-    storeAppendPrintf(sentry, "syscalls.disk.closes = %f/sec\n", XAVG(syscalls.disk.closes));
-    storeAppendPrintf(sentry, "syscalls.disk.reads = %f/sec\n", XAVG(syscalls.disk.reads));
-    storeAppendPrintf(sentry, "syscalls.disk.writes = %f/sec\n", XAVG(syscalls.disk.writes));
-    storeAppendPrintf(sentry, "syscalls.disk.seeks = %f/sec\n", XAVG(syscalls.disk.seeks));
-    storeAppendPrintf(sentry, "syscalls.disk.unlinks = %f/sec\n", XAVG(syscalls.disk.unlinks));
-    storeAppendPrintf(sentry, "syscalls.sock.accepts = %f/sec\n", XAVG(syscalls.sock.accepts));
-    storeAppendPrintf(sentry, "syscalls.sock.sockets = %f/sec\n", XAVG(syscalls.sock.sockets));
-    storeAppendPrintf(sentry, "syscalls.sock.connects = %f/sec\n", XAVG(syscalls.sock.connects));
-    storeAppendPrintf(sentry, "syscalls.sock.binds = %f/sec\n", XAVG(syscalls.sock.binds));
-    storeAppendPrintf(sentry, "syscalls.sock.closes = %f/sec\n", XAVG(syscalls.sock.closes));
-    storeAppendPrintf(sentry, "syscalls.sock.reads = %f/sec\n", XAVG(syscalls.sock.reads));
-    storeAppendPrintf(sentry, "syscalls.sock.writes = %f/sec\n", XAVG(syscalls.sock.writes));
-    storeAppendPrintf(sentry, "syscalls.sock.recvfroms = %f/sec\n", XAVG(syscalls.sock.recvfroms));
-    storeAppendPrintf(sentry, "syscalls.sock.sendtos = %f/sec\n", XAVG(syscalls.sock.sendtos));
-
-    storeAppendPrintf(sentry, "cpu_time = %f seconds\n", ct);
-    storeAppendPrintf(sentry, "wall_time = %f seconds\n", dt);
-    storeAppendPrintf(sentry, "cpu_usage = %f%%\n", Math::doublePercent(ct, dt));
+    storeAppendPrintf(sentry, "syscalls.disk.opens = %f/sec\n", stats.syscalls_disk_opens);
+    storeAppendPrintf(sentry, "syscalls.disk.closes = %f/sec\n", stats.syscalls_disk_closes);
+    storeAppendPrintf(sentry, "syscalls.disk.reads = %f/sec\n", stats.syscalls_disk_reads);
+    storeAppendPrintf(sentry, "syscalls.disk.writes = %f/sec\n", stats.syscalls_disk_writes);
+    storeAppendPrintf(sentry, "syscalls.disk.seeks = %f/sec\n", stats.syscalls_disk_seeks);
+    storeAppendPrintf(sentry, "syscalls.disk.unlinks = %f/sec\n", stats.syscalls_disk_unlinks);
+    storeAppendPrintf(sentry, "syscalls.sock.accepts = %f/sec\n", stats.syscalls_sock_accepts);
+    storeAppendPrintf(sentry, "syscalls.sock.sockets = %f/sec\n", stats.syscalls_sock_sockets);
+    storeAppendPrintf(sentry, "syscalls.sock.connects = %f/sec\n", stats.syscalls_sock_connects);
+    storeAppendPrintf(sentry, "syscalls.sock.binds = %f/sec\n", stats.syscalls_sock_binds);
+    storeAppendPrintf(sentry, "syscalls.sock.closes = %f/sec\n", stats.syscalls_sock_closes);
+    storeAppendPrintf(sentry, "syscalls.sock.reads = %f/sec\n", stats.syscalls_sock_reads);
+    storeAppendPrintf(sentry, "syscalls.sock.writes = %f/sec\n", stats.syscalls_sock_writes);
+    storeAppendPrintf(sentry, "syscalls.sock.recvfroms = %f/sec\n", stats.syscalls_sock_recvfroms);
+    storeAppendPrintf(sentry, "syscalls.sock.sendtos = %f/sec\n", stats.syscalls_sock_sendtos);
+
+    storeAppendPrintf(sentry, "cpu_time = %f seconds\n", stats.cpu_time);
+    storeAppendPrintf(sentry, "wall_time = %f seconds\n", stats.wall_time);
+    storeAppendPrintf(sentry, "cpu_usage = %f%%\n", Math::doublePercent(stats.cpu_time, stats.wall_time));
 }
 
 static void
 statRegisterWithCacheManager(void)
 {
-    CacheManager *manager = CacheManager::GetInstance();
-    manager->registerAction("info", "General Runtime Information",
-                            info_get, 0, 1);
-    manager->registerAction("service_times", "Service Times (Percentiles)",
-                            service_times, 0, 1);
-    manager->registerAction("filedescriptors", "Process Filedescriptor Allocation",
+    Mgr::RegisterAction("info", "General Runtime Information",
+                            &Mgr::InfoAction::Create, 0, 1);
+    Mgr::RegisterAction("service_times", "Service Times (Percentiles)",
+                            &Mgr::ServiceTimesAction::Create, 0, 1);
+    Mgr::RegisterAction("filedescriptors", "Process Filedescriptor Allocation",
                             fde::DumpStats, 0, 1);
-    manager->registerAction("objects", "All Cache Objects", stat_objects_get, 0, 0);
-    manager->registerAction("vm_objects", "In-Memory and In-Transit Objects",
+    Mgr::RegisterAction("objects", "All Cache Objects", stat_objects_get, 0, 0);
+    Mgr::RegisterAction("vm_objects", "In-Memory and In-Transit Objects",
                             stat_vmobjects_get, 0, 0);
-    manager->registerAction("io", "Server-side network read() size histograms",
-                            stat_io_get, 0, 1);
-    manager->registerAction("counters", "Traffic and Resource Counters",
-                            statCountersDump, 0, 1);
-    manager->registerAction("peer_select", "Peer Selection Algorithms",
+    Mgr::RegisterAction("io", "Server-side network read() size histograms",
+                            &Mgr::IoAction::Create, 0, 1);
+    Mgr::RegisterAction("counters", "Traffic and Resource Counters",
+                            &Mgr::CountersAction::Create, 0, 1);
+    Mgr::RegisterAction("peer_select", "Peer Selection Algorithms",
                             statPeerSelect, 0, 1);
-    manager->registerAction("digest_stats", "Cache Digest and ICP blob",
+    Mgr::RegisterAction("digest_stats", "Cache Digest and ICP blob",
                             statDigestBlob, 0, 1);
-    manager->registerAction("5min", "5 Minute Average of Counters",
-                            statAvg5min, 0, 1);
-    manager->registerAction("60min", "60 Minute Average of Counters",
-                            statAvg60min, 0, 1);
-    manager->registerAction("utilization", "Cache Utilization",
+    Mgr::RegisterAction("5min", "5 Minute Average of Counters",
+                            &Mgr::IntervalAction::Create5min, 0, 1);
+    Mgr::RegisterAction("60min", "60 Minute Average of Counters",
+                            &Mgr::IntervalAction::Create60min, 0, 1);
+    Mgr::RegisterAction("utilization", "Cache Utilization",
                             statUtilization, 0, 1);
-    manager->registerAction("histograms", "Full Histogram Counts",
+    Mgr::RegisterAction("histograms", "Full Histogram Counts",
                             statCountersHistograms, 0, 1);
-    manager->registerAction("active_requests",
+    Mgr::RegisterAction("active_requests",
                             "Client-side Active Requests",
                             statClientRequests, 0, 1);
-    manager->registerAction("username_cache",
+    Mgr::RegisterAction("username_cache",
                             "Active Cached Usernames",
                             AuthUser::UsernameCacheStats, 0, 1);
 #if DEBUG_OPENFD
-    manager->registerAction("openfd_objects", "Objects with Swapout files open",
+    Mgr::RegisterAction("openfd_objects", "Objects with Swapout files open",
                             statOpenfdObj, 0, 0);
 #endif
 #if STAT_GRAPHS
-    manager->registerAction("graph_variables", "Display cache metrics graphically",
+    Mgr::RegisterAction("graph_variables", "Display cache metrics graphically",
                             statGraphDump, 0, 1);
 #endif
 }
@@ -1263,6 +1586,14 @@ statCountersHistograms(StoreEntry * sentry)
 
 static void
 statCountersDump(StoreEntry * sentry)
+{
+    Mgr::CountersActionData stats;
+    GetCountersStats(stats);
+    DumpCountersStats(stats, sentry);
+}
+
+void
+GetCountersStats(Mgr::CountersActionData& stats)
 {
     StatCounters *f = &statCounter;
 
@@ -1271,126 +1602,195 @@ statCountersDump(StoreEntry * sentry)
     f->page_faults = rusage_pagefaults(&rusage);
     f->cputime = rusage_cputime(&rusage);
 
+    stats.sample_time = f->timestamp;
+    stats.client_http_requests = f->client_http.requests;
+    stats.client_http_hits = f->client_http.hits;
+    stats.client_http_errors = f->client_http.errors;
+    stats.client_http_kbytes_in = f->client_http.kbytes_in.kb;
+    stats.client_http_kbytes_out = f->client_http.kbytes_out.kb;
+    stats.client_http_hit_kbytes_out = f->client_http.hit_kbytes_out.kb;
+
+    stats.server_all_requests = f->server.all.requests;
+    stats.server_all_errors = f->server.all.errors;
+    stats.server_all_kbytes_in = f->server.all.kbytes_in.kb;
+    stats.server_all_kbytes_out = f->server.all.kbytes_out.kb;
+
+    stats.server_http_requests = f->server.http.requests;
+    stats.server_http_errors = f->server.http.errors;
+    stats.server_http_kbytes_in = f->server.http.kbytes_in.kb;
+    stats.server_http_kbytes_out = f->server.http.kbytes_out.kb;
+
+    stats.server_ftp_requests = f->server.ftp.requests;
+    stats.server_ftp_errors = f->server.ftp.errors;
+    stats.server_ftp_kbytes_in = f->server.ftp.kbytes_in.kb;
+    stats.server_ftp_kbytes_out = f->server.ftp.kbytes_out.kb;
+
+    stats.server_other_requests = f->server.other.requests;
+    stats.server_other_errors = f->server.other.errors;
+    stats.server_other_kbytes_in = f->server.other.kbytes_in.kb;
+    stats.server_other_kbytes_out = f->server.other.kbytes_out.kb;
+
+    stats.icp_pkts_sent = f->icp.pkts_sent;
+    stats.icp_pkts_recv = f->icp.pkts_recv;
+    stats.icp_queries_sent = f->icp.queries_sent;
+    stats.icp_replies_sent = f->icp.replies_sent;
+    stats.icp_queries_recv = f->icp.queries_recv;
+    stats.icp_replies_recv = f->icp.replies_recv;
+    stats.icp_query_timeouts = f->icp.query_timeouts;
+    stats.icp_replies_queued = f->icp.replies_queued;
+    stats.icp_kbytes_sent = f->icp.kbytes_sent.kb;
+    stats.icp_kbytes_recv = f->icp.kbytes_recv.kb;
+    stats.icp_q_kbytes_sent = f->icp.q_kbytes_sent.kb;
+    stats.icp_r_kbytes_sent = f->icp.r_kbytes_sent.kb;
+    stats.icp_q_kbytes_recv = f->icp.q_kbytes_recv.kb;
+    stats.icp_r_kbytes_recv = f->icp.r_kbytes_recv.kb;
+
+#if USE_CACHE_DIGESTS
+
+    stats.icp_times_used = f->icp.times_used;
+    stats.cd_times_used = f->cd.times_used;
+    stats.cd_msgs_sent = f->cd.msgs_sent;
+    stats.cd_msgs_recv = f->cd.msgs_recv;
+    stats.cd_memory = f->cd.memory.kb;
+    stats.cd_local_memory = store_digest ? store_digest->mask_size / 1024 : 0;
+    stats.cd_kbytes_sent = f->cd.kbytes_sent.kb;
+    stats.cd_kbytes_recv = f->cd.kbytes_recv.kb;
+#endif
+
+    stats.unlink_requests = f->unlink.requests;
+    stats.page_faults = f->page_faults;
+    stats.select_loops = f->select_loops;
+    stats.cpu_time = f->cputime;
+    stats.wall_time = tvSubDsec(f->timestamp, current_time);
+    stats.swap_outs = f->swap.outs;
+    stats.swap_ins = f->swap.ins;
+    stats.swap_files_cleaned = f->swap.files_cleaned;
+    stats.aborted_requests = f->aborted_requests;
+}
+
+void
+DumpCountersStats(Mgr::CountersActionData& stats, StoreEntry* sentry)
+{
     storeAppendPrintf(sentry, "sample_time = %d.%d (%s)\n",
-                      (int) f->timestamp.tv_sec,
-                      (int) f->timestamp.tv_usec,
-                      mkrfc1123(f->timestamp.tv_sec));
-    storeAppendPrintf(sentry, "client_http.requests = %ld\n",
-                      (long)f->client_http.requests);
-    storeAppendPrintf(sentry, "client_http.hits = %ld\n",
-                      (long)f->client_http.hits);
-    storeAppendPrintf(sentry, "client_http.errors = %ld\n",
-                      (long)f->client_http.errors);
-    storeAppendPrintf(sentry, "client_http.kbytes_in = %ld\n",
-                      (long)f->client_http.kbytes_in.kb);
-    storeAppendPrintf(sentry, "client_http.kbytes_out = %ld\n",
-                      (long)f->client_http.kbytes_out.kb);
-    storeAppendPrintf(sentry, "client_http.hit_kbytes_out = %ld\n",
-                      (long)f->client_http.hit_kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.all.requests = %ld\n",
-                      (long)f->server.all.requests);
-    storeAppendPrintf(sentry, "server.all.errors = %ld\n",
-                      (long) f->server.all.errors);
-    storeAppendPrintf(sentry, "server.all.kbytes_in = %ld\n",
-                      (long) f->server.all.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.all.kbytes_out = %ld\n",
-                      (long) f->server.all.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.http.requests = %ld\n",
-                      (long) f->server.http.requests);
-    storeAppendPrintf(sentry, "server.http.errors = %ld\n",
-                      (long) f->server.http.errors);
-    storeAppendPrintf(sentry, "server.http.kbytes_in = %ld\n",
-                      (long) f->server.http.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.http.kbytes_out = %ld\n",
-                      (long) f->server.http.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.ftp.requests = %ld\n",
-                      (long) f->server.ftp.requests);
-    storeAppendPrintf(sentry, "server.ftp.errors = %ld\n",
-                      (long) f->server.ftp.errors);
-    storeAppendPrintf(sentry, "server.ftp.kbytes_in = %ld\n",
-                      (long) f->server.ftp.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.ftp.kbytes_out = %ld\n",
-                      (long) f->server.ftp.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "server.other.requests = %ld\n",
-                      (long) f->server.other.requests);
-    storeAppendPrintf(sentry, "server.other.errors = %ld\n",
-                      (long) f->server.other.errors);
-    storeAppendPrintf(sentry, "server.other.kbytes_in = %ld\n",
-                      (long) f->server.other.kbytes_in.kb);
-    storeAppendPrintf(sentry, "server.other.kbytes_out = %ld\n",
-                      (long) f->server.other.kbytes_out.kb);
-
-    storeAppendPrintf(sentry, "icp.pkts_sent = %ld\n",
-                      (long)f->icp.pkts_sent);
-    storeAppendPrintf(sentry, "icp.pkts_recv = %ld\n",
-                      (long)f->icp.pkts_recv);
-    storeAppendPrintf(sentry, "icp.queries_sent = %ld\n",
-                      (long)f->icp.queries_sent);
-    storeAppendPrintf(sentry, "icp.replies_sent = %ld\n",
-                      (long)f->icp.replies_sent);
-    storeAppendPrintf(sentry, "icp.queries_recv = %ld\n",
-                      (long)f->icp.queries_recv);
-    storeAppendPrintf(sentry, "icp.replies_recv = %ld\n",
-                      (long)f->icp.replies_recv);
-    storeAppendPrintf(sentry, "icp.query_timeouts = %ld\n",
-                      (long)f->icp.query_timeouts);
-    storeAppendPrintf(sentry, "icp.replies_queued = %ld\n",
-                      (long)f->icp.replies_queued);
-    storeAppendPrintf(sentry, "icp.kbytes_sent = %ld\n",
-                      (long) f->icp.kbytes_sent.kb);
-    storeAppendPrintf(sentry, "icp.kbytes_recv = %ld\n",
-                      (long) f->icp.kbytes_recv.kb);
-    storeAppendPrintf(sentry, "icp.q_kbytes_sent = %ld\n",
-                      (long) f->icp.q_kbytes_sent.kb);
-    storeAppendPrintf(sentry, "icp.r_kbytes_sent = %ld\n",
-                      (long) f->icp.r_kbytes_sent.kb);
-    storeAppendPrintf(sentry, "icp.q_kbytes_recv = %ld\n",
-                      (long) f->icp.q_kbytes_recv.kb);
-    storeAppendPrintf(sentry, "icp.r_kbytes_recv = %ld\n",
-                      (long) f->icp.r_kbytes_recv.kb);
+                      (int) stats.sample_time.tv_sec,
+                      (int) stats.sample_time.tv_usec,
+                      mkrfc1123(stats.sample_time.tv_sec));
+    storeAppendPrintf(sentry, "client_http.requests = %.0f\n",
+                      stats.client_http_requests);
+    storeAppendPrintf(sentry, "client_http.hits = %.0f\n",
+                      stats.client_http_hits);
+    storeAppendPrintf(sentry, "client_http.errors = %.0f\n",
+                      stats.client_http_errors);
+    storeAppendPrintf(sentry, "client_http.kbytes_in = %.0f\n",
+                      stats.client_http_kbytes_in);
+    storeAppendPrintf(sentry, "client_http.kbytes_out = %.0f\n",
+                      stats.client_http_kbytes_out);
+    storeAppendPrintf(sentry, "client_http.hit_kbytes_out = %.0f\n",
+                      stats.client_http_hit_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.all.requests = %.0f\n",
+                      stats.server_all_requests);
+    storeAppendPrintf(sentry, "server.all.errors = %.0f\n",
+                      stats.server_all_errors);
+    storeAppendPrintf(sentry, "server.all.kbytes_in = %.0f\n",
+                      stats.server_all_kbytes_in);
+    storeAppendPrintf(sentry, "server.all.kbytes_out = %.0f\n",
+                      stats.server_all_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.http.requests = %.0f\n",
+                      stats.server_http_requests);
+    storeAppendPrintf(sentry, "server.http.errors = %.0f\n",
+                      stats.server_http_errors);
+    storeAppendPrintf(sentry, "server.http.kbytes_in = %.0f\n",
+                      stats.server_http_kbytes_in);
+    storeAppendPrintf(sentry, "server.http.kbytes_out = %.0f\n",
+                      stats.server_http_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.ftp.requests = %.0f\n",
+                      stats.server_ftp_requests);
+    storeAppendPrintf(sentry, "server.ftp.errors = %.0f\n",
+                      stats.server_ftp_errors);
+    storeAppendPrintf(sentry, "server.ftp.kbytes_in = %.0f\n",
+                      stats.server_ftp_kbytes_in);
+    storeAppendPrintf(sentry, "server.ftp.kbytes_out = %.0f\n",
+                      stats.server_ftp_kbytes_out);
+
+    storeAppendPrintf(sentry, "server.other.requests = %.0f\n",
+                      stats.server_other_requests);
+    storeAppendPrintf(sentry, "server.other.errors = %.0f\n",
+                      stats.server_other_errors);
+    storeAppendPrintf(sentry, "server.other.kbytes_in = %.0f\n",
+                      stats.server_other_kbytes_in);
+    storeAppendPrintf(sentry, "server.other.kbytes_out = %.0f\n",
+                      stats.server_other_kbytes_out);
+
+    storeAppendPrintf(sentry, "icp.pkts_sent = %.0f\n",
+                      stats.icp_pkts_sent);
+    storeAppendPrintf(sentry, "icp.pkts_recv = %.0f\n",
+                      stats.icp_pkts_recv);
+    storeAppendPrintf(sentry, "icp.queries_sent = %.0f\n",
+                      stats.icp_queries_sent);
+    storeAppendPrintf(sentry, "icp.replies_sent = %.0f\n",
+                      stats.icp_replies_sent);
+    storeAppendPrintf(sentry, "icp.queries_recv = %.0f\n",
+                      stats.icp_queries_recv);
+    storeAppendPrintf(sentry, "icp.replies_recv = %.0f\n",
+                      stats.icp_replies_recv);
+    storeAppendPrintf(sentry, "icp.query_timeouts = %.0f\n",
+                      stats.icp_query_timeouts);
+    storeAppendPrintf(sentry, "icp.replies_queued = %.0f\n",
+                      stats.icp_replies_queued);
+    storeAppendPrintf(sentry, "icp.kbytes_sent = %.0f\n",
+                      stats.icp_kbytes_sent);
+    storeAppendPrintf(sentry, "icp.kbytes_recv = %.0f\n",
+                      stats.icp_kbytes_recv);
+    storeAppendPrintf(sentry, "icp.q_kbytes_sent = %.0f\n",
+                      stats.icp_q_kbytes_sent);
+    storeAppendPrintf(sentry, "icp.r_kbytes_sent = %.0f\n",
+                      stats.icp_r_kbytes_sent);
+    storeAppendPrintf(sentry, "icp.q_kbytes_recv = %.0f\n",
+                      stats.icp_q_kbytes_recv);
+    storeAppendPrintf(sentry, "icp.r_kbytes_recv = %.0f\n",
+                      stats.icp_r_kbytes_recv);
 
 #if USE_CACHE_DIGESTS
 
-    storeAppendPrintf(sentry, "icp.times_used = %ld\n",
-                      (long)f->icp.times_used);
-    storeAppendPrintf(sentry, "cd.times_used = %ld\n",
-                      (long)f->cd.times_used);
-    storeAppendPrintf(sentry, "cd.msgs_sent = %ld\n",
-                      (long)f->cd.msgs_sent);
-    storeAppendPrintf(sentry, "cd.msgs_recv = %ld\n",
-                      (long)f->cd.msgs_recv);
-    storeAppendPrintf(sentry, "cd.memory = %ld\n",
-                      (long) f->cd.memory.kb);
-    storeAppendPrintf(sentry, "cd.local_memory = %ld\n",
-                      (long) (store_digest ? store_digest->mask_size / 1024 : 0));
-    storeAppendPrintf(sentry, "cd.kbytes_sent = %ld\n",
-                      (long) f->cd.kbytes_sent.kb);
-    storeAppendPrintf(sentry, "cd.kbytes_recv = %ld\n",
-                      (long) f->cd.kbytes_recv.kb);
+    storeAppendPrintf(sentry, "icp.times_used = %.0f\n",
+                      stats.icp_times_used);
+    storeAppendPrintf(sentry, "cd.times_used = %.0f\n",
+                      stats.cd_times_used);
+    storeAppendPrintf(sentry, "cd.msgs_sent = %.0f\n",
+                      stats.cd_msgs_sent);
+    storeAppendPrintf(sentry, "cd.msgs_recv = %.0f\n",
+                      stats.cd_msgs_recv);
+    storeAppendPrintf(sentry, "cd.memory = %.0f\n",
+                      stats.cd_memory);
+    storeAppendPrintf(sentry, "cd.local_memory = %.0f\n",
+                      stats.cd_local_memory);
+    storeAppendPrintf(sentry, "cd.kbytes_sent = %.0f\n",
+                      stats.cd_kbytes_sent);
+    storeAppendPrintf(sentry, "cd.kbytes_recv = %.0f\n",
+                      stats.cd_kbytes_recv);
 #endif
 
-    storeAppendPrintf(sentry, "unlink.requests = %ld\n",
-                      (long)f->unlink.requests);
-    storeAppendPrintf(sentry, "page_faults = %ld\n",
-                      (long)f->page_faults);
-    storeAppendPrintf(sentry, "select_loops = %ld\n",
-                      (long)f->select_loops);
+    storeAppendPrintf(sentry, "unlink.requests = %.0f\n",
+                      stats.unlink_requests);
+    storeAppendPrintf(sentry, "page_faults = %.0f\n",
+                      stats.page_faults);
+    storeAppendPrintf(sentry, "select_loops = %.0f\n",
+                      stats.select_loops);
     storeAppendPrintf(sentry, "cpu_time = %f\n",
-                      f->cputime);
+                      stats.cpu_time);
     storeAppendPrintf(sentry, "wall_time = %f\n",
-                      tvSubDsec(f->timestamp, current_time));
-    storeAppendPrintf(sentry, "swap.outs = %ld\n",
-                      (long)f->swap.outs);
-    storeAppendPrintf(sentry, "swap.ins = %ld\n",
-                      (long)f->swap.ins);
-    storeAppendPrintf(sentry, "swap.files_cleaned = %ld\n",
-                      (long)f->swap.files_cleaned);
-    storeAppendPrintf(sentry, "aborted_requests = %ld\n",
-                      (long)f->aborted_requests);
+                      stats.wall_time);
+    storeAppendPrintf(sentry, "swap.outs = %.0f\n",
+                      stats.swap_outs);
+    storeAppendPrintf(sentry, "swap.ins = %.0f\n",
+                      stats.swap_ins);
+    storeAppendPrintf(sentry, "swap.files_cleaned = %.0f\n",
+                      stats.swap_files_cleaned);
+    storeAppendPrintf(sentry, "aborted_requests = %.0f\n",
+                      stats.aborted_requests);
 }
 
 void
@@ -1455,18 +1855,6 @@ statDigestBlob(StoreEntry * sentry)
     storeDigestReport(sentry);
 }
 
-static void
-statAvg5min(StoreEntry * e)
-{
-    statAvgDump(e, 5, 0);
-}
-
-static void
-statAvg60min(StoreEntry * e)
-{
-    statAvgDump(e, 60, 0);
-}
-
 static double
 statPctileSvc(double pctile, int interval, int which)
 {
index c4671d1aeed0843541ce838029f38005a344f6d5..e5c0a43c5857e3fbcd2454cc988de56cb5d045e7 100644 (file)
@@ -37,7 +37,7 @@
 #include "event.h"
 #include "fde.h"
 #include "Store.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "StoreClient.h"
 #include "stmem.h"
 #include "HttpReply.h"
@@ -52,6 +52,7 @@
 #include "Stack.h"
 #include "SquidTime.h"
 #include "swap_log_op.h"
+#include "mgr/StoreIoAction.h"
 
 static STMCB storeWriteComplete;
 
@@ -84,8 +85,6 @@ const char *swapStatusStr[] = {
     "SWAPOUT_DONE"
 };
 
-extern OBJH storeIOStats;
-
 
 /*
  * This defines an repl type
@@ -1378,10 +1377,9 @@ StoreEntry::validLength() const
 static void
 storeRegisterWithCacheManager(void)
 {
-    CacheManager *manager=CacheManager::GetInstance();
-    manager->registerAction("storedir", "Store Directory Stats", Store::Stats, 0, 1);
-    manager->registerAction("store_io", "Store IO Interface Stats", storeIOStats, 0, 1);
-    manager->registerAction("store_check_cachable_stats", "storeCheckCachable() Stats",
+    Mgr::RegisterAction("storedir", "Store Directory Stats", Store::Stats, 0, 1);
+    Mgr::RegisterAction("store_io", "Store IO Interface Stats", &Mgr::StoreIoAction::Create, 0, 1);
+    Mgr::RegisterAction("store_check_cachable_stats", "storeCheckCachable() Stats",
                             storeCheckCachableStats, 0, 1);
 }
 
index ac0678dfedd674aaf7fa1a01bfc31ab728a3010d..4d419d5e5c06758e25422c9870876b4cc7c48513 100644 (file)
@@ -42,7 +42,7 @@
 
 #include "squid.h"
 #include "event.h"
-#include "CacheManager.h"
+#include "mgr/Registration.h"
 #if USE_CACHE_DIGESTS
 
 #include "Store.h"
@@ -103,8 +103,7 @@ static void storeDigestAdd(const StoreEntry *);
 static void
 storeDigestRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("store_digest", "Store Digest", storeDigestReport, 0, 1);
+    Mgr::RegisterAction("store_digest", "Store Digest", storeDigestReport, 0, 1);
 }
 
 /*
index 4f95df662c061409fd60d10214eaf85ebf81a9c3..eb4801e2189243aab1cb71d7ebb6017f4d16c48c 100644 (file)
@@ -3,17 +3,7 @@
 #include "MemObject.h"
 #include "SwapDir.h"
 
-static struct {
-
-    struct {
-        int calls;
-        int select_fail;
-        int create_fail;
-        int success;
-    } create;
-} store_io_stats;
-
-OBJH storeIOStats;
+StoreIoStats store_io_stats;
 
 /*
  * submit a request to create a cache object for writing.
@@ -97,17 +87,3 @@ storeIOWrite(StoreIOState::Pointer sio, char const *buf, size_t size, off_t offs
 {
     sio->write(buf,size,offset,free_func);
 }
-
-/*
- * Make this non-static so we can register
- * it from storeInit();
- */
-void
-storeIOStats(StoreEntry * sentry)
-{
-    storeAppendPrintf(sentry, "Store IO Interface Stats\n");
-    storeAppendPrintf(sentry, "create.calls %d\n", store_io_stats.create.calls);
-    storeAppendPrintf(sentry, "create.select_fail %d\n", store_io_stats.create.select_fail);
-    storeAppendPrintf(sentry, "create.create_fail %d\n", store_io_stats.create.create_fail);
-    storeAppendPrintf(sentry, "create.success %d\n", store_io_stats.create.success);
-}
index 617c57e29e279e97887082aebab2aabf3966e698..a9640dce4c227ec8b7274591c6b8bd2abb139bd3 100644 (file)
  */
 
 #include "squid.h"
-#include "CacheManager.h"
 #include "HttpReply.h"
 #include "log/File.h"
 #include "MemObject.h"
+#include "mgr/Registration.h"
 #include "Store.h"
 #include "SquidTime.h"
 
@@ -139,8 +139,7 @@ storeLogClose(void)
 static void
 storeLogRegisterWithCacheManager(void)
 {
-    CacheManager::GetInstance()->
-    registerAction("store_log_tags", "Histogram of store.log tags",
+    Mgr::RegisterAction("store_log_tags", "Histogram of store.log tags",
                    storeLogTagsHist, 0, 1);
 }
 
index ee814a69fce192783f2c637cd08999800bc5560a..80e95636584ddb2ce9b161600a534002da3a738b 100644 (file)
@@ -1002,15 +1002,16 @@ struct _netdbEntry {
     int n_peers;
 };
 
-
 struct _iostats {
 
+    enum { histSize = 16 };
+
     struct {
         int reads;
         int reads_deferred;
-        int read_hist[16];
+        int read_hist[histSize];
         int writes;
-        int write_hist[16];
+        int write_hist[histSize];
     }
 
     Http, Ftp, Gopher;
diff --git a/src/tests/stub_Port.cc b/src/tests/stub_Port.cc
new file mode 100644 (file)
index 0000000..478ce74
--- /dev/null
@@ -0,0 +1,4 @@
+#include "config.h"
+#include "ipc/Port.h"
+
+const char Ipc::coordinatorAddr[] = "";
diff --git a/src/tests/stub_TypedMsgHdr.cc b/src/tests/stub_TypedMsgHdr.cc
new file mode 100644 (file)
index 0000000..52fc5c9
--- /dev/null
@@ -0,0 +1,44 @@
+#include "config.h"
+#include "fatal.h"
+#include "ipc/TypedMsgHdr.h"
+
+Ipc::TypedMsgHdr::TypedMsgHdr()
+{
+    fatal("Not implemented");
+}
+
+void
+Ipc::TypedMsgHdr::getFixed(void *raw, size_t size) const
+{
+    fatal("Not implemented");
+}
+
+void
+Ipc::TypedMsgHdr::putFixed(const void *raw, size_t size)
+{
+    fatal("Not implemented");
+}
+
+void
+Ipc::TypedMsgHdr::getString(String &size) const
+{
+    fatal("Not implemented");
+}
+
+void
+Ipc::TypedMsgHdr::putString(const String & size)
+{
+    fatal("Not implemented");
+}
+
+void
+Ipc::TypedMsgHdr::checkType(int destType) const
+{
+    fatal("Not implemented");
+}
+
+void
+Ipc::TypedMsgHdr::setType(int aType)
+{
+    fatal("Not implemented");
+}
diff --git a/src/tests/stub_UdsOp.cc b/src/tests/stub_UdsOp.cc
new file mode 100644 (file)
index 0000000..7e19dd0
--- /dev/null
@@ -0,0 +1,7 @@
+#include "config.h"
+#include "ipc/UdsOp.h"
+
+void Ipc::SendMessage(const String& toAddress, const TypedMsgHdr& message)
+{
+    fatal ("Not implemented");
+}
index b67584e549a5ce70dc8542cda77cc4cc29fad3ff..7e4eb13febc9e9be883d01cf5110f6bf306ad8d3 100644 (file)
  */
 
 #include "CacheManager.h"
+#include "mgr/Registration.h"
 #include "squid.h"
 
-static CacheManager *cm=0;
-
-CacheManager::CacheManager()
-{
-}
-
-void
-CacheManager::registerAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
+Mgr::Action::Pointer
+CacheManager::createNamedAction(char const* action)
 {
-    return;
+    fatal ("Not implemented");
+    return NULL;
 }
 
 void
-CacheManager::registerAction(CacheManagerAction *anAction)
+CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
 {
     return;
 }
 
-CacheManagerAction *
-CacheManager::findAction(char const * action)
+CacheManager*
+CacheManager::GetInstance(void)
 {
-    return 0;
+    static CacheManager *instance = 0;
+    if (!instance)
+        instance = new CacheManager();
+    return instance;
 }
 
 void
-CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
+Mgr::RegisterAction(char const*, char const*, OBJH, int, int)
 {
-    return;
 }
 
-CacheManager*
-CacheManager::GetInstance(void)
+void
+Mgr::RegisterAction(char const * action, char const * desc,
+    Mgr::ClassActionCreationHandler *handler,
+    int pw_req_flag, int atomic)
 {
-    if (!cm)
-        cm=new CacheManager();
-    return cm;
 }
-
index 132d5732de068288d06f17f9ac31db63ad034a1c..45f8a8b906fce2da268ade94e9a680a219560682 100644 (file)
@@ -156,3 +156,28 @@ _comm_close(int fd, char const *file, int line)
 {
     fatal ("Not implemented");
 }
+
+int
+commSetTimeout(int fd, int timeout, AsyncCall::Pointer& callback)
+{
+    fatal ("Not implemented");
+    return -1;
+}
+
+int
+comm_open_uds(int sock_type, int proto, struct sockaddr_un* addr, int flags)
+{
+    fatal ("Not implemented");
+    return -1;
+}
+
+void
+comm_write(int fd, const char *buf, int size, AsyncCall::Pointer &callback, FREE * free_func)
+{
+    fatal ("Not implemented");
+}
+
+ConnectionDetail::ConnectionDetail() : me(), peer()
+{
+    fatal ("Not implemented");
+}
index fc46bae17a79e68ca76549ecd2b994c81a170c71..655405847d4840f177dc0be00a180e22826c66d3 100644 (file)
@@ -35,6 +35,8 @@
 #include "squid.h"
 #include "Store.h"
 
+StoreIoStats store_io_stats;
+
 void
 StoreEntry::swapOutFileClose()
 {
@@ -61,14 +63,6 @@ storeUnlink(StoreEntry * e)
     fatal ("Not implemented");
 }
 
-
-void
-storeIOStats(StoreEntry *)
-{
-    fatal ("Not implemented");
-}
-
-
 #include "StoreMeta.h"
 
 char *
index 2e94e7d8289df2a2f7f2b23003c2a0cf4380b5b8..95537ed940e827eb47187bf2acc69b02a58e6e4c 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include "config.h"
+#include "protos.h"
 
 int
 percent(int a, int b)
@@ -46,3 +47,10 @@ death(int sig)
     fprintf(stderr, "Not implemented");
     exit(1);
 }
+
+void*
+xmemset(void* dst, int val, size_t sz)
+{
+    assert(dst);
+    return memset(dst, val, sz);
+}
index 39d9d806a1c457bcb376aebdb53648a1a01beed2..702a88fb693b2334352f31d9fd8e5a26281624ca 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "squid.h"
 #include <cppunit/TestAssert.h>
+#include "mgr/Action.h"
 
 #include "Mem.h"
 #include "testCacheManager.h"
@@ -41,16 +42,21 @@ void
 testCacheManager::testRegister()
 {
     CacheManager *manager=CacheManager::GetInstance();
+    CPPUNIT_ASSERT(manager != NULL);
 
-    manager->registerAction("sample", "my sample", &dummy_action, false, false);
-    CacheManagerAction *anAction = manager->findAction("sample");
+    manager->registerProfile("sample", "my sample", &dummy_action, false, false);
+    Mgr::Action::Pointer action = manager->createNamedAction("sample");
+    CPPUNIT_ASSERT(action != NULL);
 
-    CPPUNIT_ASSERT_EQUAL(0, (int)anAction->flags.pw_req);
-    CPPUNIT_ASSERT_EQUAL(0, (int)anAction->flags.atomic);
-    CPPUNIT_ASSERT_EQUAL(String("sample"), String(anAction->action));
+    const Mgr::ActionProfile::Pointer profile = action->command().profile;
+    CPPUNIT_ASSERT(profile != NULL);
+    CPPUNIT_ASSERT(profile->creator != NULL);
+    CPPUNIT_ASSERT_EQUAL(false, profile->isPwReq);
+    CPPUNIT_ASSERT_EQUAL(false, profile->isAtomic);
+    CPPUNIT_ASSERT_EQUAL(String("sample"), String(action->name()));
 
     StoreEntry *sentry=new StoreEntry();
     sentry->flags=0x25; //arbitrary test value
-    anAction->run(sentry);
+    action->run(sentry, false);
     CPPUNIT_ASSERT_EQUAL(1,(int)sentry->flags);
 }
index 72c0273b614224272856dac9180f9ac93f670fa5..401cbdb6bb9cf188d77db1979200d8ea08d12bc0 100644 (file)
@@ -37,6 +37,8 @@
 #include "StoreMetaUnpacker.h"
 #include "Store.h"
 #include "Generic.h"
+#include "mgr/Registration.h"
+
 #undef malloc
 #undef free
 
@@ -70,16 +72,8 @@ storeAppendPrintf(StoreEntry * e, const char *fmt,...)
     va_end(args);
 }
 
-#include "CacheManager.h"
-CacheManager*
-CacheManager::GetInstance()
-{
-    assert(false);
-    return NULL;
-}
-
 void
-CacheManager::registerAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic) {}
+Mgr::RegisterAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic) {}
 
 /* MinGW needs also a stub of death() */
 void