Project

General

Profile

lighttpd.r1882.cgi-throttle.patch

first attempt at a workaround for ticket:1264 (still contains some debug code) - ctaylor, 2007-07-25 22:39

View differences:

src/mod_cgi.c (working copy)
51 51
typedef struct {
52 52
	array *cgi;
53 53
	unsigned short execute_all;
54
	int high_watermark; /* maximum bytes in send_raw before backing off */
55
	int low_watermark; /* minimum bytes in send_raw to disable backoff */
54 56
} plugin_config;
55 57

  
56 58
typedef struct {
......
85 87
	cgi_state_t state;
86 88

  
87 89
	connection *remote_con;  /* dumb pointer */
90

  
91
	int throttling; /* 1=waiting for send_raw buffer to drain */
92
	int high_watermark; /* maximum bytes in send_raw before backing off */
93
	int low_watermark; /* minimum bytes in send_raw to disable backoff */
88 94
} cgi_session;
89 95

  
90
static cgi_session * cgi_session_init() {
96
static cgi_session * cgi_session_init(plugin_data *p) {
91 97
	cgi_session *sess = calloc(1, sizeof(*sess));
92 98
	assert(sess);
93 99

  
......
96 102
	sess->wb = chunkqueue_init();
97 103
	sess->rb = chunkqueue_init();
98 104

  
105
	sess->throttling = 0;
106
	sess->high_watermark = p->conf.high_watermark; // local copy
107
	sess->low_watermark = p->conf.low_watermark; // local copy
108
	if (sess->low_watermark >= sess->high_watermark)
109
		sess->low_watermark = sess->high_watermark * 3 / 4; // 75%
110

  
99 111
	return sess;
100 112
}
101 113

  
......
159 171
#define PLUGIN_NAME "cgi"
160 172
#define CONFIG_ASSIGN      PLUGIN_NAME ".assign"
161 173
#define CONFIG_EXECUTE_ALL PLUGIN_NAME ".execute-all"
174
#define CONFIG_HIGH_WATERMARK PLUGIN_NAME ".high-watermark"
175
#define CONFIG_LOW_WATERMARK PLUGIN_NAME ".low-watermark"
162 176

  
163 177
SETDEFAULTS_FUNC(mod_cgi_set_defaults) {
164 178
	plugin_data *p = p_d;
......
167 181
	config_values_t cv[] = {
168 182
		{ CONFIG_ASSIGN,                 NULL, T_CONFIG_ARRAY,   T_CONFIG_SCOPE_CONNECTION },       /* 0 */
169 183
		{ CONFIG_EXECUTE_ALL,            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
184
		{ CONFIG_HIGH_WATERMARK,         NULL, T_CONFIG_INT,     T_CONFIG_SCOPE_CONNECTION },       /* 2 */
185
		{ CONFIG_LOW_WATERMARK,          NULL, T_CONFIG_INT,     T_CONFIG_SCOPE_CONNECTION },       /* 3 */
170 186
		{ NULL,                          NULL, T_CONFIG_UNSET,   T_CONFIG_SCOPE_UNSET}
171 187
	};
172 188

  
......
182 198

  
183 199
		s->cgi    = array_init();
184 200
		s->execute_all = 0;
201
		s->high_watermark = 0; // 0 == disabled
202
		s->low_watermark = 0;
185 203

  
186 204
		cv[0].destination = s->cgi;
187 205
		cv[1].destination = &(s->execute_all);
206
		cv[2].destination = &(s->high_watermark);
207
		cv[3].destination = &(s->low_watermark);
188 208

  
189 209
		p->config_storage[i] = s;
190 210

  
......
272 292
	}
273 293
	chunkqueue_remove_finished_chunks(sess->rb);
274 294

  
295
	/* optionally stop reading from pipe if send_raw buffer is too full */
296
	if (sess->high_watermark && !sess->throttling) {
297
		off_t delta = con->send_raw->bytes_in - con->send_raw->bytes_out;
298
		if (delta > sess->high_watermark) {
299
			fdevent_event_del(srv->ev, sess->sock);
300
			sess->throttling = 1;
301
			TRACE ( "backoff: %d/%d in=%u out=%u delta=%u",
302
				sess->sock->fd, con->sock->fd,
303
				(unsigned int) con->send_raw->bytes_in,
304
				(unsigned int) con->send_raw->bytes_out,
305
				(unsigned int) delta );
306
		}
307
	}
308

  
275 309
	if(sess->rb->is_closed) {
276 310
		con->send->is_closed = 1;
277 311
	}
......
282 316
static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
283 317
	cgi_session *sess = con->plugin_ctx[p->id];
284 318

  
319
	if (sess->throttling) {
320
		off_t delta = con->send_raw->bytes_in - con->send_raw->bytes_out;
321
		if (delta <= sess->low_watermark) {
322
			fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
323
			sess->throttling = 0;
324
		}
325

  
326
		TRACE ( "throttle: %d/%d rb=%u/%u delta=%u t=%d",
327
			sess->sock->fd, con->sock->fd,
328
			(unsigned int) sess->rb->bytes_in,
329
			(unsigned int) sess->rb->bytes_in,
330
			(unsigned int) delta, sess->throttling );
331
	}
332

  
285 333
	switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
286 334
	case NETWORK_STATUS_CONNECTION_CLOSE:
287 335
		fdevent_event_del(srv->ev, sess->sock);
......
380 428
	* - use next-queue instead of con->write_queue
381 429
	*/
382 430

  
383
	/* copy the resopnse content */
431
	/* copy the response content */
384 432
	cgi_copy_response(srv, con, sess);
385 433

  
386 434
	joblist_append(srv, con);
......
517 565

  
518 566
				/* how much do we want to read ? */
519 567

  
520
				/* copy the resopnse content */
568
				/* copy the response content */
521 569
				cgi_copy_response(srv, con, sess);
522 570

  
523 571
				break;
......
878 926
		con->mode = p->id;
879 927
		buffer_reset(con->physical.path);
880 928

  
881
		sess = cgi_session_init();
929
		sess = cgi_session_init(p);
882 930

  
883 931
		sess->remote_con = con;
884 932
		sess->pid = pid;
......
921 969

  
922 970
	PATCH_OPTION(cgi);
923 971
	PATCH_OPTION(execute_all);
972
	PATCH_OPTION(high_watermark);
973
	PATCH_OPTION(low_watermark);
924 974

  
925 975
	/* skip the first, the global context */
926 976
	for (i = 1; i < srv->config_context->used; i++) {
......
938 988
				PATCH_OPTION(cgi);
939 989
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXECUTE_ALL))) {
940 990
				PATCH_OPTION(execute_all);
991
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIGH_WATERMARK))) {
992
				PATCH_OPTION(high_watermark);
993
			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_LOW_WATERMARK))) {
994
				PATCH_OPTION(low_watermark);
941 995
			}
942 996
		}
943 997
	}
......
951 1005
	buffer *fn = con->physical.path;
952 1006

  
953 1007
	if (fn->used == 0) return HANDLER_GO_ON;
954
	
1008

  
955 1009
	mod_cgi_patch_connection(srv, con, p);
956 1010

  
957 1011
	if (p->conf.cgi->used == 0 && p->conf.execute_all == 0) {
......
998 1052
TRIGGER_FUNC(cgi_trigger) {
999 1053
	plugin_data *p = p_d;
1000 1054
	size_t ndx;
1055

  
1001 1056
	/* the trigger handle only cares about lonely PID which we have to wait for */
1002 1057
#ifndef _WIN32
1003 1058

  
......
1154 1209
		}
1155 1210
		chunkqueue_remove_finished_chunks(con->recv);
1156 1211
	}
1212

  
1157 1213
	/* we have to close the pipe to finish the request. */
1158 1214
	if ((con->recv->is_closed && con->recv->bytes_in == con->recv->bytes_out) ||
1159 1215
			con->request.content_length <= 0) {