]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/pconn.cc
3 * $Id: pconn.cc,v 1.35 2003/01/23 00:37:24 robertc 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.
41 hash_link hash
; /* must be first */
47 typedef struct _pconn pconn
;
49 #define PCONN_FDS_SZ 8 /* pconn set size, increase for better memcache hit rate */
50 #define PCONN_HIST_SZ (1<<16)
51 int client_pconn_hist
[PCONN_HIST_SZ
];
52 int server_pconn_hist
[PCONN_HIST_SZ
];
54 static IOCB pconnRead
;
55 static PF pconnTimeout
;
56 static const char *pconnKey(const char *host
, u_short port
);
57 static hash_table
*table
= NULL
;
58 static struct _pconn
*pconnNew(const char *key
);
59 static void pconnDelete(struct _pconn
*p
);
60 static void pconnRemoveFD(struct _pconn
*p
, int fd
);
61 static OBJH pconnHistDump
;
62 static MemPool
*pconn_fds_pool
= NULL
;
68 pconnKey(const char *host
, u_short port
)
70 LOCAL_ARRAY(char, buf
, SQUIDHOSTNAMELEN
+ 10);
71 snprintf(buf
, SQUIDHOSTNAMELEN
+ 10, "%s.%d", host
, (int) port
);
75 static struct _pconn
*
76 pconnNew(const char *key
)
79 CBDATA_INIT_TYPE(pconn
);
80 p
= cbdataAlloc(pconn
);
81 p
->hash
.key
= xstrdup(key
);
82 p
->nfds_alloc
= PCONN_FDS_SZ
;
83 p
->fds
= (int *)memPoolAlloc(pconn_fds_pool
);
84 debug(48, 3) ("pconnNew: adding %s\n", hashKeyStr(&p
->hash
));
85 hash_join(table
, &p
->hash
);
90 pconnDelete(struct _pconn
*p
)
92 debug(48, 3) ("pconnDelete: deleting %s\n", hashKeyStr(&p
->hash
));
93 hash_remove_link(table
, (hash_link
*) p
);
94 if (p
->nfds_alloc
== PCONN_FDS_SZ
)
95 memPoolFree(pconn_fds_pool
, p
->fds
);
103 pconnFindFDIndex (struct _pconn
*p
, int fd
)
106 for (result
= 0; result
< p
->nfds
; ++result
) {
107 if (p
->fds
[result
] == fd
)
114 pconnRemoveFDByIndex (struct _pconn
*p
, int index
)
116 for (; index
< p
->nfds
- 1; index
++)
117 p
->fds
[index
] = p
->fds
[index
+ 1];
121 pconnPreventHandingOutFD(struct _pconn
*p
, int fd
)
123 int i
= pconnFindFDIndex (p
, fd
);
125 debug(48, 3) ("pconnRemoveFD: found FD %d at index %d\n", fd
, i
);
126 pconnRemoveFDByIndex(p
, i
);
130 pconnRemoveFD(struct _pconn
*p
, int fd
)
132 pconnPreventHandingOutFD(p
, fd
);
138 pconnTimeout(int fd
, void *data
)
140 struct _pconn
*p
= (_pconn
*)data
;
141 assert(table
!= NULL
);
142 debug(48, 3) ("pconnTimeout: FD %d %s\n", fd
, hashKeyStr(&p
->hash
));
143 pconnRemoveFD(p
, fd
);
148 pconnRead(int fd
, char *buf
, size_t len
, comm_err_t flag
, int xerrno
, void *data
)
150 struct _pconn
*p
= (_pconn
*)data
;
151 assert(table
!= NULL
);
152 /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
153 if (flag
== COMM_ERR_CLOSING
) {
157 debug(48, 3) ("pconnRead: %d bytes from FD %d, %s\n", (int) len
, fd
,
158 hashKeyStr(&p
->hash
));
159 pconnRemoveFD(p
, fd
);
164 pconnHistDump(StoreEntry
* e
)
168 "Client-side persistent connection counts:\n"
172 "\t---- ---------\n");
173 for (i
= 0; i
< PCONN_HIST_SZ
; i
++) {
174 if (client_pconn_hist
[i
] == 0)
176 storeAppendPrintf(e
, "\t%4d %9d\n", i
, client_pconn_hist
[i
]);
180 "Server-side persistent connection counts:\n"
184 "\t---- ---------\n");
185 for (i
= 0; i
< PCONN_HIST_SZ
; i
++) {
186 if (server_pconn_hist
[i
] == 0)
188 storeAppendPrintf(e
, "\t%4d %9d\n", i
, server_pconn_hist
[i
]);
192 /* ========== PUBLIC FUNCTIONS ============================================ */
199 assert(table
== NULL
);
200 table
= hash_create((HASHCMP
*) strcmp
, 229, hash_string
);
201 for (i
= 0; i
< PCONN_HIST_SZ
; i
++) {
202 client_pconn_hist
[i
] = 0;
203 server_pconn_hist
[i
] = 0;
205 pconn_fds_pool
= memPoolCreate("pconn_fds", PCONN_FDS_SZ
* sizeof(int));
207 cachemgrRegister("pconn",
208 "Persistent Connection Utilization Histograms",
209 pconnHistDump
, 0, 1);
210 debug(48, 3) ("persistent connection module initialized\n");
214 pconnPush(int fd
, const char *host
, u_short port
)
218 LOCAL_ARRAY(char, key
, SQUIDHOSTNAMELEN
+ 10);
219 LOCAL_ARRAY(char, desc
, FD_DESC_SZ
);
220 if (fdNFree() < (RESERVED_FD
<< 1)) {
221 debug(48, 3) ("pconnPush: Not many unused FDs\n");
224 } else if (shutting_down
) {
228 assert(table
!= NULL
);
229 strcpy(key
, pconnKey(host
, port
));
230 p
= (struct _pconn
*) hash_lookup(table
, key
);
233 if (p
->nfds
== p
->nfds_alloc
) {
234 debug(48, 3) ("pconnPush: growing FD array\n");
237 p
->fds
= (int *)xmalloc(p
->nfds_alloc
* sizeof(int));
238 xmemcpy(p
->fds
, old
, p
->nfds
* sizeof(int));
239 if (p
->nfds
== PCONN_FDS_SZ
)
240 memPoolFree(pconn_fds_pool
, old
);
244 p
->fds
[p
->nfds
++] = fd
;
245 comm_read(fd
, p
->buf
, BUFSIZ
, pconnRead
, p
);
246 commSetTimeout(fd
, Config
.Timeout
.pconn
, pconnTimeout
, p
);
247 snprintf(desc
, FD_DESC_SZ
, "%s idle connection", host
);
249 debug(48, 3) ("pconnPush: pushed FD %d for %s\n", fd
, key
);
253 * return a pconn fd for host:port, or -1 if none are available
255 * XXX this routine isn't terribly efficient - if there's a pending
256 * read event (which signifies the fd will close in the next IO loop!)
257 * we ignore the FD and move onto the next one. This means, as an example,
258 * if we have a lot of FDs open to a very popular server and we get a bunch
259 * of requests JUST as they timeout (say, it shuts down) we'll be wasting
260 * quite a bit of CPU. Just keep it in mind.
263 pconnPop(const char *host
, u_short port
)
268 LOCAL_ARRAY(char, key
, SQUIDHOSTNAMELEN
+ 10);
269 assert(table
!= NULL
);
270 strcpy(key
, pconnKey(host
, port
));
271 hptr
= (hash_link
*)hash_lookup(table
, key
);
273 p
= (struct _pconn
*) hptr
;
275 for (int i
= 0; i
< p
->nfds
; i
++) {
277 /* If there are pending read callbacks - we're about to close it, so don't issue it! */
278 if (!comm_has_pending_read_callback(fd
)) {
279 pconnRemoveFD(p
, fd
);
280 comm_read_cancel(fd
, pconnRead
, p
);
281 commSetTimeout(fd
, -1, NULL
, NULL
);
286 /* Nothing (valid!) found */
291 pconnHistCount(int what
, int i
)
293 if (i
>= PCONN_HIST_SZ
)
294 i
= PCONN_HIST_SZ
- 1;
295 /* what == 0 for client, 1 for server */
297 client_pconn_hist
[i
]++;
299 server_pconn_hist
[i
]++;