From 8694164f1ede27017dd7252d26be2246d88c3a14 Mon Sep 17 00:00:00 2001 From: phk Date: Tue, 11 Jul 2006 15:18:54 +0000 Subject: [PATCH] This commit breaks warnish temporarily: 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 | 372 +++++++++++++++++++--- 1 file changed, 334 insertions(+), 38 deletions(-) diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index fdf95648..f1aa6af7 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -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 @@ -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 } +*/ -- 2.39.5