]> err.no Git - varnish/commitdiff
This commit breaks warnish temporarily:
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 11 Jul 2006 15:18:54 +0000 (15:18 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Tue, 11 Jul 2006 15:18:54 +0000 (15:18 +0000)
Insert the new master state engine.

A dot(1) graph is embedded in the source code and can be extracted
with:

sed -n '/^DOT/s///p' cache_center.c | dot -Tps > /tmp/_.ps

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@428 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/cache_center.c

index fdf95648f69ca42fae32d344b636e4619807325a..f1aa6af774fcf4dfafae033a463d52e70c26a162 100644 (file)
@@ -1,6 +1,31 @@
 /*
  * $Id$
  *
+ * This file contains the central state machine for pushing requests.
+ *
+ * We cannot just use direct calls because it is possible to kick a
+ * request back to the lookup stage (usually after a rewrite).  The
+ * state engine also allows us to break the processing up into some
+ * logical chunks which improves readability a little bit.
+ *
+ * Since the states are rather nasty in detail, I have decided to embedd
+ * a dot(1) graph in the source code comments.  So to see the big picture,
+ * extract the DOT lines and run though dot(1), for instance with the
+ * command:
+ *     sed -n '/^DOT/s///p' cache_center.c | dot -Tps > /tmp/_.ps
+ *
+ */
+
+/*
+DOT digraph vcl_center {
+DOT    page="8.2,11.7"
+DOT    size="6.3,9.7"
+DOT    margin="1.0"
+DOT start [
+DOT    shape=hexagon
+DOT    label="Start"
+DOT ]
+DOT start -> RECV
  */
 
 #include <stdio.h>
@@ -47,62 +72,333 @@ DeliverSession(struct worker *w, struct sess *sp)
        return (1);
 }
 
-void
-CNT_Session(struct worker *w, struct sess *sp)
+/*--------------------------------------------------------------------
+DOT subgraph cluster_deliver {
+DOT    deliver [
+DOT            shape=ellipse
+DOT            label="Build & send header"
+DOT    ]
+DOT    DELIVER -> deliver [style=bold]
+DOT    deliver2 [
+DOT            shape=ellipse
+DOT            label="Send object"
+DOT    ]
+DOT    deliver -> deliver2 [style=bold]
+DOT }
+DOT deliver2 -> DONE [style=bold]
+ */
+
+static void cnt_deliver(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT    DONE [
+DOT            shape=hexagon
+DOT            label="Request completed"
+DOT    ]
+ */
+
+#if 0
+       if (http_GetHdr(sp->http, "Connection", &b) &&
+           !strcmp(b, "close")) {
+               vca_close_session(sp, "Connection header");
+       } else if (http_GetProto(sp->http, &b) &&
+           strcmp(b, "HTTP/1.1")) {
+               vca_close_session(sp, "not HTTP/1.1");
+#endif
+
+static void cnt_done(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_error {
+DOT    error [
+DOT            shape=ellipse
+DOT            label="Issue HTTP error"
+DOT    ]
+DOT    ERROR -> error
+DOT }
+DOT error -> DONE
+ */
+
+static void cnt_error(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_fetch {
+DOT    fetch [
+DOT            shape=ellipse
+DOT            label="find obj.ttl\nobj.cacheable"
+DOT    ]
+DOT    FETCH -> fetch [style=bold]
+DOT    vcl_fetch [
+DOT            shape=box
+DOT            label="vcl_fetch()"
+DOT    ]
+DOT    fetch -> vcl_fetch [style=bold]
+DOT    fetch_lookup [
+DOT            shape=ellipse
+DOT            label="obj.cacheable=false\nunbusy obj\ndiscard body\n"
+DOT    ]
+DOT    vcl_fetch -> fetch_lookup [label="lookup", style=dotted, weight=0]
+DOT    fetch_pass [
+DOT            shape=ellipse
+DOT            label="obj.cacheable=false\nunbusy obj"
+DOT    ]
+DOT    vcl_fetch -> fetch_pass [label="pass"]
+DOT    fetch_ipass [
+DOT            shape=ellipse
+DOT            label="obj.cacheable=true\nobj.pass=true\nunbusy obj"
+DOT    ]
+DOT    vcl_fetch -> fetch_ipass [label="insert_pass"]
+DOT    fetch_insert [
+DOT            shape=ellipse
+DOT            label="rcv body\nobj.cacheable=true\nunbusy"
+DOT    ]
+DOT    vcl_fetch -> fetch_insert [label="insert", style=bold]
+DOT    fetch_error [
+DOT            shape=ellipse
+DOT            label="disc body\nobj.cacheable=false\nunbusy"
+DOT    ]
+DOT    vcl_fetch -> fetch_error [label="error"]
+DOT }
+DOT fetch_lookup -> LOOKUP [style=dotted, weight=0]
+DOT fetch_pass -> PASSBODY 
+DOT fetch_ipass -> PASSBODY 
+DOT fetch_insert -> DELIVER [style=bold]
+DOT fetch_error -> ERROR
+ */
+
+static void cnt_fetch(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_hit {
+DOT    hit [
+DOT            shape=box
+DOT            label="vcl_hit()"
+DOT    ]
+DOT    HIT -> hit [style=bold]
+DOT    hit2 [
+DOT            shape=diamond
+DOT            label="obj.pass ?"
+DOT    ]
+DOT    hit -> hit2 [label=deliver, style=bold]
+DOT    hit_lookup [
+DOT            shape=ellipse
+DOT            label="unbusy"
+DOT    ]
+DOT    hit -> hit_lookup [label="lookup", style=dotted, weight=0]
+DOT    hit_error [
+DOT            shape=ellipse
+DOT            label="unbusy"
+DOT    ]
+DOT    hit -> hit_error [label="error", weight=0]
+DOT    hit_pass [
+DOT            shape=ellipse
+DOT            label="unbusy"
+DOT    ]
+DOT    hit -> hit_pass [label=pass]
+DOT    hit2 -> hit_pass
+DOT }
+DOT hit_error -> ERROR
+DOT hit_pass -> PASS
+DOT hit_lookup -> LOOKUP [style=dotted, weight=0]
+DOT hit2 -> DELIVER [style=bold]
+ */
+
+static void cnt_hit(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_lookup {
+DOT    lookup [
+DOT            shape=ellipse
+DOT            label="find obj in cache"
+DOT    ]
+DOT    LOOKUP -> lookup [style=bold]
+DOT    lookup2 [
+DOT            shape=ellipse
+DOT            label="Insert new busy object"
+DOT    ]
+DOT    lookup -> lookup2 [style=bold]
+DOT }
+DOT lookup -> HIT [label="hit", style=bold]
+DOT lookup2 -> MISS [label="miss", style=bold]
+ */
+
+static void cnt_lookup(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_miss {
+DOT    miss [
+DOT            shape=box
+DOT            label="vcl_miss()"
+DOT    ]
+DOT    MISS -> miss [style=bold]
+DOT    miss_error [
+DOT            shape=ellipse
+DOT            label="obj.cacheable=false\nunbusy"
+DOT    ]
+DOT    miss -> miss_error [label="error"]
+DOT    miss_pass [
+DOT            shape=ellipse
+DOT            label="obj.cacheable=false\nunbusy"
+DOT    ]
+DOT    miss -> miss_pass [label="pass"]
+DOT    miss_lookup [
+DOT            shape=ellipse
+DOT            label="obj.cacheable=false\nunbusy"
+DOT    ]
+DOT    miss -> miss_lookup [label="lookup", style=dotted, weight=0]
+DOT    miss_fetch [
+DOT            shape=ellipse
+DOT            label="fetch obj headers\nfrom backend"
+DOT    ]
+DOT    miss -> miss_fetch [label="fetch", style=bold]
+DOT }
+DOT miss_error -> ERROR
+DOT miss_pass -> PASS
+DOT miss_fetch -> FETCH [style=bold]
+DOT miss_lookup -> LOOKUP [style=dotted, weight=0]
+DOT
+ */
+
+static void cnt_miss(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_pass {
+DOT    pass [
+DOT            shape=ellipse
+DOT            label="send to bke\nrx bkehdr"
+DOT    ]
+DOT    PASS -> pass
+DOT }
+DOT pass -> PASSBODY
+ */
+
+static void cnt_pass(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_passbody {
+DOT    passbody [
+DOT            shape=ellipse
+DOT            label="send hdrs\npass body\n"
+DOT    ]
+DOT    PASSBODY -> passbody
+DOT }
+DOT passbody -> DONE
+ */
+
+static void cnt_passbody(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_pipe {
+DOT    pipe [
+DOT            shape=ellipse
+DOT            label="build&send hdr\npipe until close"
+DOT    ]
+DOT    PIPE -> pipe
+DOT }
+DOT pipe -> DONE
+ */
+
+static void cnt_pipe(struct worker *w, struct sess *sp) { (void)w; (void)sp; INCOMPL(); }
+
+/*--------------------------------------------------------------------
+DOT subgraph cluster_recv {
+DOT    recv [
+DOT            shape=box
+DOT            label="vcl_recv()"
+DOT    ]
+DOT    RECV -> recv
+DOT    recv_lookup [
+DOT            shape=ellipse
+DOT            label="discard any body"
+DOT    ]
+DOT    recv -> recv_lookup [label="lookup"]
+DOT    recv_error [
+DOT            shape=ellipse
+DOT            label="discard any body"
+DOT    ]
+DOT    recv -> recv_error [label="error"]
+DOT }
+DOT recv -> PIPE [label="pipe"]
+DOT recv -> PASS [label="pass"]
+DOT recv_lookup -> LOOKUP
+DOT recv_error -> ERROR
+ */
+
+static void
+cnt_recv(struct worker *w, struct sess *sp)
 {
        int done;
-       char *b;
-
-       time(&sp->t0);
-       AZ(pthread_mutex_lock(&sessmtx));
-       sp->vcl = GetVCL();
-       AZ(pthread_mutex_unlock(&sessmtx));
 
        done = http_DissectRequest(sp->http, sp->fd);
        if (done != 0) {
                RES_Error(w, sp, done, NULL);
-               goto out;
+               sp->step = STP_DONE;
+               return;
        }
 
        sp->backend = sp->vcl->backend[0];
 
+       /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
+
+       /* XXX: determine if request comes with body */
+
        VCL_recv_method(sp);
 
-       for (done = 0; !done; ) {
-               switch(sp->handling) {
-               case VCL_RET_LOOKUP:
-                       done = LookupSession(w, sp);
-                       break;
-               case VCL_RET_FETCH:
-                       done = FetchSession(w, sp);
-                       break;
-               case VCL_RET_DELIVER:
-                       done = DeliverSession(w, sp);
-                       break;
-               case VCL_RET_PIPE:
-                       PipeSession(w, sp);
-                       done = 1;
-                       break;
-               case VCL_RET_PASS:
-                       PassSession(w, sp);
-                       done = 1;
-                       break;
-               default:
-                       INCOMPL();
-               }
+       switch(sp->handling) {
+       case VCL_RET_LOOKUP:
+               /* XXX: discard req body, if any */
+               sp->step = STP_LOOKUP;
+               return;
+       case VCL_RET_PIPE:
+               sp->step = STP_PIPE;
+               return;
+       case VCL_RET_PASS:
+               sp->step = STP_PASS;
+               return;
+       case VCL_RET_ERROR:
+               /* XXX: discard req body, if any */
+               sp->step = STP_ERROR;
+               return;
+       default:
+               INCOMPL();
        }
-       if (http_GetHdr(sp->http, "Connection", &b) &&
-           !strcmp(b, "close")) {
-               vca_close_session(sp, "Connection header");
-       } else if (http_GetProto(sp->http, &b) &&
-           strcmp(b, "HTTP/1.1")) {
-               vca_close_session(sp, "not HTTP/1.1");
+}
+
+
+/*--------------------------------------------------------------------
+ * Central state engine dispatcher.
+ * 
+ * We grab a VCL reference, and keeps kicking the session around until
+ * it has had enough.
+ *
+ */
+
+void
+CNT_Session(struct worker *w, struct sess *sp)
+{
+
+       time(&sp->t0);
+       AZ(pthread_mutex_lock(&sessmtx));
+       sp->vcl = GetVCL();
+       AZ(pthread_mutex_unlock(&sessmtx));
+
+       for (sp->step = STP_RECV; sp->step != STP_DONE; ) {
+               switch (sp->step) {
+#define STEP(l,u) case STP_##u: cnt_##l(w, sp); break;
+#include "steps.h"
+#undef STEP
+               default:        INCOMPL();
+               }
        }
 
-out:
        AZ(pthread_mutex_lock(&sessmtx));
        RelVCL(sp->vcl);
        AZ(pthread_mutex_unlock(&sessmtx));
        sp->vcl = NULL;
+
        vca_return_session(sp);
 }
+
+/*
+DOT }
+*/