]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Turned pconn.cc into C++ classes. There are now separate persistent
authorwessels <>
Wed, 7 Dec 2005 06:03:34 +0000 (06:03 +0000)
committerwessels <>
Wed, 7 Dec 2005 06:03:34 +0000 (06:03 +0000)
connection pools for client-side, server-side, and now ICAP.

Accounting for persistent connection use still sucks because HTTP
(http.c) and ICAP state structures don't have any way to keep track
of how many times a given TCP connection was used.  So we'll keep
abusing fd_entry[] for this purpose.

12 files changed:
src/ICAP/ICAPModXact.cc
src/ICAP/ICAPXaction.cc
src/client_side.cc
src/comm.cc
src/fde.cc
src/fde.h
src/forward.cc
src/http.cc
src/main.cc
src/pconn.cc
src/pconn.h [new file with mode: 0644]
src/protos.h

index e4dd01a5791e7989dd5595d6dc64e23c9fdcb350..da763b9a76232ec34dcd6834d73d732b7362b3b6 100644 (file)
@@ -707,7 +707,7 @@ bool ICAPModXact::parseHead(HttpMsg *head)
     }
 
     if (httpHeaderHasConnDir(&head->header, "close")) {
-        debug(0,0)("%s(%d) found connection close!\n", __FILE__,__LINE__);
+        debug(93,5)("%s(%d) found connection close\n", __FILE__,__LINE__);
         reuseConnection = false;
     }
 
index b4bb330c8495f50ea0ca47edc97b0846e16acae1..2a6503ca9c1e622d531656334502a169535f15c5 100644 (file)
@@ -8,6 +8,10 @@
 #include "ICAPXaction.h"
 #include "ICAPClient.h"
 #include "TextException.h"
+#include "pconn.h"
+#include "fde.h"
+
+static PconnPool *icapPconnPool = new PconnPool("ICAP Servers");
 
 /* comm module handlers (wrappers around corresponding ICAPXaction methods */
 
@@ -81,7 +85,7 @@ void ICAPXaction::openConnection()
 {
     const ICAPServiceRep &s = service();
     // TODO: check whether NULL domain is appropriate here
-    connection = pconnPop(s.host.buf(), s.port, NULL);
+    connection = icapPconnPool->pop(s.host.buf(), s.port, NULL);
 
     if (connection >= 0) {
         debug(93,3)("%s(%d) reused pconn FD %d\n", __FILE__, __LINE__, connection);
@@ -144,7 +148,7 @@ void ICAPXaction::closeConnection()
 
         if (reuseConnection) {
             debug(93,3)("%s(%d) pushing pconn %d\n", __FILE__,__LINE__,connection);
-            pconnPush(connection, theService->host.buf(), theService->port, NULL);
+            icapPconnPool->push(connection, theService->host.buf(), theService->port, NULL);
         } else {
             debug(93,3)("%s(%d) closing pconn %d\n", __FILE__,__LINE__,connection);
             comm_close(connection);
@@ -174,6 +178,7 @@ void ICAPXaction::scheduleWrite(MemBuf &buf)
     // comm module will free the buffer
     writer = &ICAPXaction_noteCommWrote;
     comm_old_write_mbuf(connection, &buf, writer, this);
+    fd_table[connection].noteUse(icapPconnPool);
 }
 
 void ICAPXaction::noteCommWrote(comm_err_t commStatus, size_t size)
index c10cf436e5eb3c6bd7e5344fd5e8f8ad83dd8f7b..2599fb746dc79020d49a096018f9595461489fba 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: client_side.cc,v 1.704 2005/11/29 20:18:20 serassio Exp $
+ * $Id: client_side.cc,v 1.705 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section 33    Client-side Routines
  * AUTHOR: Duane Wessels
@@ -624,8 +624,6 @@ ConnStateData::~ConnStateData()
 
     auth_user_request = NULL;
 
-    pconnHistCount(0, nrequests);
-
     cbdataReferenceDone(port);
 }
 
index 212b9cbebd32d4981175b705e4d433ee904ca7cd..8ef527ac34ec5199a5324134af675777fcb4366e 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: comm.cc,v 1.411 2005/09/17 05:50:08 wessels Exp $
+ * $Id: comm.cc,v 1.412 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section 5     Socket Functions
  * AUTHOR: Harvest Derived
@@ -42,6 +42,7 @@
 #include "CommIO.h"
 #include "ConnectionDetail.h"
 #include "MemBuf.h"
+#include "pconn.h"
 
 #if defined(_SQUID_CYGWIN_)
 #include <sys/ioctl.h>
@@ -1786,8 +1787,8 @@ _comm_close(int fd, char const *file, int line)
 
     commCallCloseHandlers(fd);
 
-    if (F->uses)               /* assume persistent connect count */
-        pconnHistCount(1, F->uses);
+    if (F->pconn.uses)
+        F->pconn.pool->count(F->pconn.uses);
 
     comm_empty_os_read_buffers(fd);
 
index 5f025ef0eb4543c3e8693a83950cf6c51d6c7292..69534d24ac707bde68838f515ad85d940e9ea742 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: fde.cc,v 1.2 2003/02/21 22:50:08 robertc Exp $
+ * $Id: fde.cc,v 1.3 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section ??   FDE
  * AUTHOR: Robert Collins
@@ -98,3 +98,9 @@ fde::remoteAddr() const
     return buf;
 }
 
+void
+fde::noteUse(PconnPool *pool)
+{
+    pconn.uses++;
+    pconn.pool = pool;
+}
index cac05c73bf754cbc2a6b282a13360518ab0bb24f..e6329e79213a69f6a177c6845765cb85cf568c89 100644 (file)
--- a/src/fde.h
+++ b/src/fde.h
@@ -1,6 +1,6 @@
 
 /*
- * $Id: fde.h,v 1.9 2005/08/27 18:40:20 serassio Exp $
+ * $Id: fde.h,v 1.10 2005/12/06 23:03:34 wessels Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -35,6 +35,8 @@
 #define SQUID_FDE_H
 #include "comm.h"
 
+class PconnPool;
+
 class fde
 {
 
@@ -45,6 +47,7 @@ public:
     char const *remoteAddr() const;
     void dumpStats (StoreEntry &, int);
     bool readPending(int);
+    void noteUse(PconnPool *);
 
     unsigned int type;
     u_short local_port;
@@ -101,7 +104,14 @@ unsigned int write_pending:
     flags;
     int bytes_read;
     int bytes_written;
-    int uses;                   /* ie # req's over persistent conn */
+
+    struct
+    {
+        int uses;                   /* ie # req's over persistent conn */
+        PconnPool *pool;
+    }
+
+    pconn;
     unsigned epoll_state;
 
     struct _fde_disk disk;
index 1af4dd2afe8f00f96c08abdf7fc067cbb0e02cde..4549eaf10dc058791d124cab183101f1050a58d0 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: forward.cc,v 1.130 2005/11/06 11:14:27 serassio Exp $
+ * $Id: forward.cc,v 1.131 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section 17    Request Forwarding
  * AUTHOR: Duane Wessels
@@ -42,6 +42,7 @@
 #include "ACLChecklist.h"
 #include "ACL.h"
 #include "HttpReply.h"
+#include "pconn.h"
 
 static PSC fwdStartComplete;
 static void fwdDispatch(FwdState *);
@@ -67,6 +68,8 @@ static void fwdLog(FwdState * fwdState);
 static Logfile *logfile = NULL;
 #endif
 
+static PconnPool *fwdPconnPool = new PconnPool("server-side");
+
 static peer *
 fwdStateServerPeer(FwdState * fwdState)
 {
@@ -581,7 +584,7 @@ fwdConnectStart(void *data)
     if (ftimeout < ctimeout)
         ctimeout = ftimeout;
 
-    if ((fd = pconnPop(host, port, domain)) >= 0) {
+    if ((fd = fwdPconnPool->pop(host, port, domain)) >= 0) {
         if (fwdCheckRetriable(fwdState)) {
             debug(17, 3) ("fwdConnectStart: reusing pconn FD %d\n", fd);
             fwdState->server_fd = fd;
@@ -715,7 +718,7 @@ fwdDispatch(FwdState * fwdState)
 
     fd_note(server_fd, storeUrl(fwdState->entry));
 
-    fd_table[server_fd].uses++;
+    fd_table[server_fd].noteUse(fwdPconnPool);
 
     /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
     assert(entry->ping_status != PING_WAITING);
@@ -1040,6 +1043,12 @@ fwdComplete(FwdState * fwdState)
     }
 }
 
+void
+fwdPconnPush(int fd, const char *host, int port, const char *domain)
+{
+    fwdPconnPool->push(fd, host, port, domain);
+}
+
 void
 fwdInit(void)
 {
index e1ca8e719226f51036739601cd2128f78ac85938..86173e440db1cc7dfa13adeffc96466272d8e2b2 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: http.cc,v 1.469 2005/12/03 18:00:28 wessels Exp $
+ * $Id: http.cc,v 1.470 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
  * AUTHOR: Harvest Derived
@@ -1195,11 +1195,11 @@ HttpStateData::processReplyBody()
 
             if (_peer) {
                 if (_peer->options.originserver)
-                    pconnPush(fd, _peer->name, orig_request->port, orig_request->host);
+                    fwdPconnPush(fd, _peer->name, orig_request->port, orig_request->host);
                 else
-                    pconnPush(fd, _peer->name, _peer->http_port, NULL);
+                    fwdPconnPush(fd, _peer->name, _peer->http_port, NULL);
             } else {
-                pconnPush(fd, request->host, request->port, NULL);
+                fwdPconnPush(fd, request->host, request->port, NULL);
             }
 
             fd = -1;
index 31c6dcd017d7dc3f2ea200e2e160445aa08a9cba..40c534bc5f8ef9f5f0898e5dcaa46e9268f7bf4c 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: main.cc,v 1.414 2005/11/21 22:41:45 wessels Exp $
+ * $Id: main.cc,v 1.415 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section 1     Startup and Main Loop
  * AUTHOR: Harvest Derived
@@ -787,7 +787,6 @@ mainInitialize(void)
         /* after this point we want to see the mallinfo() output */
         do_mallinfo = 1;
         mimeInit(Config.mimeTablePathname);
-        pconnInit();
         refreshInit();
 #if DELAY_POOLS
 
index 33b2335d010d293def68fb4843f69ab434f0155a..a0b56ae748c869d519bc6fd6304539b025a1b097 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: pconn.cc,v 1.44 2004/08/30 05:12:31 robertc Exp $
+ * $Id: pconn.cc,v 1.45 2005/12/06 23:03:34 wessels Exp $
  *
  * DEBUG: section 48    Persistent Connections
  * AUTHOR: Duane Wessels
 #include "squid.h"
 #include "Store.h"
 #include "comm.h"
-
-struct _pconn
-{
-    hash_link hash;            /* must be first */
-    int *fds;
-    int nfds_alloc;
-    int nfds;
-    char buf[4096];
-};
-
-typedef struct _pconn pconn;
+#include "pconn.h"
+#include "fde.h"
 
 #define PCONN_FDS_SZ   8       /* pconn set size, increase for better memcache hit rate */
-#define PCONN_HIST_SZ (1<<16)
-int client_pconn_hist[PCONN_HIST_SZ];
-int server_pconn_hist[PCONN_HIST_SZ];
-
-static IOCB pconnRead;
-static PF pconnTimeout;
-static const char *pconnKey(const char *host, u_short port, const char *domain);
-static hash_table *table = NULL;
-
-static struct _pconn *pconnNew(const char *key);
 
-static void pconnDelete(struct _pconn *p);
-
-static void pconnRemoveFD(struct _pconn *p, int fd);
-static OBJH pconnHistDump;
+static PconnModule *ThePconnModule = NULL;
 static MemAllocator *pconn_fds_pool = NULL;
-CBDATA_TYPE(pconn);
-
+static OBJH PconnModuleDumpWrapper;
+CBDATA_CLASS_INIT(IdleConnList);
 
+/* ========== IdleConnList ============================================ */
 
-static const char *
-pconnKey(const char *host, u_short port, const char *domain)
+IdleConnList::IdleConnList(const char *key, PconnPool *thePool) : parent(thePool)
 {
-    LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN * 2 + 10);
-
-    if (domain)
-        snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d/%s", host, (int) port, domain);
-    else
-        snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d", host, (int) port);
-
-    return buf;
+    hash.key = xstrdup(key);
+    nfds_alloc = PCONN_FDS_SZ;
+    nfds = 0;
+    fds = (int *)pconn_fds_pool->alloc();
 }
 
-static struct _pconn *
-            pconnNew(const char *key)
+IdleConnList::~IdleConnList()
 {
-    pconn *p;
-    CBDATA_INIT_TYPE(pconn);
-    p = cbdataAlloc(pconn);
-    p->hash.key = xstrdup(key);
-    p->nfds_alloc = PCONN_FDS_SZ;
-    p->nfds = 0;
-    p->fds = (int *)pconn_fds_pool->alloc();
-    debug(48, 3) ("pconnNew: adding %s\n", hashKeyStr(&p->hash));
-    hash_join(table, &p->hash);
-    return p;
-}
 
-static void
+    parent->unlinkList(this);
 
-pconnDelete(struct _pconn *p)
-{
-    debug(48, 3) ("pconnDelete: deleting %s\n", hashKeyStr(&p->hash));
-    hash_remove_link(table, (hash_link *) p);
-
-    if (p->nfds_alloc == PCONN_FDS_SZ)
-        pconn_fds_pool->free(p->fds);
+    if (nfds_alloc == PCONN_FDS_SZ)
+        pconn_fds_pool->free(fds);
     else
-        xfree(p->fds);
-
-    xfree(p->hash.key);
+        xfree(fds);
 
-    cbdataFree(p);
+    xfree(hash.key);
 }
 
-static int
-
-pconnFindFDIndex (struct _pconn *p, int fd)
+int
+IdleConnList::findFDIndex (int fd)
 {
-    int result;
+    int index;
 
-    for (result = p->nfds - 1; result >= 0; --result)
-    {
-        if (p->fds[result] == fd)
-            return result;
+    for (index = nfds - 1; index >= 0; --index) {
+        if (fds[index] == fd)
+            return index;
     }
 
-    return p->nfds;
+    return -1;
 }
 
-static void
-
-pconnRemoveFDByIndex (struct _pconn *p, int index)
+void
+IdleConnList::removeFD(int fd)
 {
-    for (; index < p->nfds - 1; index++)
-        p->fds[index] = p->fds[index + 1];
-}
+    int index = findFDIndex(fd);
+    assert(index >= 0);
+    debug(48, 3) ("IdleConnList::removeFD: found FD %d at index %d\n", fd, index);
 
-static void
+    for (; index < nfds - 1; index++)
+        fds[index] = fds[index + 1];
 
-pconnPreventHandingOutFD(struct _pconn *p, int fd)
-{
-    int i = pconnFindFDIndex (p, fd);
-    assert(i >= 0);
-    debug(48, 3) ("pconnRemoveFD: found FD %d at index %d\n", fd, i);
-    pconnRemoveFDByIndex(p, i);
+    if (--nfds == 0) {
+        debug(48, 3) ("IdleConnList::removeFD: deleting %s\n", hashKeyStr(&hash));
+        delete this;
+    }
 }
 
-static void
+void
+IdleConnList::clearHandlers(int fd)
+{
+    comm_read_cancel(fd, IdleConnList::read, this);
+    commSetTimeout(fd, -1, NULL, NULL);
+}
 
-pconnRemoveFD(struct _pconn *p, int fd)
+void
+IdleConnList::push(int fd)
 {
-    pconnPreventHandingOutFD(p, fd);
+    if (nfds == nfds_alloc) {
+        debug(48, 3) ("IdleConnList::push: growing FD array\n");
+        nfds_alloc <<= 1;
+        int *old = fds;
+        fds = (int *)xmalloc(nfds_alloc * sizeof(int));
+        xmemcpy(fds, old, nfds * sizeof(int));
+
+        if (nfds == PCONN_FDS_SZ)
+            pconn_fds_pool->free(old);
+        else
+            xfree(old);
+    }
 
-    if (--p->nfds == 0)
-        pconnDelete(p);
+    fds[nfds++] = fd;
+    comm_read(fd, fakeReadBuf, sizeof(fakeReadBuf), IdleConnList::read, this);
+    commSetTimeout(fd, Config.Timeout.pconn, IdleConnList::timeout, this);
 }
 
-static void
-pconnTimeout(int fd, void *data)
+/*
+ * XXX this routine isn't terribly efficient - if there's a pending
+ * read event (which signifies the fd will close in the next IO loop!)
+ * we ignore the FD and move onto the next one. This means, as an example,
+ * if we have a lot of FDs open to a very popular server and we get a bunch
+ * of requests JUST as they timeout (say, it shuts down) we'll be wasting
+ * quite a bit of CPU. Just keep it in mind.
+ */
+int
+IdleConnList::findUseableFD()
 {
+    assert(nfds);
 
-    struct _pconn *p = (_pconn *)data;
-    assert(table != NULL);
-    debug(48, 3) ("pconnTimeout: FD %d %s\n", fd, hashKeyStr(&p->hash));
-    pconnRemoveFD(p, fd);
-    comm_close(fd);
+    for (int i = 0; i< nfds; i++) {
+        if (!comm_has_pending_read_callback(fds[i])) {
+            return fds[i];
+        }
+    }
+
+    return -1;
 }
 
-static void
-pconnRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
+void
+IdleConnList::read(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
 {
-
-    struct _pconn *p = (_pconn *)data;
-    assert(table != NULL);
-    /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
+    debug(48, 3) ("IdleConnList::read: %d bytes from FD %d\n", (int) len, fd);
 
     if (flag == COMM_ERR_CLOSING) {
+        /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
         return;
     }
 
-    debug(48, 3) ("pconnRead: %d bytes from FD %d, %s\n", (int) len, fd,
-                  hashKeyStr(&p->hash));
-    pconnRemoveFD(p, fd);
+    IdleConnList *list = (IdleConnList *) data;
+    list->removeFD(fd);        /* might delete list */
     comm_close(fd);
 }
 
-static void
-pconnHistDump(StoreEntry * e)
+void
+IdleConnList::timeout(int fd, void *data)
 {
-    int i;
-    storeAppendPrintf(e,
-                      "Client-side persistent connection counts:\n"
-                      "\n"
-                      "\treq/\n"
-                      "\tconn      count\n"
-                      "\t----  ---------\n");
+    debug(48, 3) ("IdleConnList::timeout: FD %d\n", fd);
+    IdleConnList *list = (IdleConnList *) data;
+    list->removeFD(fd);        /* might delete list */
+    comm_close(fd);
+}
 
-    for (i = 0; i < PCONN_HIST_SZ; i++) {
-        if (client_pconn_hist[i] == 0)
-            continue;
+/* ========== PconnPool PRIVATE FUNCTIONS ============================================ */
 
-        storeAppendPrintf(e, "\t%4d  %9d\n", i, client_pconn_hist[i]);
-    }
+const char *
+PconnPool::key(const char *host, u_short port, const char *domain)
+{
+    LOCAL_ARRAY(char, buf, SQUIDHOSTNAMELEN * 2 + 10);
+
+    if (domain)
+        snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d/%s", host, (int) port, domain);
+    else
+        snprintf(buf, SQUIDHOSTNAMELEN * 2 + 10, "%s:%d", host, (int) port);
+
+    return buf;
+}
 
+void
+PconnPool::dumpHist(StoreEntry * e)
+{
+    int i;
     storeAppendPrintf(e,
-                      "\n"
-                      "Server-side persistent connection counts:\n"
+                      "%s persistent connection counts:\n"
                       "\n"
                       "\treq/\n"
                       "\tconn      count\n"
-                      "\t----  ---------\n");
+                      "\t----  ---------\n",
+                      descr);
 
     for (i = 0; i < PCONN_HIST_SZ; i++) {
-        if (server_pconn_hist[i] == 0)
+        if (hist[i] == 0)
             continue;
 
-        storeAppendPrintf(e, "\t%4d  %9d\n", i, server_pconn_hist[i]);
+        storeAppendPrintf(e, "\t%4d  %9d\n", i, hist[i]);
     }
 }
 
-/* ========== PUBLIC FUNCTIONS ============================================ */
+/* ========== PconnPool PUBLIC FUNCTIONS ============================================ */
 
-
-void
-pconnInit(void)
+PconnPool::PconnPool(const char *aDescr) : table(NULL), descr(aDescr)
 {
     int i;
-    assert(table == NULL);
     table = hash_create((HASHCMP *) strcmp, 229, hash_string);
 
-    for (i = 0; i < PCONN_HIST_SZ; i++) {
-        client_pconn_hist[i] = 0;
-        server_pconn_hist[i] = 0;
-    }
+    for (i = 0; i < PCONN_HIST_SZ; i++)
+        hist[i] = 0;
 
-    pconn_fds_pool = MemPools::GetInstance().create("pconn_fds", PCONN_FDS_SZ * sizeof(int));
+    if (ThePconnModule == NULL)
+        ThePconnModule = new PconnModule;
 
-    cachemgrRegister("pconn",
-                     "Persistent Connection Utilization Histograms",
-                     pconnHistDump, 0, 1);
-    debug(48, 3) ("persistent connection module initialized\n");
+    ThePconnModule->add
+    (this);
 }
 
 void
-pconnPush(int fd, const char *host, u_short port, const char *domain)
+PconnPool::push(int fd, const char *host, u_short port, const char *domain)
 {
 
-    struct _pconn *p;
-    int *old;
-    LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10);
+    IdleConnList *list;
+    const char *aKey;
     LOCAL_ARRAY(char, desc, FD_DESC_SZ);
 
     if (fdUsageHigh()) {
-        debug(48, 3) ("pconnPush: Not many unused FDs\n");
+        debug(48, 3) ("PconnPool::push: Not many unused FDs\n");
         comm_close(fd);
         return;
     } else if (shutting_down) {
@@ -261,91 +241,100 @@ pconnPush(int fd, const char *host, u_short port, const char *domain)
         return;
     }
 
-    assert(table != NULL);
-    strncpy(key, pconnKey(host, port, domain), SQUIDHOSTNAMELEN + 10);
-
-    p = (struct _pconn *) hash_lookup(table, key);
-
-    if (p == NULL)
-        p = pconnNew(key);
+    aKey = key(host, port, domain);
 
-    if (p->nfds == p->nfds_alloc) {
-        debug(48, 3) ("pconnPush: growing FD array\n");
-        p->nfds_alloc <<= 1;
-        old = p->fds;
-        p->fds = (int *)xmalloc(p->nfds_alloc * sizeof(int));
-        xmemcpy(p->fds, old, p->nfds * sizeof(int));
+    list = (IdleConnList *) hash_lookup(table, aKey);
 
-        if (p->nfds == PCONN_FDS_SZ)
-            pconn_fds_pool->free(old);
-        else
-            xfree(old);
+    if (list == NULL) {
+        list = new IdleConnList(aKey, this);
+        debug(48, 3) ("pconnNew: adding %s\n", hashKeyStr(&list->hash));
+        hash_join(table, &list->hash);
     }
 
+    list->push(fd);
+
     assert(!comm_has_incomplete_write(fd));
-    p->fds[p->nfds++] = fd;
-    comm_read(fd, p->buf, BUFSIZ, pconnRead, p);
-    commSetTimeout(fd, Config.Timeout.pconn, pconnTimeout, p);
     snprintf(desc, FD_DESC_SZ, "%s idle connection", host);
     fd_note(fd, desc);
-    debug(48, 3) ("pconnPush: pushed FD %d for %s\n", fd, key);
+    debug(48, 3) ("PconnPool::push: pushed FD %d for %s\n", fd, aKey);
 }
 
 /*
  * return a pconn fd for host:port, or -1 if none are available
- * 
- * XXX this routine isn't terribly efficient - if there's a pending
- * read event (which signifies the fd will close in the next IO loop!)
- * we ignore the FD and move onto the next one. This means, as an example,
- * if we have a lot of FDs open to a very popular server and we get a bunch
- * of requests JUST as they timeout (say, it shuts down) we'll be wasting
- * quite a bit of CPU. Just keep it in mind.
  */
 int
-pconnPop(const char *host, u_short port, const char *domain)
+PconnPool::pop(const char *host, u_short port, const char *domain)
 {
+    IdleConnList *list;
+    const char * aKey = key(host, port, domain);
+    list = (IdleConnList *)hash_lookup(table, aKey);
 
-    struct _pconn *p;
-    hash_link *hptr;
-    int fd = -1;
-    LOCAL_ARRAY(char, key, SQUIDHOSTNAMELEN + 10);
-    assert(table != NULL);
-    strncpy(key, pconnKey(host, port, domain), SQUIDHOSTNAMELEN + 10);
-    hptr = (hash_link *)hash_lookup(table, key);
-
-    if (hptr != NULL) {
-
-        p = (struct _pconn *) hptr;
-        assert(p->nfds > 0);
-
-        for (int i = 0; i < p->nfds; i++) {
-            fd = p->fds[p->nfds - 1];
-            /* If there are pending read callbacks - we're about to close it, so don't issue it! */
-
-            if (!comm_has_pending_read_callback(fd)) {
-                pconnRemoveFD(p, fd);
-                comm_read_cancel(fd, pconnRead, p);
-                commSetTimeout(fd, -1, NULL, NULL);
-                return fd;
-            }
-        }
+    if (list == NULL)
+        return -1;
+
+    int fd = list->findUseableFD();
+
+    if (fd >= 0) {
+        list->clearHandlers(fd);
+        list->removeFD(fd);    /* might delete list */
     }
 
-    /* Nothing (valid!) found */
-    return -1;
+    return fd;
 }
 
 void
-pconnHistCount(int what, int i)
+PconnPool::unlinkList(IdleConnList *list) const
 {
-    if (i >= PCONN_HIST_SZ)
-        i = PCONN_HIST_SZ - 1;
-
-    /* what == 0 for client, 1 for server */
-    if (what == 0)
-        client_pconn_hist[i]++;
-    else if (what == 1)
-        server_pconn_hist[i]++;
-    else
-        assert(0);
+    hash_remove_link(table, &list->hash);
+}
+
+void
+PconnPool::count(int uses)
+{
+    if (uses >= PCONN_HIST_SZ)
+        uses = PCONN_HIST_SZ - 1;
+
+    hist[uses]++;
+}
+
+/* ========== PconnModule ============================================ */
+
+/*
+ * This simple class exists only for the cache manager
+ */
+
+PconnModule::PconnModule() : pools(NULL), poolCount(0)
+{
+    pools = (PconnPool **) xcalloc(MAX_NUM_PCONN_POOLS, sizeof(*pools));
+    cachemgrRegister("pconn",
+                     "Persistent Connection Utilization Histograms",
+                     PconnModuleDumpWrapper, 0, 1);
+    pconn_fds_pool = MemPools::GetInstance().create("pconn_fds", PCONN_FDS_SZ * sizeof(int));
+    debug(48, 0) ("persistent connection module initialized\n");
+}
+
+void
+
+PconnModule::add
+    (PconnPool *aPool)
+{
+    assert(poolCount < MAX_NUM_PCONN_POOLS);
+    *(pools+poolCount) = aPool;
+    poolCount++;
+}
+
+void
+PconnModule::dump(StoreEntry *e)
+{
+    int i;
+
+    for (i = 0; i < poolCount; i++) {
+        (*(pools+i))->dumpHist(e);
+    }
+}
+
+static void
+PconnModuleDumpWrapper(StoreEntry *e)
+{
+    ThePconnModule->dump(e);
 }
diff --git a/src/pconn.h b/src/pconn.h
new file mode 100644 (file)
index 0000000..a8a08b5
--- /dev/null
@@ -0,0 +1,80 @@
+
+#ifndef SQUID_PCONN_H
+#define SQUID_PCONN_H
+
+#define MAX_NUM_PCONN_POOLS 10
+#define PCONN_HIST_SZ (1<<16)
+
+class PconnPool;
+
+class IdleConnList
+{
+
+public:
+    IdleConnList(const char *key, PconnPool *parent);
+    ~IdleConnList();
+    int numIdle() { return nfds; }
+
+    int findFDIndex(int fd);
+    void removeFD(int fd);
+    void push(int fd);
+    int findUseableFD();
+    void clearHandlers(int fd);
+
+private:
+    static IOCB read;
+    static PF timeout;
+
+public:
+    hash_link hash;             /* must be first */
+
+private:
+    int *fds;
+    int nfds_alloc;
+    int nfds;
+    PconnPool *parent;
+    char fakeReadBuf[4096];
+    CBDATA_CLASS2(IdleConnList);
+};
+
+class PconnPool
+{
+
+public:
+    PconnPool(const char *);
+
+    void moduleInit();
+    void push(int fd, const char *host, u_short port, const char *domain);
+    int pop(const char *host, u_short port, const char *domain);
+    void count(int uses);
+    void dumpHist(StoreEntry *e);
+    void unlinkList(IdleConnList *list) const;
+
+private:
+
+    static const char *key(const char *host, u_short port, const char *domain);
+
+    int hist[PCONN_HIST_SZ];
+    hash_table *table;
+    const char *descr;
+
+};
+
+class PconnModule
+{
+
+public:
+    PconnModule();
+
+    void add
+        (PconnPool *);
+
+    OBJH dump;
+
+private:
+    PconnPool **pools;
+
+    int poolCount;
+};
+
+#endif /* SQUID_PCONN_H */
index 322ea12ae2dce8424cbb84a629bb48b30166ebc9..2e5e0c3c51067eb84fbab5ab541b65ba40171890 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: protos.h,v 1.514 2005/11/06 16:54:30 serassio Exp $
+ * $Id: protos.h,v 1.515 2005/12/06 23:03:34 wessels Exp $
  *
  *
  * SQUID Web Proxy Cache          http://www.squid-cache.org/
@@ -598,6 +598,7 @@ SQUIDCEXTERN void fwdComplete(FwdState * fwdState);
 SQUIDCEXTERN void fwdInit(void);
 SQUIDCEXTERN int fwdReforwardableStatus(http_status s);
 SQUIDCEXTERN void fwdServersFree(FwdServer ** FSVR);
+SQUIDCEXTERN void fwdPconnPush(int, const char *, int, const char *);
 #if WIP_FWD_LOG
 SQUIDCEXTERN void fwdUninit(void);
 SQUIDCEXTERN void fwdLogRotate(void);
@@ -852,10 +853,6 @@ SQUIDCEXTERN void errorStateFree(ErrorState * err);
 SQUIDCEXTERN err_type errorReservePageId(const char *page_name);
 SQUIDCEXTERN ErrorState *errorCon(err_type type, http_status);
 
-SQUIDCEXTERN void pconnPush(int, const char *host, u_short port, const char *domain);
-SQUIDCEXTERN int pconnPop(const char *host, u_short port, const char *domain);
-SQUIDCEXTERN void pconnInit(void);
-
 /* tools.c */
 SQUIDCEXTERN void dlinkAdd(void *data, dlink_node *, dlink_list *);
 SQUIDCEXTERN void dlinkAddAfter(void *, dlink_node *, dlink_node *, dlink_list *);