source: bin/varnishd/cache_center.c @ 9d2bb6

Revision 9d2bb6, 21.0 KB checked in by Poul-Henning Kamp <phk@…>, 6 years ago (diff)

Keep track of how often we flush the private shm buffer due to overflows.

git-svn-id:  http://www.varnish-cache.org/svn/trunk@2557 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2008 Linpro 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 * $Id$
30 *
31 * This file contains the central state machine for pushing requests.
32 *
33 * We cannot just use direct calls because it is possible to kick a
34 * request back to the lookup stage (usually after a rewrite).  The
35 * state engine also allows us to break the processing up into some
36 * logical chunks which improves readability a little bit.
37 *
38 * Since the states are rather nasty in detail, I have decided to embedd
39 * a dot(1) graph in the source code comments.  So to see the big picture,
40 * extract the DOT lines and run though dot(1), for instance with the
41 * command:
42 *      sed -n '/^DOT/s///p' cache_center.c | dot -Tps > /tmp/_.ps
43 */
44
45/*
46DOT digraph vcl_center {
47xDOT    page="8.2,11.5"
48DOT     size="7.2,10.5"
49DOT     margin="0.5"
50DOT     center="1"
51DOT acceptor [
52DOT     shape=hexagon
53DOT     label="Request received"
54DOT ]
55DOT ERROR [shape=plaintext]
56DOT acceptor -> start [style=bold,color=green,weight=4]
57 */
58
59#include "config.h"
60
61#include <stdio.h>
62#include <errno.h>
63#include <math.h>
64#include <stdlib.h>
65#include <string.h>
66#include <unistd.h>
67
68#ifndef HAVE_SRANDOMDEV
69#include "compat/srandomdev.h"
70#endif
71
72#include "shmlog.h"
73#include "vcl.h"
74#include "cache.h"
75
76static unsigned xids;
77
78/*--------------------------------------------------------------------
79 * AGAIN
80 * We come here when we just completed a request and already have
81 * received (part of) the next one.  Instead taking the detour
82 * around the acceptor and then back to a worker, just stay in this
83 * worker and do what it takes.
84 */
85
86static int
87cnt_again(struct sess *sp)
88{
89        int i;
90
91        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
92        AZ(sp->vcl);
93        AZ(sp->obj);
94        assert(sp->xid == 0);
95
96        i = HTC_Complete(sp->htc);
97        while (i == 0)
98                i = HTC_Rx(sp->htc);
99        if (i == 1) {
100                sp->step = STP_START;
101        } else {
102                vca_close_session(sp, "overflow");
103                sp->step = STP_DONE;
104        }
105        return (0);
106}
107
108
109/*--------------------------------------------------------------------
110 * We have a refcounted object on the session, now deliver it.
111 *
112DOT subgraph xcluster_deliver {
113DOT     deliver [
114DOT             shape=ellipse
115DOT             label="Filter obj.->resp."
116DOT     ]
117DOT     vcl_deliver [
118DOT             shape=record
119DOT             label="vcl_deliver()|resp."
120DOT     ]
121DOT     deliver2 [
122DOT             shape=ellipse
123DOT             label="Send hdr + object"
124DOT     ]
125DOT     deliver -> vcl_deliver [style=bold,color=green,weight=4]
126DOT     vcl_deliver -> deliver2 [style=bold,color=green,weight=4,label=deliver]
127DOT     vcl_deliver -> errdeliver [label="error"]
128DOT     errdeliver [label="ERROR",shape=plaintext]
129DOT }
130DOT deliver2 -> DONE [style=bold,color=green,weight=4]
131 *
132 * XXX: Ideally we should make the req. available in vcl_deliver() but for
133 * XXX: reasons of economy we don't, since that allows us to reuse the space
134 * XXX: in sp->req for the response.
135 *
136 * XXX: Rather than allocate two http's and workspaces for all sessions to
137 * XXX: address this deficiency, we could make the VCL compiler set a flag
138 * XXX: if req. is used in vcl_deliver().  When the flag is set we would
139 * XXX: take the memory overhead, for instance by borrowing a struct bereq
140 * XXX: or similar.
141 *
142 * XXX: For now, wait until somebody asks for it.
143 */
144
145static int
146cnt_deliver(struct sess *sp)
147{
148
149        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
150        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
151        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
152
153        sp->t_resp = TIM_real();
154        if (sp->obj->objhead != NULL) {
155                sp->obj->last_use = sp->t_resp; /* XXX: locking ? */
156                EXP_Touch(sp->obj, sp->t_resp);
157        }
158        RES_BuildHttp(sp);
159        VCL_deliver_method(sp);
160        switch (sp->handling) {
161        case VCL_RET_DELIVER:
162                break;
163        case VCL_RET_ERROR:
164                HSH_Deref(sp->obj);
165                sp->obj = NULL;
166                sp->step = STP_ERROR;
167                return (0);
168        default:
169                INCOMPL();
170        }
171
172        RES_WriteObj(sp);
173        HSH_Deref(sp->obj);
174        sp->obj = NULL;
175        sp->step = STP_DONE;
176        return (0);
177}
178
179
180/*--------------------------------------------------------------------
181 * This is the final state, figure out if we should close or recycle
182 * the client connection
183 *
184DOT     DONE [
185DOT             shape=hexagon
186DOT             label="Request completed"
187DOT     ]
188 */
189
190static int
191cnt_done(struct sess *sp)
192{
193        double dh, dp, da;
194        int i;
195
196        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
197        CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC);
198
199        AZ(sp->obj);
200        AZ(sp->bereq);
201        sp->director = NULL;
202        sp->backend = NULL;             /*
203                                         * XXX: we may want to leave this
204                                         * behind to hint directors ?
205                                         */
206                                       
207        if (sp->vcl != NULL) {
208                if (sp->wrk->vcl != NULL)
209                        VCL_Rel(&sp->wrk->vcl);
210                sp->wrk->vcl = sp->vcl;
211                sp->vcl = NULL;
212        }
213
214        sp->t_end = TIM_real();
215        sp->wrk->used = sp->t_end;
216        if (sp->xid == 0) {
217                sp->t_req = sp->t_end;
218                sp->t_resp = sp->t_end;
219        }
220        dp = sp->t_resp - sp->t_req;
221        da = sp->t_end - sp->t_resp;
222        dh = sp->t_req - sp->t_open;
223        WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f",
224            sp->xid, sp->t_req, sp->t_end, dh, dp, da);
225
226        sp->xid = 0;
227        SES_Charge(sp);
228        sp->t_open = sp->t_end;
229        sp->t_req = NAN;
230        sp->t_resp = NAN;
231        WSL_Flush(sp->wrk, 0);
232
233        /* If we did an ESI include, don't mess up our state */
234        if (sp->esis > 0)
235                return (1);
236
237        if (sp->fd >= 0 && sp->doclose != NULL)
238                vca_close_session(sp, sp->doclose);
239        if (sp->fd < 0) {
240                VSL_stats->sess_closed++;
241                assert(!isnan(sp->wrk->used));
242                sp->wrk = NULL;
243                SES_Delete(sp);
244                return (1);
245        }
246
247        /* Reset the workspace to the session-watermark */
248        WS_Reset(sp->ws, sp->ws_ses);
249
250        i = HTC_Reinit(sp->htc);
251        if (i == 1) {
252                VSL_stats->sess_pipeline++;
253                sp->step = STP_START;
254                return (0);
255        }
256        if (Tlen(sp->htc->rxbuf)) {
257                VSL_stats->sess_readahead++;
258                sp->step = STP_AGAIN;
259                return (0);
260        }
261        VSL_stats->sess_herd++;
262        assert(!isnan(sp->wrk->used));
263        sp->wrk = NULL;
264        vca_return_session(sp);
265        return (1);
266}
267
268
269/*--------------------------------------------------------------------
270 * Emit an error
271 *
272DOT subgraph xcluster_error {
273DOT     error [
274DOT             shape=ellipse
275DOT             label="Issue HTTP error"
276DOT     ]
277DOT     ERROR -> error
278DOT }
279DOT error -> DONE
280 */
281
282static int
283cnt_error(struct sess *sp)
284{
285
286        AZ(sp->obj);
287        SYN_ErrorPage(sp, sp->err_code, sp->err_reason);
288        sp->err_code = 0;
289        sp->err_reason = NULL;
290        sp->step = STP_DONE;
291        return (0);
292}
293
294
295/*--------------------------------------------------------------------
296 * We have fetched the headers from the backend, ask the VCL code what
297 * to do next, then head off in that direction.
298 *
299DOT subgraph xcluster_fetch {
300DOT     fetch [
301DOT             shape=ellipse
302DOT             label="fetch from backend\n(find obj.ttl)"
303DOT     ]
304DOT     vcl_fetch [
305DOT             shape=record
306DOT             label="vcl_fetch()|req.\nobj.\nbereq."
307DOT     ]
308DOT     fetch -> vcl_fetch [style=bold,color=blue,weight=2]
309DOT     fetch_pass [
310DOT             shape=ellipse
311DOT             label="obj.pass=true"
312DOT     ]
313DOT     vcl_fetch -> fetch_pass [label="pass"]
314DOT }
315DOT fetch_pass -> deliver
316DOT vcl_fetch -> deliver [label="insert",style=bold,color=blue,weight=2]
317DOT vcl_fetch -> recv [label="restart"]
318DOT vcl_fetch -> errfetch [label="error"]
319DOT errfetch [label="ERROR",shape=plaintext]
320 */
321
322static int
323cnt_fetch(struct sess *sp)
324{
325        int i;
326
327        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
328        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
329
330        AN(sp->bereq);
331        CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
332        i = Fetch(sp);
333        CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
334
335        if (!i)
336                RFC2616_cache_policy(sp, sp->obj->http);        /* XXX -> VCL */
337        else {
338                http_PutStatus(sp->wrk, sp->fd, sp->obj->http, 503);
339                http_PutProtocol(sp->wrk, sp->fd, sp->obj->http, "HTTP/1.1");
340                http_PutResponse(sp->wrk, sp->fd, sp->obj->http,
341                    "Backend error");
342        }
343
344        sp->err_code = http_GetStatus(sp->obj->http);
345        VCL_fetch_method(sp);
346
347        VBE_free_bereq(sp->bereq);
348        sp->bereq = NULL;
349
350        switch (sp->handling) {
351        case VCL_RET_ERROR:
352        case VCL_RET_RESTART:
353                sp->obj->ttl = 0;
354                sp->obj->cacheable = 0;
355                HSH_Unbusy(sp->obj);
356                HSH_Deref(sp->obj);
357                sp->obj = NULL;
358                if (sp->handling == VCL_RET_ERROR)
359                        sp->step = STP_ERROR;
360                else {
361                        sp->restarts++;
362                        sp->step = STP_RECV;
363                }
364                return (0);
365        case VCL_RET_PASS:
366                sp->obj->pass = 1;
367                break;
368        case VCL_RET_INSERT:
369                break;
370        default:
371                INCOMPL();
372        }
373
374        sp->obj->cacheable = 1;
375        if (sp->obj->objhead != NULL) {
376                VRY_Create(sp);
377                EXP_Insert(sp->obj, sp->wrk->used);
378                HSH_Unbusy(sp->obj);
379        }
380        sp->wrk->acct.fetch++;
381        sp->step = STP_DELIVER;
382        return (0);
383}
384
385/*--------------------------------------------------------------------
386 * The very first request
387 */
388static int
389cnt_first(struct sess *sp)
390{
391        int i;
392
393        /*
394         * XXX: If we don't have acceptfilters we are somewhat subject
395         * XXX: to DoS'ing here.  One remedy would be to set a shorter
396         * XXX: SO_RCVTIMEO and once we have received something here
397         * XXX: increase it to the normal value.
398         */
399
400        assert(sp->xid == 0);
401        VCA_Prep(sp);
402
403        /* Record the session watermark */
404        sp->ws_ses = WS_Snapshot(sp->ws);
405
406        /* Receive a HTTP protocol request */
407        HTC_Init(sp->htc, sp->ws, sp->fd);
408        sp->wrk->used = sp->t_open;
409        sp->wrk->acct.sess++;
410        SES_RefSrcAddr(sp);
411        do
412                i = HTC_Rx(sp->htc);
413        while (i == 0);
414
415        switch (i) {
416        case 1:
417                sp->step = STP_START;
418                break;
419        case -1:
420                vca_close_session(sp, "error");
421                sp->step = STP_DONE;
422                break;
423        case -2:
424                vca_close_session(sp, "blast");
425                sp->step = STP_DONE;
426                break;
427        default:
428                INCOMPL();
429        }
430        return (0);
431}
432
433/*--------------------------------------------------------------------
434 * HIT
435 * We had a cache hit.  Ask VCL, then march off as instructed.
436 *
437DOT subgraph xcluster_hit {
438DOT     hit [
439DOT             shape=record
440DOT             label="vcl_hit()|req.\nobj."
441DOT     ]
442DOT }
443DOT hit -> err_hit [label="error"]
444DOT err_hit [label="ERROR",shape=plaintext]
445DOT hit -> pass [label=pass]
446DOT hit -> deliver [label="deliver",style=bold,color=green,weight=4]
447 */
448
449static int
450cnt_hit(struct sess *sp)
451{
452
453        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
454        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
455        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
456
457        assert(!sp->obj->pass);
458
459        VCL_hit_method(sp);
460
461        if (sp->handling == VCL_RET_DELIVER) {
462                /* Dispose of any body part of the request */
463                FetchReqBody(sp);
464                sp->step = STP_DELIVER;
465                return (0);
466        }
467
468        /* Drop our object, we won't need it */
469        HSH_Deref(sp->obj);
470        sp->obj = NULL;
471
472        if (sp->handling == VCL_RET_PASS) {
473                sp->step = STP_PASS;
474                return (0);
475        }
476
477        if (sp->handling == VCL_RET_ERROR) {
478                sp->step = STP_ERROR;
479                return (0);
480        }
481
482
483        INCOMPL();
484}
485
486
487/*--------------------------------------------------------------------
488 * LOOKUP
489 * Hash things together and look object up in hash-table.
490 *
491 * LOOKUP consists of two substates so that we can reenter if we
492 * encounter a busy object.
493 *
494DOT subgraph xcluster_lookup {
495DOT     hash [
496DOT             shape=record
497DOT             label="vcl_hash()|req."
498DOT     ]
499DOT     lookup [
500DOT             shape=diamond
501DOT             label="obj in cache ?\ncreate if not"
502DOT     ]
503DOT     lookup2 [
504DOT             shape=diamond
505DOT             label="obj.pass ?"
506DOT     ]
507DOT     hash -> lookup [label="hash",style=bold,color=green,weight=4]
508DOT     lookup -> lookup2 [label="yes",style=bold,color=green,weight=4]
509DOT }
510DOT lookup2 -> hit [label="no", style=bold,color=green,weight=4]
511DOT lookup2 -> pass [label="yes"]
512DOT lookup -> miss [label="no",style=bold,color=blue,weight=2]
513 */
514
515static int
516cnt_lookup(struct sess *sp)
517{
518        struct object *o;
519        char *p;
520        uintptr_t u;
521
522        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
523        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
524
525        if (sp->obj == NULL) {
526
527                /* Allocate the pointers we need, align properly. */
528                sp->lhashptr = 1;       /* space for NUL */
529                sp->ihashptr = 0;
530                sp->nhashptr = sp->vcl->nhashcount * 2;
531                p = WS_Alloc(sp->http->ws,
532                    sizeof(const char *) * (sp->nhashptr + 1));
533                XXXAN(p);
534                /* Align pointer properly (?) */
535                u = (uintptr_t)p;
536                u &= sizeof(const char *) - 1;
537                if (u)
538                        p += sizeof(const char *) - u;
539                sp->hashptr = (void*)p;
540
541                VCL_hash_method(sp);
542                /* XXX check error */
543        }
544
545        o = HSH_Lookup(sp);
546
547        if (o == NULL) {
548                /*
549                 * We hit a busy object, disembark worker thread and expect
550                 * hash code to restart us, still in STP_LOOKUP, later.
551                 */
552                spassert(sp->objhead != NULL);
553                if (params->diag_bitmap & 0x20)
554                        WSP(sp, SLT_Debug,
555                            "on waiting list <%s>", sp->objhead->hash);
556                /*
557                 * There is a non-zero risk that we come here more than once
558                 * before we get through, in that case cnt_recv must be set
559                 */
560                if (isnan(sp->wrk->used))
561                        sp->wrk->used = TIM_real();
562                SES_Charge(sp);
563                return (1);
564        }
565
566        sp->obj = o;
567
568        /* If we inserted a new object it's a miss */
569        if (sp->obj->busy) {
570                VSL_stats->cache_miss++;
571                sp->step = STP_MISS;
572                return (0);
573        }
574
575        if (sp->obj->pass) {
576                VSL_stats->cache_hitpass++;
577                WSP(sp, SLT_HitPass, "%u", sp->obj->xid);
578                HSH_Deref(sp->obj);
579                sp->obj = NULL;
580                sp->step = STP_PASS;
581                return (0);
582        }
583
584        VSL_stats->cache_hit++;
585        WSP(sp, SLT_Hit, "%u", sp->obj->xid);
586        sp->step = STP_HIT;
587        return (0);
588}
589
590
591/*--------------------------------------------------------------------
592 * We had a miss, ask VCL, proceed as instructed
593 *
594DOT subgraph xcluster_miss {
595DOT     miss [
596DOT             shape=ellipse
597DOT             label="filter req.->bereq."
598DOT     ]
599DOT     vcl_miss [
600DOT             shape=record
601DOT             label="vcl_miss()|req.\nbereq."
602DOT     ]
603DOT     miss_ins [
604DOT             label="obj.pass=true"
605DOT     ]
606DOT     miss -> vcl_miss [style=bold,color=blue,weight=2]
607DOT }
608DOT vcl_miss -> err_miss [label="error"]
609DOT err_miss [label="ERROR",shape=plaintext]
610DOT vcl_miss -> fetch [label="fetch",style=bold,color=blue,weight=2]
611DOT miss_ins -> pass
612DOT vcl_miss -> miss_ins [label="pass"]
613DOT
614 */
615
616static int
617cnt_miss(struct sess *sp)
618{
619
620        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
621        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
622        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
623
624        VBE_SelectBackend(sp);
625        http_FilterHeader(sp, HTTPH_R_FETCH);
626        VCL_miss_method(sp);
627        if (sp->handling == VCL_RET_ERROR) {
628                sp->obj->cacheable = 0;
629                HSH_Unbusy(sp->obj);
630                HSH_Deref(sp->obj);
631                sp->obj = NULL;
632                VBE_free_bereq(sp->bereq);
633                sp->bereq = NULL;
634                sp->step = STP_ERROR;
635                return (0);
636        }
637        if (sp->handling == VCL_RET_PASS) {
638                sp->obj->cacheable = 0;
639                HSH_Unbusy(sp->obj);
640                HSH_Deref(sp->obj);
641                sp->obj = NULL;
642                sp->step = STP_PASS;
643                VBE_free_bereq(sp->bereq);
644                sp->bereq = NULL;
645                return (0);
646        }
647        if (sp->handling == VCL_RET_FETCH) {
648                sp->step = STP_FETCH;
649                return (0);
650        }
651        INCOMPL();
652}
653
654
655/*--------------------------------------------------------------------
656 * Start pass processing by getting headers from backend, then
657 * continue in passbody.
658 *
659DOT subgraph xcluster_pass {
660DOT     pass [
661DOT             shape=ellipse
662DOT             label="deref obj\nfilter req.->bereq."
663DOT     ]
664DOT     vcl_pass [
665DOT             shape=record
666DOT             label="vcl_pass()|req.\nbereq."
667DOT     ]
668DOT     pass_do [
669DOT             shape=ellipse
670DOT             label="create anon object\n"
671DOT     ]
672DOT     pass -> vcl_pass
673DOT     vcl_pass -> pass_do [label="pass"]
674DOT }
675DOT pass_do -> fetch
676DOT vcl_pass -> err_pass [label="error"]
677DOT err_pass [label="ERROR",shape=plaintext]
678 */
679
680static int
681cnt_pass(struct sess *sp)
682{
683
684        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
685        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
686        AZ(sp->obj);
687
688        VBE_SelectBackend(sp);
689        http_FilterHeader(sp, HTTPH_R_PASS);
690
691        VCL_pass_method(sp);
692        if (sp->handling == VCL_RET_ERROR) {
693                sp->step = STP_ERROR;
694                return (0);
695        }
696        HSH_Prealloc(sp);
697        sp->obj = sp->wrk->nobj;
698        sp->wrk->nobj = NULL;
699        sp->obj->busy = 1;
700        sp->sendbody = 1;
701        sp->step = STP_FETCH;
702        return (0);
703}
704
705/*--------------------------------------------------------------------
706 * Ship the request header to the backend unchanged, then pipe
707 * until one of the ends close the connection.
708 *
709DOT subgraph xcluster_pipe {
710DOT     pipe [
711DOT             shape=ellipse
712DOT             label="Filter req.->bereq."
713DOT     ]
714DOT     vcl_pipe [
715DOT             shape=record
716DOT             label="vcl_pipe()|req.\nbereq\."
717DOT     ]
718DOT     pipe_do [
719DOT             shape=ellipse
720DOT             label="send bereq.\npipe until close"
721DOT     ]
722DOT     vcl_pipe -> pipe_do [label="pipe"]
723DOT     pipe -> vcl_pipe
724DOT }
725DOT pipe_do -> DONE
726DOT vcl_pipe -> err_pipe [label="error"]
727DOT err_pipe [label="ERROR",shape=plaintext]
728 */
729
730static int
731cnt_pipe(struct sess *sp)
732{
733
734        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
735        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
736
737        sp->wrk->acct.pipe++;
738        VBE_SelectBackend(sp);
739        http_FilterHeader(sp, HTTPH_R_PIPE);
740
741        VCL_pipe_method(sp);
742
743        if (sp->handling == VCL_RET_ERROR)
744                INCOMPL();
745
746        PipeSession(sp);
747        sp->step = STP_DONE;
748        return (0);
749}
750
751
752/*--------------------------------------------------------------------
753 * RECV
754 * We have a complete request, set everything up and start it.
755 *
756DOT subgraph xcluster_recv {
757DOT     recv [
758DOT             shape=record
759DOT             label="vcl_recv()|req."
760DOT     ]
761DOT }
762DOT recv -> pipe [label="pipe"]
763DOT recv -> pass [label="pass"]
764DOT recv -> err_recv [label="error"]
765DOT err_recv [label="ERROR",shape=plaintext]
766DOT recv -> hash [label="lookup",style=bold,color=green,weight=4]
767 */
768
769static int
770cnt_recv(struct sess *sp)
771{
772
773        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
774        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
775        AZ(sp->obj);
776
777        VCL_recv_method(sp);
778
779        sp->wantbody = (strcmp(sp->http->hd[HTTP_HDR_REQ].b, "HEAD") != 0);
780        sp->sendbody = 0;
781        switch(sp->handling) {
782        case VCL_RET_LOOKUP:
783                /* XXX: discard req body, if any */
784                sp->step = STP_LOOKUP;
785                return (0);
786        case VCL_RET_PIPE:
787                if (sp->esis > 0) {
788                        /* XXX: VSL something */
789                        INCOMPL();
790                        sp->step = STP_DONE;
791                        return (1);
792                }
793                sp->step = STP_PIPE;
794                return (0);
795        case VCL_RET_PASS:
796                sp->step = STP_PASS;
797                return (0);
798        case VCL_RET_ERROR:
799                /* XXX: discard req body, if any */
800                sp->step = STP_ERROR;
801                return (0);
802        default:
803                INCOMPL();
804        }
805}
806
807/*--------------------------------------------------------------------
808 * START
809 * Handle a request, wherever it came from recv/restart.
810 *
811DOT start [shape=box,label="Dissect request"]
812DOT start -> recv
813 */
814
815static int
816cnt_start(struct sess *sp)
817{
818        int done;
819
820        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
821        AZ(sp->restarts);
822        AZ(sp->obj);
823        AZ(sp->vcl);
824
825        /* Update stats of various sorts */
826        VSL_stats->client_req++;                        /* XXX not locked */
827        sp->t_req = TIM_real();
828        sp->wrk->used = sp->t_req;
829        sp->wrk->acct.req++;
830
831        /* Assign XID and log */
832        sp->xid = ++xids;                               /* XXX not locked */
833        WSP(sp, SLT_ReqStart, "%s %s %u", sp->addr, sp->port,  sp->xid);
834
835        /* Borrow VCL reference from worker thread */
836        VCL_Refresh(&sp->wrk->vcl);
837        sp->vcl = sp->wrk->vcl;
838        sp->wrk->vcl = NULL;
839
840        http_Setup(sp->http, sp->ws);
841        done = http_DissectRequest(sp);
842
843        /* Catch request snapshot */
844        sp->ws_req = WS_Snapshot(sp->ws);
845
846        /* Catch original request, before modification */
847        *sp->http0 = *sp->http;
848
849        if (done != 0) {
850                SYN_ErrorPage(sp, done, NULL);          /* XXX: STP_ERROR ? */
851                sp->step = STP_DONE;
852                return (0);
853        }
854
855        sp->doclose = http_DoConnection(sp->http);
856
857        /* By default we use the first backend */
858        AZ(sp->director);
859        sp->director = sp->vcl->director[0];
860        CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
861
862        /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
863
864        sp->step = STP_RECV;
865        return (0);
866}
867
868/*--------------------------------------------------------------------
869 * Central state engine dispatcher.
870 *
871 * Kick the session around until it has had enough.
872 *
873 */
874
875static void
876cnt_diag(struct sess *sp, const char *state)
877{
878        if (sp->wrk != NULL) {
879                WSL(sp->wrk, SLT_Debug, sp->id,
880                    "thr %p STP_%s sp %p obj %p vcl %p",
881                    pthread_self(), state, sp, sp->obj, sp->vcl);
882                WSL_Flush(sp->wrk, 0);
883        } else {
884                VSL(SLT_Debug, sp->id,
885                    "thr %p STP_%s sp %p obj %p vcl %p",
886                    pthread_self(), state, sp, sp->obj, sp->vcl);
887        }
888}
889
890void
891CNT_Session(struct sess *sp)
892{
893        int done;
894        struct worker *w;
895
896        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
897        w = sp->wrk;
898        CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
899
900        for (done = 0; !done; ) {
901                assert(sp->wrk == w);
902                /*
903                 * This is a good place to be paranoid about the various
904                 * pointers still pointing to the things we expect.
905                 */
906                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
907                CHECK_OBJ_ORNULL(sp->obj, OBJECT_MAGIC);
908                CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
909                CHECK_OBJ_ORNULL(w->nobj, OBJECT_MAGIC);
910                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
911                CHECK_OBJ_ORNULL(sp->director, DIRECTOR_MAGIC);
912
913                switch (sp->step) {
914#define STEP(l,u) \
915                    case STP_##u: \
916                        if (params->diag_bitmap & 0x01) \
917                                cnt_diag(sp, #u); \
918                        done = cnt_##l(sp); \
919                        break;
920#include "steps.h"
921#undef STEP
922                default:        INCOMPL();
923                }
924                CHECK_OBJ_ORNULL(w->nobj, OBJECT_MAGIC);
925                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
926        }
927        assert(!isnan(w->used));
928        WSL_Flush(w, 0);
929}
930
931/*
932DOT }
933*/
934
935void
936CNT_Init(void)
937{
938
939        srandomdev();
940        xids = random();
941}
Note: See TracBrowser for help on using the repository browser.