Varnish Processing States

Introduction

Varnish processing of client and backend requests is implemented as state machines. Whenever a state is entered, a C function is called, which in turn calls the appropriate Varnish core code functions to process the request or response at this stage. For most states, core code also calls into a state-specific function compiled from VCL, a VCL subroutine (see Built in subroutines ).

As a general guideline, core code aims to prepare objects accessible from VCL with good defaults for the most common cases before calling into the respective VCL subroutine. These can then be modified from VCL where necessary.

The following graphs attempt to provide an overview over the processing states, their transisions and the most relevant functions in core code. They represent a compromise between usefulness for core/VMOD developers and administrators and are intended to serve as the reference basis for deriavtive work, such as more VCL-centric views.

Client Side

/*
 * we should format labels in a readable form like
 *			 label="\
 *			 {cnt_deliver:|\
 *				 Filter obj.-\>resp.|\
 *				 {vcl_deliver\{\}|\
 *				 {req.*|resp.*}}|\
 *				 {restart|<deliver>deliver|<synth>synth}}"
 *
 * <rant>
 * ... but some servers in the v-c.o build farm use old graphviz 2.26.3
 * which cannot handle labels with additional whitespace properly, so
 * for the time being we need to fall back into dark middle ages and
 * use illegibly long lines
 * </rant>
 * -- slink 20141013
 */

digraph cache_req_fsm {
	margin="0.25"
	ranksep="0.5"
	center="1"

	//// XXX does this belong here? -- from cache_vcl.c
	/*
	vcl_load [label = "vcl.load",shape=plaintext]
	vcl_load -> init
	init [
	      shape=record
	      label="
	      {VCL_Load:|
		      {vcl_init}|
		      {<ok>ok|<fail>fail}}"
	]
	init:ok -> ok
	init:fail -> fail

	vcl_discard [label = "vcl.discard",shape=plaintext]
	vcl_discard -> fini
	fini [
	      shape=record
	      label="
	      {VCL_Nuke:|
		      {vcl_fini}|
		      {<ok>ok}}"
	]
	fini:ok -> ok
	*/

	acceptor [
		  shape=hexagon
		  label="Request received"
	]
	ESI_REQ [ shape=hexagon ]
	RESTART [shape=plaintext]

	ESI_REQ -> recv
	SYNTH [shape=plaintext]
	acceptor -> recv [style=bold]

	subgraph xcluster_deliver {
		/* cnt_deliver() */
		deliver [
			 shape=record
			 label="{cnt_deliver:|Filter obj.-\>resp.|{vcl_deliver\{\}|{req.*|resp.*}}|{restart|<deliver>deliver|<synth>synth}}"
		]

		deliver:deliver:s -> V1D_Deliver [style=bold,color=green]
		deliver:deliver:s -> V1D_Deliver [style=bold,color=red]
		deliver:deliver:s -> V1D_Deliver [style=bold,color=blue]

		stream [label="stream?\nbody",style=filled,color=turquoise]
		stream -> V1D_Deliver [style=dotted]
	}

	V1D_Deliver -> DONE

	/* cnt_synth() */
	subgraph xcluster_synth {
		synth [
		       shape=record
		       label="{cnt_synth:|{vcl_synth\{\}|{req.*|resp.*}}|{<del>deliver|<restart>restart}}"
		]

		SYNTH -> synth [color=purple]
		synth:del:s -> V1D_Deliver [color=purple]
	}

	subgraph cluster_backend {
		style=filled
		color=aliceblue

		"see backend graph" [shape=plaintext]

		node [shape=box,
		      style=filled,
		      color=turquoise]

		BGFETCH
		FETCH
		FETCH_DONE
		FETCH_FAIL
	}

	lookup2:deliver:s -> BGFETCH [label="parallel\nif obj expired",
				      color=green]
	FETCH_FAIL -> synth [color=purple]

	FETCH_DONE -> deliver [style=bold,color=red]
	FETCH_DONE -> deliver [style=bold,color=blue]
	FETCH -> FETCH_DONE [style=dotted]
	FETCH -> FETCH_FAIL [style=dotted]
	/* cnt_lookup() */
	subgraph xcluster_lookup {
		lookup [
			shape=record
			color=grey
			fontcolor=grey
			label="{<top>cnt_lookup:|hash lookup|{<h>hit?|<miss>miss?|<hfp>hit-for-pass?|<busy>busy?}}"
		]
		lookup2 [
			 shape=record
			 label="{<top>cnt_lookup:|{vcl_hit\{\}|{req.*|obj.*}}|{<deliver>deliver|<fetch>fetch|restart|synth|<pass>pass}}"
		]
	}
	lookup:busy:e -> lookup:top:e [label="(waitinglist)",
				       color=grey,
				       fontcolor=grey]
	lookup:miss:s -> miss [style=bold,color=blue]
	lookup:hfp:s -> pass [style=bold,color=red]
	lookup:h:s -> lookup2 [style=bold,color=green]

	lookup2:deliver:s -> deliver:n [style=bold,color=green]
	lookup2:fetch:s -> miss [style=bold,color=blue]
	// XXX should not happen
	// lookup2:fetch:s -> pass [style=bold,color=red,label="(no busy obj)"]
	lookup2:pass:s -> pass [style=bold,color=red]

	/* cnt_miss */
	subgraph xcluster_miss {
		miss [
		      shape=record
		      label="{cnt_miss:|{vcl_miss\{\}|req.*}|{<fetch>fetch|<synth>synth|<rst>restart|<pass>pass}}"
		]
	}
	miss:fetch:s -> FETCH [style=bold,color=blue]
	miss:pass:s -> pass [style=bold,color=red]

	/* cnt_pass */
	subgraph xcluster_pass {
		pass [
		      shape=record
		      label="{cnt_pass:|{vcl_pass\{\}|req.*}|{<fetch>fetch|<synth>synth|<rst>restart}}"
		]
	}
	pass:fetch:s -> FETCH [style=bold, color=red]

	/* cnt_pipe */
	subgraph xcluster_pipe {
		pipe [
		      shape=record
		      label="{cnt_pipe:|filter req.*-\>bereq.*|{vcl_pipe\{\}|{req.*|bereq.*}}|{<pipe>pipe|<synth>synth}}"
		]
		pipe_do [
			 shape=ellipse
			 label="send bereq,\ncopy bytes until close"
		]
		pipe:pipe -> pipe_do [style=bold,color=orange]
	}
	pipe_do -> DONE [style=bold,color=orange]

	/* cnt_restart */
	subgraph xcluster_restart {
		restart [
			shape=record
			color=grey
			fontcolor=grey
			label="{cnt_restart:|{<ok>ok?|<max>max_restarts?}}"
		]
	}
	RESTART -> restart [color=purple]
	restart:ok:s -> recv
	restart:max:s -> err_restart [color=purple]
	err_restart [label="SYNTH",shape=plaintext]

	/* cnt_recv() */
	subgraph xcluster_recv {
		recv [
		      shape=record
		      label="{cnt_recv:|{vcl_recv\{\}|req.*}|{<hash>hash|<purge>purge|<pass>pass|<pipe>pipe|<synth>synth}}"
		      ]
		recv:hash -> hash [style=bold,color=green]
		hash [
		      shape=record
		      label="{cnt_recv:|{vcl_hash\{\}|req.*}|{<lookup>lookup}}"
		      ]
	}
	recv:pipe -> pipe [style=bold,color=orange]
	recv:pass -> pass [style=bold,color=red]
	hash:lookup:w -> lookup [style=bold,color=green]
	hash:lookup:s -> purge:top:n [style=bold,color=purple]
	recv:purge:s -> hash [style=bold,color=purple]

	/* cnt_purge */
	subgraph xcluster_purge {
		purge [
		       shape=record
		       label="{<top>cnt_purge:|{vcl_purge\{\}|req.*}|{<synth>synth|<restart>restart}}"
		]
	}
}

Backend Side

/*
 * we should format labels in a readable form like
 *			    label="
 *			    {vbf_stp_startfetch:|
 *				    {vcl_backend_fetch\{\}|bereq.*}|
 *				    {abandon|
 *					    <fetch>fetch}}"
 *
 * <rant>
 * ... but some servers in the v-c.o build farm use old graphviz 2.26.3
 * which cannot handle labels with additional whitespace properly, so
 * for the time being we need to fall back into dark middle ages and
 * use illegibly long lines
 * </rant>
 * -- slink 20141013
 */

digraph cache_fetch {
	margin="0.5"
	center="1"

	/*** cache_fetch.c ***/
	subgraph cluster_backend {
		style=filled
		color=aliceblue
		RETRY [shape=plaintext]
		v_b_f_BGFETCH [label="BGFETCH",
			       shape=box,
			       style=filled,
			       color=turquoise]
		v_b_f_FETCH [label="FETCH",
			       shape=box,
			       style=filled,
			       color=turquoise]
		v_b_f_BGFETCH -> v_b_f [style=bold,color=green]
		v_b_f_FETCH -> v_b_f [style=bold,color=blue]
		v_b_f_FETCH -> v_b_f [style=bold,color=red]
		RETRY -> v_b_f [color=purple]
		/* vbf_stp_startfetch() */
		v_b_f [
			    shape=record
			    label="{vbf_stp_startfetch:|{vcl_backend_fetch\{\}|bereq.*}|{abandon|<fetch>fetch}}"
		]
		v_b_f:fetch:s -> v_b_hdrs [style=bold]
		v_b_hdrs [ label="send bereq,\nread beresp (headers)"]
		v_b_hdrs -> v_b_r [style=bold]
		v_b_hdrs -> v_b_e
		v_b_r [
			    shape=record
			    label="{vbf_stp_startfetch:|{vcl_backend_response\{\}|{bereq.*|beresp.*}}|{{retry|{<max>max?|<retry>ok?}}|abandon|{deliver|{<fetch_304>304?|<non_304>other?}}}}"
		]
		v_b_r:retry -> v_b_r_retry [color=purple]
		v_b_r:max -> v_b_e
		v_b_r:fetch_304:s -> vbf_stp_condfetch
		v_b_r:non_304:s -> vbf_stp_fetch

		v_b_r_retry [label="RETRY",shape=plaintext]

		vbf_stp_fetch [
			       shape=record
			       fontcolor=grey
			       color=grey
			       label="{vbf_stp_fetch:|setup VFPs|<fetch>fetch|{fetch_fail?|error?|<ok>ok?}}"
			       ]
		vbf_stp_fetch:ok:s -> FETCH_DONE

		vbf_stp_condfetch [
			       shape=record
			       fontcolor=grey
			       color=grey
			       label="{vbf_stp_condfetch:|copy obj attr|steal body|{fetch_fail?|<ok>ok?}}"

		]
		vbf_stp_condfetch:ok:s -> FETCH_DONE

		error [shape=plaintext]
		error -> FETCH_FAIL

		/* vbf_stp_error */
		v_b_e [
			    shape=record
			    label="{vbf_stp_error:|{vcl_backend_error\{\}|{bereq.*|beresp.*}}|{{retry|{<max>max?|<retry>ok?}}|<deliver>deliver}}}"
			    ]
		// v_b_e:deliver aka "backend synth" - goes into cache
		v_b_e:deliver -> FETCH_DONE [label="\"backend synth\""]
		v_b_e:retry -> v_b_e_retry [color=purple]
		v_b_e_retry [label="RETRY",shape=plaintext]
		v_b_e:max:s -> FETCH_FAIL

		v_b_e_retry [label="RETRY",shape=plaintext]

		FETCH_DONE [label="FETCH_DONE",
			    shape=box,style=filled,color=turquoise]

		abandon [shape=plaintext]
		abandon -> FETCH_FAIL
		// F_STP_FAIL
		FETCH_FAIL [label="FETCH_FAIL",
			    shape=box,style=filled,color=turquoise]
	}
}