]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/pconn.cc
3 * $Id: pconn.cc,v 1.50 2007/04/30 16:56:09 wessels Exp $
5 * DEBUG: section 48 Persistent Connections
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #include "CacheManager.h"
43 #define PCONN_FDS_SZ 8 /* pconn set size, increase for better memcache hit rate */
45 static MemAllocator
*pconn_fds_pool
= NULL
;
46 PconnModule
* PconnModule::instance
= NULL
;
47 CBDATA_CLASS_INIT(IdleConnList
);
49 /* ========== IdleConnList ============================================ */
51 IdleConnList::IdleConnList(const char *key
, PconnPool
*thePool
) : parent(thePool
)
53 hash
.key
= xstrdup(key
);
54 nfds_alloc
= PCONN_FDS_SZ
;
56 fds
= (int *)pconn_fds_pool
->alloc();
59 IdleConnList::~IdleConnList()
62 parent
->unlinkList(this);
64 if (nfds_alloc
== PCONN_FDS_SZ
)
65 pconn_fds_pool
->free(fds
);
73 IdleConnList::findFDIndex (int fd
)
77 for (index
= nfds
- 1; index
>= 0; --index
) {
86 IdleConnList::removeFD(int fd
)
88 int index
= findFDIndex(fd
);
90 debugs(48, 3, "IdleConnList::removeFD: found FD " << fd
<< " at index " << index
);
92 for (; index
< nfds
- 1; index
++)
93 fds
[index
] = fds
[index
+ 1];
96 debugs(48, 3, "IdleConnList::removeFD: deleting " << hashKeyStr(&hash
));
102 IdleConnList::clearHandlers(int fd
)
104 comm_read_cancel(fd
, IdleConnList::read
, this);
105 commSetTimeout(fd
, -1, NULL
, NULL
);
109 IdleConnList::push(int fd
)
111 if (nfds
== nfds_alloc
) {
112 debugs(48, 3, "IdleConnList::push: growing FD array");
115 fds
= (int *)xmalloc(nfds_alloc
* sizeof(int));
116 xmemcpy(fds
, old
, nfds
* sizeof(int));
118 if (nfds
== PCONN_FDS_SZ
)
119 pconn_fds_pool
->free(old
);
125 comm_read(fd
, fakeReadBuf
, sizeof(fakeReadBuf
), IdleConnList::read
, this);
126 commSetTimeout(fd
, Config
.Timeout
.pconn
, IdleConnList::timeout
, this);
130 * XXX this routine isn't terribly efficient - if there's a pending
131 * read event (which signifies the fd will close in the next IO loop!)
132 * we ignore the FD and move onto the next one. This means, as an example,
133 * if we have a lot of FDs open to a very popular server and we get a bunch
134 * of requests JUST as they timeout (say, it shuts down) we'll be wasting
135 * quite a bit of CPU. Just keep it in mind.
138 IdleConnList::findUseableFD()
142 for (int i
= 0; i
< nfds
; i
++) {
143 if (!comm_has_pending_read_callback(fds
[i
])) {
152 IdleConnList::read(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
154 debugs(48, 3, "IdleConnList::read: " << len
<< " bytes from FD " << fd
);
156 if (flag
== COMM_ERR_CLOSING
) {
157 /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
161 IdleConnList
*list
= (IdleConnList
*) data
;
162 list
->removeFD(fd
); /* might delete list */
167 IdleConnList::timeout(int fd
, void *data
)
169 debugs(48, 3, "IdleConnList::timeout: FD " << fd
);
170 IdleConnList
*list
= (IdleConnList
*) data
;
171 list
->removeFD(fd
); /* might delete list */
175 /* ========== PconnPool PRIVATE FUNCTIONS ============================================ */
179 PconnPool::key(const char *host
, u_short port
, const char *domain
, struct IN_ADDR
*client_address
)
181 LOCAL_ARRAY(char, buf
, SQUIDHOSTNAMELEN
* 2 + 10);
183 if (domain
&& client_address
)
184 snprintf(buf
, SQUIDHOSTNAMELEN
* 2 + 10, "%s:%d-%s/%s", host
, (int) port
, inet_ntoa(*client_address
), domain
);
185 else if (domain
&& (!client_address
))
186 snprintf(buf
, SQUIDHOSTNAMELEN
* 2 + 10, "%s:%d/%s", host
, (int) port
, domain
);
187 else if ((!domain
) && client_address
)
188 snprintf(buf
, SQUIDHOSTNAMELEN
* 2 + 10, "%s:%d-%s", host
, (int) port
, inet_ntoa(*client_address
));
190 snprintf(buf
, SQUIDHOSTNAMELEN
* 2 + 10, "%s:%d", host
, (int) port
);
196 PconnPool::dumpHist(StoreEntry
* e
)
200 "%s persistent connection counts:\n"
204 "\t---- ---------\n",
207 for (i
= 0; i
< PCONN_HIST_SZ
; i
++) {
211 storeAppendPrintf(e
, "\t%4d %9d\n", i
, hist
[i
]);
215 /* ========== PconnPool PUBLIC FUNCTIONS ============================================ */
217 PconnPool::PconnPool(const char *aDescr
) : table(NULL
), descr(aDescr
)
220 table
= hash_create((HASHCMP
*) strcmp
, 229, hash_string
);
222 for (i
= 0; i
< PCONN_HIST_SZ
; i
++)
225 PconnModule::GetInstance()->add
231 PconnPool::push(int fd
, const char *host
, u_short port
, const char *domain
, struct IN_ADDR
*client_address
)
236 LOCAL_ARRAY(char, desc
, FD_DESC_SZ
);
240 debugs(48, 3, "PconnPool::push: Not many unused FDs");
243 } else if (shutting_down
)
249 aKey
= key(host
, port
, domain
, client_address
);
251 list
= (IdleConnList
*) hash_lookup(table
, aKey
);
255 list
= new IdleConnList(aKey
, this);
256 debugs(48, 3, "pconnNew: adding " << hashKeyStr(&list
->hash
));
257 hash_join(table
, &list
->hash
);
262 assert(!comm_has_incomplete_write(fd
));
263 snprintf(desc
, FD_DESC_SZ
, "%s idle connection", host
);
265 debugs(48, 3, "PconnPool::push: pushed FD " << fd
<< " for " << aKey
);
269 * return a pconn fd for host:port, or -1 if none are available
273 PconnPool::pop(const char *host
, u_short port
, const char *domain
, struct IN_ADDR
*client_address
)
276 const char * aKey
= key(host
, port
, domain
, client_address
);
277 list
= (IdleConnList
*)hash_lookup(table
, aKey
);
282 int fd
= list
->findUseableFD();
286 list
->clearHandlers(fd
);
287 list
->removeFD(fd
); /* might delete list */
294 PconnPool::unlinkList(IdleConnList
*list
) const
296 hash_remove_link(table
, &list
->hash
);
300 PconnPool::count(int uses
)
302 if (uses
>= PCONN_HIST_SZ
)
303 uses
= PCONN_HIST_SZ
- 1;
308 /* ========== PconnModule ============================================ */
311 * This simple class exists only for the cache manager
314 PconnModule::PconnModule() : pools(NULL
), poolCount(0)
316 pools
= (PconnPool
**) xcalloc(MAX_NUM_PCONN_POOLS
, sizeof(*pools
));
317 pconn_fds_pool
= memPoolCreate("pconn_fds", PCONN_FDS_SZ
* sizeof(int));
318 debugs(48, 0, "persistent connection module initialized");
322 PconnModule::GetInstance()
324 if (instance
== NULL
)
325 instance
= new PconnModule
;
331 PconnModule::registerWithCacheManager(CacheManager
& manager
)
333 manager
.registerAction("pconn",
334 "Persistent Connection Utilization Histograms",
343 assert(poolCount
< MAX_NUM_PCONN_POOLS
);
344 *(pools
+poolCount
) = aPool
;
349 PconnModule::dump(StoreEntry
*e
)
353 for (i
= 0; i
< poolCount
; i
++) {
354 (*(pools
+i
))->dumpHist(e
);
359 PconnModule::DumpWrapper(StoreEntry
*e
)
361 PconnModule::GetInstance()->dump(e
);