varnish-cache/bin/varnishd/cache/cache_session.c
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
 * The overall goal here is to hold as little state as possible for an
32
 * idle session.  This leads to various nasty-ish overloads of struct
33
 * sess fields, for instance ->fd being negative ->reason.
34
 *
35
 */
36
37
#include "config.h"
38
39
#include "cache_varnishd.h"
40
41
#include <errno.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44
45
#include "cache_pool.h"
46
#include "cache_transport.h"
47
48
#include "vsa.h"
49
#include "vtcp.h"
50
#include "vtim.h"
51
#include "waiter/waiter.h"
52
53
/*--------------------------------------------------------------------*/
54
55
void
56 1576
SES_SetTransport(struct worker *wrk, struct sess *sp, struct req *req,
57
    const struct transport *xp)
58
{
59
60 1576
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
61 1576
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
62 1576
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
63 1576
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
64 1576
        assert(xp->number > 0);
65
66 1576
        sp->sattr[SA_TRANSPORT] = xp->number;
67 1576
        req->transport = xp;
68 1576
        wrk->task.func = xp->new_session;
69 1576
        wrk->task.priv = req;
70 1576
}
71
72
/*--------------------------------------------------------------------*/
73
74
static int
75 14577
ses_get_attr(const struct sess *sp, enum sess_attr a, void **dst)
76
{
77 14577
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
78 14577
        assert(a < SA_LAST);
79 14577
        AN(dst);
80
81 14577
        if (sp->sattr[a] == 0xffff) {
82 0
                *dst = NULL;
83 0
                return (-1);
84
        } else {
85 14577
                *dst = sp->ws->s + sp->sattr[a];
86 14577
                return (0);
87
        }
88
}
89
90
static int
91 7847
ses_set_attr(const struct sess *sp, enum sess_attr a, const void *src, int sz)
92
{
93
        void *dst;
94 7847
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
95 7847
        assert(a < SA_LAST);
96 7847
        AN(src);
97 7847
        assert(sz > 0);
98
99 7847
        if (sp->sattr[a] == 0xffff)
100 0
                return (-1);
101 7847
        dst = sp->ws->s + sp->sattr[a];
102 7847
        AN(dst);
103 7847
        memcpy(dst, src, sz);
104 7847
        return (0);
105
}
106
107
static void
108 7463
ses_reserve_attr(struct sess *sp, enum sess_attr a, void **dst, int sz)
109
{
110
        ssize_t o;
111
112 7463
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
113 7463
        assert(a < SA_LAST);
114 7463
        assert(sz >= 0);
115 7463
        AN(dst);
116 7463
        o = WS_Reserve(sp->ws, sz);
117 7462
        assert(o >= sz);
118 7462
        *dst = sp->ws->f;
119 7462
        o = sp->ws->f - sp->ws->s;
120 7462
        WS_Release(sp->ws, sz);
121 7462
        assert(o >= 0 && o <= 0xffff);
122 7462
        sp->sattr[a] = (uint16_t)o;
123 7462
}
124
125
#define SESS_ATTR(UP, low, typ, len)                                    \
126
        int                                                             \
127
        SES_Set_##low(const struct sess *sp, const typ *src)            \
128
        {                                                               \
129
                return (ses_set_attr(sp, SA_##UP, src, len));           \
130
        }                                                               \
131
                                                                        \
132
        int                                                             \
133
        SES_Get_##low(const struct sess *sp, typ **dst)                 \
134
        {                                                               \
135
                return (ses_get_attr(sp, SA_##UP, (void**)dst));        \
136
        }                                                               \
137
                                                                        \
138
        void                                                            \
139
        SES_Reserve_##low(struct sess *sp, typ **dst)                   \
140
        {                                                               \
141
                assert(len >= 0);                                       \
142
                ses_reserve_attr(sp, SA_##UP, (void**)dst, len);        \
143
        }
144
145
#include "tbl/sess_attr.h"
146
147
void
148 2990
SES_Set_String_Attr(struct sess *sp, enum sess_attr a, const char *src)
149
{
150
        void *q;
151
152 2990
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
153 2990
        AN(src);
154
155 2990
        switch (a) {
156
#define SESS_ATTR(UP, low, typ, len)    case SA_##UP: assert(len < 0); break;
157
#include "tbl/sess_attr.h"
158 0
        default:  WRONG("wrong sess_attr");
159
        }
160
161 2990
        ses_reserve_attr(sp, a, &q, strlen(src) + 1);
162 2990
        strcpy(q, src);
163 2990
}
164
165
const char *
166 4907
SES_Get_String_Attr(const struct sess *sp, enum sess_attr a)
167
{
168
        void *q;
169
170 4907
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
171
172 4907
        switch (a) {
173
#define SESS_ATTR(UP, low, typ, len)    case SA_##UP: assert(len < 0); break;
174
#include "tbl/sess_attr.h"
175 0
        default:  WRONG("wrong sess_attr");
176
        }
177
178 4907
        if (ses_get_attr(sp, a, &q) < 0)
179 0
                return (NULL);
180 4907
        return (q);
181
}
182
183
/*--------------------------------------------------------------------*/
184
185
const char *
186 14
HTC_Status(enum htc_status_e e)
187
{
188 14
        switch (e) {
189
#define HTC_STATUS(e, n, s, l)                          \
190
                case HTC_S_ ## e:       return (s);
191
#include "tbl/htc.h"
192
        default:
193 0
                WRONG("HTC_Status");
194
        }
195
        NEEDLESS(return (NULL));
196
}
197
198
/*--------------------------------------------------------------------*/
199
200
void
201 5447
HTC_RxInit(struct http_conn *htc, struct ws *ws)
202
{
203
        ssize_t l;
204
205 5447
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
206 5447
        htc->ws = ws;
207 5447
        (void)WS_Reserve(htc->ws, 0);
208 5446
        htc->rxbuf_b = ws->f;
209 5446
        htc->rxbuf_e = ws->f;
210 5446
        if (htc->pipeline_b != NULL) {
211 63
                AN(htc->pipeline_e);
212
                // assert(WS_Inside(ws, htc->pipeline_b, htc->pipeline_e));
213 63
                l = htc->pipeline_e - htc->pipeline_b;
214 63
                assert(l > 0);
215 63
                assert(l <= ws->r - htc->rxbuf_b);
216 63
                memmove(htc->rxbuf_b, htc->pipeline_b, l);
217 63
                htc->rxbuf_e += l;
218 63
                htc->pipeline_b = NULL;
219 63
                htc->pipeline_e = NULL;
220
        }
221 5446
}
222
223
void
224 4092
HTC_RxPipeline(struct http_conn *htc, void *p)
225
{
226
227 4092
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
228 4092
        if (p == NULL || (char*)p == htc->rxbuf_e) {
229 3098
                htc->pipeline_b = NULL;
230 3098
                htc->pipeline_e = NULL;
231
        } else {
232 994
                assert((char*)p >= htc->rxbuf_b);
233 994
                assert((char*)p < htc->rxbuf_e);
234 994
                htc->pipeline_b = p;
235 994
                htc->pipeline_e = htc->rxbuf_e;
236
        }
237 4092
}
238
239
/*----------------------------------------------------------------------
240
 * Receive a request/packet/whatever, with timeouts
241
 *
242
 * maxbytes is the maximum number of bytes the caller expects to need to
243
 * reach a complete work unit. Note that due to pipelining the actual
244
 * number of bytes passed to func in htc->rxbuf_b through htc->rxbuf_e may
245
 * be larger.
246
 *
247
 * t0 is when we start
248
 * *t1 becomes time of first non-idle rx
249
 * *t2 becomes time of complete rx
250
 * ti is when we return IDLE if nothing has arrived
251
 * tn is when we timeout on non-complete
252
 */
253
254
enum htc_status_e
255 5447
HTC_RxStuff(struct http_conn *htc, htc_complete_f *func,
256
    double *t1, double *t2, double ti, double tn, int maxbytes)
257
{
258
        double tmo;
259
        double now;
260
        enum htc_status_e hs;
261
        ssize_t z;
262
263 5447
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
264 5447
        AN(htc->rfd);
265 5447
        assert(*htc->rfd > 0);
266 5447
        AN(htc->ws->r);
267 5447
        AN(htc->rxbuf_b);
268 5447
        assert(htc->rxbuf_b <= htc->rxbuf_e);
269 5447
        assert(htc->rxbuf_e <= htc->ws->r);
270
271 5447
        AZ(isnan(tn));
272 5447
        if (t1 != NULL)
273 3456
                assert(isnan(*t1));
274
275 5447
        if (htc->rxbuf_e == htc->ws->r) {
276
                /* Can't work with a zero size buffer */
277 2
                WS_ReleaseP(htc->ws, htc->rxbuf_b);
278 2
                return (HTC_S_OVERFLOW);
279
        }
280 5445
        z = (htc->ws->r - htc->rxbuf_b);
281 5445
        if (z < maxbytes)
282 130
                maxbytes = z;   /* Cap maxbytes at available WS */
283
284
        while (1) {
285 15081
                now = VTIM_real();
286 10263
                AZ(htc->pipeline_b);
287 10263
                AZ(htc->pipeline_e);
288 10263
                assert(htc->rxbuf_e <= htc->ws->r);
289
290 10263
                hs = func(htc);
291 10263
                if (hs == HTC_S_OVERFLOW || hs == HTC_S_JUNK) {
292 3
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
293 3
                        return (hs);
294
                }
295 10260
                if (hs == HTC_S_COMPLETE) {
296 4131
                        WS_ReleaseP(htc->ws, htc->rxbuf_e);
297
                        /* Got it, run with it */
298 4131
                        if (t1 != NULL && isnan(*t1))
299 2130
                                *t1 = now;
300 4131
                        if (t2 != NULL)
301 2211
                                *t2 = now;
302 4131
                        return (HTC_S_COMPLETE);
303
                }
304 6129
                if (hs == HTC_S_MORE) {
305
                        /* Working on it */
306 984
                        if (t1 != NULL && isnan(*t1))
307 83
                                *t1 = now;
308 5145
                } else if (hs == HTC_S_EMPTY)
309 5145
                        htc->rxbuf_e = htc->rxbuf_b;
310
                else
311 0
                        WRONG("htc_status_e");
312
313 6129
                tmo = tn - now;
314 6129
                if (!isnan(ti) && ti < tn && hs == HTC_S_EMPTY)
315 5142
                        tmo = ti - now;
316 6129
                z = maxbytes - (htc->rxbuf_e - htc->rxbuf_b);
317 6129
                if (z <= 0) {
318
                        /* maxbytes reached but not HTC_S_COMPLETE. Return
319
                         * overflow. */
320 14
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
321 14
                        return (HTC_S_OVERFLOW);
322
                }
323 6115
                if (tmo <= 0.0)
324 240
                        tmo = 1e-3;
325 6115
                z = VTCP_read(*htc->rfd, htc->rxbuf_e, z, tmo);
326 6114
                if (z == 0 || z == -1) {
327 1165
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
328 1165
                        return (HTC_S_EOF);
329 4949
                } else if (z > 0)
330 4678
                        htc->rxbuf_e += z;
331 271
                else if (z == -2) {
332 271
                        if (hs == HTC_S_EMPTY && ti <= now) {
333 128
                                WS_ReleaseP(htc->ws, htc->rxbuf_b);
334 128
                                return (HTC_S_IDLE);
335
                        }
336 143
                        if (tn <= now) {
337 3
                                WS_ReleaseP(htc->ws, htc->rxbuf_b);
338 3
                                return (HTC_S_TIMEOUT);
339
                        }
340
                }
341
        }
342
}
343
344
/*--------------------------------------------------------------------
345
 * Get a new session, preferably by recycling an already ready one
346
 *
347
 * Layout is:
348
 *      struct sess
349
 *      workspace
350
 */
351
352
struct sess *
353 1463
SES_New(struct pool *pp)
354
{
355
        struct sess *sp;
356
        unsigned sz;
357
        char *p, *e;
358
359 1463
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
360 1463
        sp = MPL_Get(pp->mpl_sess, &sz);
361 1463
        sp->magic = SESS_MAGIC;
362 1463
        sp->pool = pp;
363 1463
        sp->refcnt = 1;
364 1463
        memset(sp->sattr, 0xff, sizeof sp->sattr);
365
366 1463
        e = (char*)sp + sz;
367 1463
        p = (char*)(sp + 1);
368 1463
        p = (void*)PRNDUP(p);
369 1463
        assert(p < e);
370 1463
        WS_Init(sp->ws, "ses", p, e - p);
371
372 1463
        sp->t_open = NAN;
373 1463
        sp->t_idle = NAN;
374 1463
        Lck_New(&sp->mtx, lck_sess);
375 1463
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
376 1463
        return (sp);
377
}
378
379
/*--------------------------------------------------------------------
380
 * Reschedule a request on a work-thread from its sessions pool
381
 *
382
 * This is used to reschedule requests waiting on busy objects
383
 */
384
385
int
386 27
SES_Reschedule_Req(struct req *req, enum task_prio prio)
387
{
388
        struct sess *sp;
389
        struct pool *pp;
390
391 27
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
392 27
        sp = req->sp;
393 27
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
394 27
        pp = sp->pool;
395 27
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
396 27
        AN(TASK_QUEUE_CLIENT(prio));
397
398 27
        AN(req->task.func);
399
400 27
        return (Pool_Task(pp, &req->task, prio));
401
}
402
403
/*--------------------------------------------------------------------
404
 * Handle a session (from waiter)
405
 */
406
407
static void v_matchproto_(waiter_handle_f)
408 124
ses_handle(struct waited *wp, enum wait_event ev, double now)
409
{
410
        struct sess *sp;
411
        struct pool *pp;
412
        struct pool_task *tp;
413
        const struct transport *xp;
414
415 124
        CHECK_OBJ_NOTNULL(wp, WAITED_MAGIC);
416 124
        CAST_OBJ_NOTNULL(sp, wp->priv1, SESS_MAGIC);
417 124
        CAST_OBJ_NOTNULL(xp, (const void*)wp->priv2, TRANSPORT_MAGIC);
418 124
        AN(wp->priv2);
419 124
        assert((void *)sp->ws->f == wp);
420 124
        wp->magic = 0;
421 124
        wp = NULL;
422
423 124
        WS_Release(sp->ws, 0);
424
425 124
        switch (ev) {
426
        case WAITER_TIMEOUT:
427 4
                SES_Delete(sp, SC_RX_TIMEOUT, now);
428 4
                break;
429
        case WAITER_REMCLOSE:
430 11
                SES_Delete(sp, SC_REM_CLOSE, now);
431 11
                break;
432
        case WAITER_ACTION:
433 109
                pp = sp->pool;
434 109
                CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
435 109
                assert(sizeof *tp <= WS_Reserve(sp->ws, sizeof *tp));
436 109
                tp = (void*)sp->ws->f;
437 109
                tp->func = xp->unwait;
438 109
                tp->priv = sp;
439 109
                if (Pool_Task(pp, tp, TASK_QUEUE_REQ))
440 0
                        SES_Delete(sp, SC_OVERLOAD, now);
441 109
                break;
442
        case WAITER_CLOSE:
443 0
                WRONG("Should not see WAITER_CLOSE on client side");
444
                break;
445
        default:
446 0
                WRONG("Wrong event in ses_handle");
447
        }
448 124
}
449
450
/*--------------------------------------------------------------------
451
 */
452
453
void
454 124
SES_Wait(struct sess *sp, const struct transport *xp)
455
{
456
        struct pool *pp;
457
        struct waited *wp;
458
459 124
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
460 124
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
461 124
        pp = sp->pool;
462 124
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
463 124
        assert(sp->fd > 0);
464
        /*
465
         * XXX: waiter_epoll prevents us from zeroing the struct because
466
         * XXX: it keeps state across calls.
467
         */
468 124
        if (VTCP_nonblocking(sp->fd)) {
469 0
                SES_Delete(sp, SC_REM_CLOSE, NAN);
470 0
                return;
471
        }
472
473
        /*
474
         * put struct waited on the workspace
475
         */
476 124
        if (WS_Reserve(sp->ws, sizeof(struct waited))
477
            < sizeof(struct waited)) {
478 0
                SES_Delete(sp, SC_OVERLOAD, NAN);
479 0
                return;
480
        }
481 124
        wp = (void*)sp->ws->f;
482 124
        INIT_OBJ(wp, WAITED_MAGIC);
483 124
        wp->fd = sp->fd;
484 124
        wp->priv1 = sp;
485 124
        wp->priv2 = (uintptr_t)xp;
486 124
        wp->idle = sp->t_idle;
487 124
        wp->func = ses_handle;
488 124
        wp->tmo = &cache_param->timeout_idle;
489 124
        if (Wait_Enter(pp->waiter, wp))
490 0
                SES_Delete(sp, SC_PIPE_OVERFLOW, NAN);
491
}
492
493
/*--------------------------------------------------------------------
494
 * Update sc_ counters by reason
495
 *
496
 * assuming that the approximation of non-atomic global counters is sufficient.
497
 * if not: update to per-wrk
498
 */
499
500
static void
501 1458
ses_close_acct(enum sess_close reason)
502
{
503 1458
        int i = 0;
504
505 1458
        assert(reason != SC_NULL);
506 1458
        switch (reason) {
507
#define SESS_CLOSE(reason, stat, err, desc)             \
508
        case SC_ ## reason:                             \
509
                VSC_C_main->sc_ ## stat++;              \
510
                i = err;                                \
511
                break;
512
#include "tbl/sess_close.h"
513
514
        default:
515 0
                WRONG("Wrong event in ses_close_acct");
516
        }
517 1458
        if (i)
518 246
                VSC_C_main->sess_closed_err++;
519 1458
}
520
521
/*--------------------------------------------------------------------
522
 * Close a session's connection.
523
 * XXX: Technically speaking we should catch a t_end timestamp here
524
 * XXX: for SES_Delete() to use.
525
 */
526
527
void
528 1458
SES_Close(struct sess *sp, enum sess_close reason)
529
{
530
        int i;
531
532 1458
        assert(reason > 0);
533 1458
        assert(sp->fd > 0);
534 1458
        i = close(sp->fd);
535 1458
        assert(i == 0 || errno != EBADF); /* XXX EINVAL seen */
536 1458
        sp->fd = -(int)reason;
537 1458
        ses_close_acct(reason);
538 1458
}
539
540
/*--------------------------------------------------------------------
541
 * Report and dismantle a session.
542
 */
543
544
void
545 1458
SES_Delete(struct sess *sp, enum sess_close reason, double now)
546
{
547
548 1458
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
549
550 1458
        if (reason != SC_NULL)
551 1229
                SES_Close(sp, reason);
552 1458
        assert(sp->fd < 0);
553
554 1458
        if (isnan(now))
555 1443
                now = VTIM_real();
556 1458
        AZ(isnan(sp->t_open));
557 1458
        if (now < sp->t_open) {
558 0
                VSL(SLT_Debug, sp->vxid,
559
                    "Clock step (now=%f < t_open=%f)",
560
                    now, sp->t_open);
561 0
                if (now + cache_param->clock_step < sp->t_open)
562 0
                        WRONG("Clock step detected");
563 0
                now = sp->t_open; /* Do not log negatives */
564
        }
565
566 1458
        if (reason == SC_NULL)
567 229
                reason = (enum sess_close)-sp->fd;
568
569 1458
        VSL(SLT_SessClose, sp->vxid, "%s %.3f",
570 1458
            sess_close_2str(reason, 0), now - sp->t_open);
571 1458
        VSL(SLT_End, sp->vxid, "%s", "");
572 1458
        SES_Rel(sp);
573 1458
}
574
575
/*--------------------------------------------------------------------
576
 */
577
578
void
579 1894
SES_Ref(struct sess *sp)
580
{
581
582 1894
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
583 1894
        Lck_Lock(&sp->mtx);
584 1894
        assert(sp->refcnt > 0);
585 1894
        sp->refcnt++;
586 1894
        Lck_Unlock(&sp->mtx);
587 1894
}
588
589
void
590 3351
SES_Rel(struct sess *sp)
591
{
592
        int i;
593
        struct pool *pp;
594
595 3351
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
596 3351
        pp = sp->pool;
597 3351
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
598
599 3351
        Lck_Lock(&sp->mtx);
600 3351
        assert(sp->refcnt > 0);
601 3351
        i = --sp->refcnt;
602 3351
        Lck_Unlock(&sp->mtx);
603 3351
        if (i)
604 1893
                return;
605 1458
        Lck_Delete(&sp->mtx);
606 1457
        MPL_Free(sp->pool->mpl_sess, sp);
607
}
608
609
/*--------------------------------------------------------------------
610
 * Create and delete pools
611
 */
612
613
void
614 1362
SES_NewPool(struct pool *pp, unsigned pool_no)
615
{
616
        char nb[8];
617
618 1362
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
619 1362
        bprintf(nb, "req%u", pool_no);
620 1362
        pp->mpl_req = MPL_New(nb, &cache_param->req_pool,
621 1362
            &cache_param->workspace_client);
622 1362
        bprintf(nb, "sess%u", pool_no);
623 1362
        pp->mpl_sess = MPL_New(nb, &cache_param->sess_pool,
624 1362
            &cache_param->workspace_session);
625
626 1362
        pp->waiter = Waiter_New();
627 1362
}
628
629
void
630 2
SES_DestroyPool(struct pool *pp)
631
{
632 2
        MPL_Destroy(&pp->mpl_req);
633 2
        MPL_Destroy(&pp->mpl_sess);
634 2
        Waiter_Destroy(&pp->waiter);
635 2
}