source: bin/varnishd/cache/cache_session.c @ c0442f

Revision c0442f, 10.2 KB checked in by Poul-Henning Kamp <phk@…>, 2 years ago (diff)

Only allocate sp->req where we need it.

It's lifetime is now controlled by the timeout_linger parameter, so that
the waiters won't have to think about it at all.

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2011 Varnish Software AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * Session management
30 *
31 * This is a little bit of a mixed back, containing both memory management
32 * and various state-change functions.
33 *
34 */
35
36#include "config.h"
37
38#include <math.h>
39#include <stdio.h>
40#include <stdlib.h>
41
42#include "cache.h"
43
44#include "waiter/waiter.h"
45#include "vtim.h"
46
47/*--------------------------------------------------------------------*/
48
49struct sessmem {
50        unsigned                magic;
51#define SESSMEM_MAGIC           0x555859c5
52
53        struct sesspool         *pool;
54
55        unsigned                workspace;
56        uint16_t                nhttp;
57        void                    *wsp;
58        struct http             *http[2];
59        VTAILQ_ENTRY(sessmem)   list;
60
61        struct sess             sess;
62};
63
64struct sesspool {
65        unsigned                magic;
66#define SESSPOOL_MAGIC          0xd916e202
67        struct pool             *pool;
68        VTAILQ_HEAD(,sessmem)   freelist;
69        struct lock             mtx;
70        unsigned                nsess;
71        unsigned                dly_free_cnt;
72        unsigned                req_size;
73        struct mempool          *mpl_req;
74};
75
76/*--------------------------------------------------------------------
77 * Charge statistics from worker to request and session.
78 */
79
80void
81SES_Charge(struct sess *sp)
82{
83        struct acct *a = &sp->wrk->acct_tmp;
84
85        sp->req_bodybytes += a->bodybytes;
86
87#define ACCT(foo)                               \
88        sp->wrk->stats.s_##foo += a->foo;       \
89        sp->acct_ses.foo += a->foo;             \
90        a->foo = 0;
91#include "tbl/acct_fields.h"
92#undef ACCT
93}
94
95/*--------------------------------------------------------------------
96 * This function allocates a session + assorted peripheral data
97 * structures in one single malloc operation.
98 */
99
100static struct sessmem *
101ses_sm_alloc(void)
102{
103        struct sessmem *sm;
104        unsigned char *p, *q;
105        unsigned nws;
106        uint16_t nhttp;
107        unsigned l, hl;
108
109        /*
110         * It is not necessary to lock these, but we need to
111         * cache them locally, to make sure we get a consistent
112         * view of the value.
113         */
114        nws = cache_param->sess_workspace;
115        nhttp = (uint16_t)cache_param->http_max_hdr;
116
117        hl = HTTP_estimate(nhttp);
118        l = sizeof *sm + nws + 2 * hl;
119        VSC_C_main->sessmem_size = l;
120        p = malloc(l);
121        if (p == NULL)
122                return (NULL);
123        q = p + l;
124
125        /* Don't waste time zeroing the workspace */
126        memset(p, 0, l - nws);
127
128        sm = (void*)p;
129        p += sizeof *sm;
130
131        sm->magic = SESSMEM_MAGIC;
132        sm->workspace = nws;
133        sm->nhttp = nhttp;
134
135        sm->http[0] = HTTP_create(p, nhttp);
136        p += hl;
137
138        sm->http[1] = HTTP_create(p, nhttp);
139        p += hl;
140
141        sm->wsp = p;
142        p += nws;
143
144        assert(p == q);
145
146        return (sm);
147}
148
149/*--------------------------------------------------------------------
150 * This prepares a session for use, based on its sessmem structure.
151 */
152
153static void
154ses_setup(struct sessmem *sm)
155{
156        struct sess *sp;
157
158        CHECK_OBJ_NOTNULL(sm, SESSMEM_MAGIC);
159        sp = &sm->sess;
160        memset(sp, 0, sizeof *sp);
161
162        /* We assume that the sess has been zeroed by the time we get here */
163        AZ(sp->magic);
164
165        sp->magic = SESS_MAGIC;
166        sp->mem = sm;
167        sp->sockaddrlen = sizeof(sp->sockaddr);
168        sp->mysockaddrlen = sizeof(sp->mysockaddr);
169        sp->sockaddr.ss_family = sp->mysockaddr.ss_family = PF_UNSPEC;
170        sp->t_open = NAN;
171        sp->t_idle = NAN;
172        sp->t_req = NAN;
173        sp->t_resp = NAN;
174        EXP_Clr(&sp->exp);
175
176        WS_Init(sp->ws, "sess", sm->wsp, sm->workspace);
177        sp->http = sm->http[0];
178        sp->http0 = sm->http[1];
179}
180
181/*--------------------------------------------------------------------
182 * Get a new session, preferably by recycling an already ready one
183 */
184
185struct sess *
186SES_New(struct worker *wrk, struct sesspool *pp)
187{
188        struct sessmem *sm;
189        struct sess *sp;
190        int do_alloc;
191
192        CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC);
193
194        do_alloc = 0;
195        Lck_Lock(&pp->mtx);
196        sm = VTAILQ_FIRST(&pp->freelist);
197        if (sm != NULL) {
198                VTAILQ_REMOVE(&pp->freelist, sm, list);
199        } else if (pp->nsess < cache_param->max_sess) {
200                pp->nsess++;
201                do_alloc = 1;
202        }
203        wrk->stats.sessmem_free += pp->dly_free_cnt;
204        pp->dly_free_cnt = 0;
205        Lck_Unlock(&pp->mtx);
206        if (do_alloc) {
207                sm = ses_sm_alloc();
208                if (sm != NULL) {
209                        wrk->stats.sessmem_alloc++;
210                        sm->pool = pp;
211                        ses_setup(sm);
212                } else {
213                        wrk->stats.sessmem_fail++;
214                }
215        } else if (sm == NULL) {
216                wrk->stats.sessmem_limit++;
217        }
218        if (sm == NULL)
219                return (NULL);
220        sp = &sm->sess;
221        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
222        return (sp);
223}
224
225/*--------------------------------------------------------------------
226 * Allocate a session for use by background threads.
227 */
228
229struct sess *
230SES_Alloc(void)
231{
232        struct sess *sp;
233        struct sessmem *sm;
234
235        sm = ses_sm_alloc();
236        AN(sm);
237        ses_setup(sm);
238        sp = &sm->sess;
239        sp->sockaddrlen = 0;
240        /* XXX: sp->req ? */
241        return (sp);
242}
243
244/*--------------------------------------------------------------------
245 */
246
247static struct sesspool *
248ses_getpool(const struct sess *sp)
249{
250        struct sessmem *sm;
251        struct sesspool *pp;
252
253        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
254        sm = sp->mem;
255        CHECK_OBJ_NOTNULL(sm, SESSMEM_MAGIC);
256        pp = sm->pool;
257        CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC);
258        return (pp);
259}
260
261/*--------------------------------------------------------------------
262 * Schedule a session back on a work-thread from its pool
263 */
264
265int
266SES_Schedule(struct sess *sp)
267{
268        struct sesspool *pp;
269
270        pp = ses_getpool(sp);
271        AZ(sp->wrk);
272
273        AN(pp->pool);
274
275        if (Pool_Schedule(pp->pool, sp)) {
276                VSC_C_main->client_drop_late++;
277                sp->t_idle = VTIM_real();
278                if (sp->vcl != NULL) {
279                        /*
280                         * A session parked on a busy object can come here
281                         * after it wakes up.  Loose the VCL reference.
282                         */
283                        VCL_Rel(&sp->vcl);
284                }
285                SES_Delete(sp, "dropped", sp->t_idle);
286                return (1);
287        }
288        return (0);
289}
290
291/*--------------------------------------------------------------------
292 * Handle a session (from waiter)
293 */
294
295void
296SES_Handle(struct sess *sp, double now)
297{
298
299        sp->step = STP_WAIT;
300        sp->t_req = now;
301        (void)SES_Schedule(sp);
302}
303
304/*--------------------------------------------------------------------
305 * Close a sessions connection.
306 * XXX: Technically speaking we should catch a t_end timestamp here
307 * XXX: for SES_Delete() to use.
308 */
309
310void
311SES_Close(struct sess *sp, const char *reason)
312{
313        int i;
314
315        assert(sp->fd >= 0);
316        VSL(SLT_SessionClose, sp->vsl_id, "%s", reason);
317        i = close(sp->fd);
318        assert(i == 0 || errno != EBADF); /* XXX EINVAL seen */
319        sp->fd = -1;
320}
321
322/*--------------------------------------------------------------------
323 * (Close &) Free or Recycle a session.
324 *
325 * If the workspace has changed, deleted it, otherwise wash it, and put
326 * it up for adoption.
327 *
328 * XXX: We should also check nhttp
329 */
330
331void
332SES_Delete(struct sess *sp, const char *reason, double now)
333{
334        struct acct *b;
335        struct sessmem *sm;
336        struct worker *wrk;
337        struct sesspool *pp;
338
339        pp = ses_getpool(sp);
340
341        sm = sp->mem;
342        CHECK_OBJ_NOTNULL(sm, SESSMEM_MAGIC);
343        wrk = sp->wrk;
344        CHECK_OBJ_ORNULL(wrk, WORKER_MAGIC);
345
346        if (reason != NULL)
347                SES_Close(sp, reason);
348        if (isnan(now))
349                now = VTIM_real();
350        assert(!isnan(sp->t_open));
351        assert(sp->fd < 0);
352
353        if (sp->req != NULL)
354                SES_ReleaseReq(sp);
355
356        AZ(sp->vcl);
357        if (*sp->addr == '\0')
358                strcpy(sp->addr, "-");
359        if (*sp->port == '\0')
360                strcpy(sp->addr, "-");
361
362        b = &sp->acct_ses;
363
364        VSL(SLT_StatSess, sp->vsl_id, "%s %s %.0f %ju %ju %ju %ju %ju %ju %ju",
365            sp->addr, sp->port,
366            now - sp->t_open,
367            b->sess, b->req, b->pipe, b->pass,
368            b->fetch, b->hdrbytes, b->bodybytes);
369
370        if (sm->workspace != cache_param->sess_workspace ||
371            sm->nhttp != (uint16_t)cache_param->http_max_hdr ||
372            pp->nsess > cache_param->max_sess) {
373                free(sm);
374                Lck_Lock(&pp->mtx);
375                if (wrk != NULL)
376                        wrk->stats.sessmem_free++;
377                else
378                        pp->dly_free_cnt++;
379                pp->nsess--;
380                Lck_Unlock(&pp->mtx);
381        } else {
382                /* Clean and prepare for reuse */
383                ses_setup(sm);
384                Lck_Lock(&pp->mtx);
385                if (wrk != NULL) {
386                        wrk->stats.sessmem_free += pp->dly_free_cnt;
387                        pp->dly_free_cnt = 0;
388                }
389                VTAILQ_INSERT_HEAD(&pp->freelist, sm, list);
390                Lck_Unlock(&pp->mtx);
391        }
392}
393
394/*--------------------------------------------------------------------
395 * Alloc/Free/Clean sp->req
396 */
397
398void
399SES_GetReq(struct sess *sp)
400{
401        struct sesspool *pp;
402
403        pp = ses_getpool(sp);
404        AZ(sp->req);
405        sp->req = MPL_Get(pp->mpl_req, NULL);
406        AN(sp->req);
407        sp->req->magic = REQ_MAGIC;
408}
409
410void
411SES_ReleaseReq(struct sess *sp)
412{
413        struct sesspool *pp;
414
415        pp = ses_getpool(sp);
416        CHECK_OBJ_NOTNULL(sp->req, REQ_MAGIC);
417        MPL_AssertSane(sp->req);
418        MPL_Free(pp->mpl_req, sp->req);
419        sp->req = NULL;
420}
421
422/*--------------------------------------------------------------------
423 * Create and delete pools
424 */
425
426struct sesspool *
427SES_NewPool(struct pool *wp, unsigned pool_no)
428{
429        struct sesspool *pp;
430        char nb[8];
431
432        ALLOC_OBJ(pp, SESSPOOL_MAGIC);
433        AN(pp);
434        pp->pool = wp;
435        VTAILQ_INIT(&pp->freelist);
436        Lck_New(&pp->mtx, lck_sessmem);
437        bprintf(nb, "req%u", pool_no);
438        pp->req_size = sizeof (struct req);
439        pp->mpl_req = MPL_New(nb, &cache_param->req_pool, &pp->req_size);
440        return (pp);
441}
442
443void
444SES_DeletePool(struct sesspool *pp, struct worker *wrk)
445{
446        struct sessmem *sm;
447
448        CHECK_OBJ_NOTNULL(pp, SESSPOOL_MAGIC);
449        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
450        Lck_Lock(&pp->mtx);
451        while (!VTAILQ_EMPTY(&pp->freelist)) {
452                sm = VTAILQ_FIRST(&pp->freelist);
453                CHECK_OBJ_NOTNULL(sm, SESSMEM_MAGIC);
454                VTAILQ_REMOVE(&pp->freelist, sm, list);
455                FREE_OBJ(sm);
456                wrk->stats.sessmem_free++;
457                pp->nsess--;
458        }
459        AZ(pp->nsess);
460        Lck_Unlock(&pp->mtx);
461        Lck_Delete(&pp->mtx);
462        MPL_Destroy(&pp->mpl_req);
463        FREE_OBJ(pp);
464}
Note: See TracBrowser for help on using the repository browser.