[master] ac8609f Add H/2 stream timeouts
Dag Haavi Finstad
daghf at varnish-software.com
Mon Feb 26 13:19:09 UTC 2018
commit ac8609f6ca53338fafd66216d603837d61c096a5
Author: Dag Haavi Finstad <daghf at varnish-software.com>
Date: Mon Feb 26 14:13:40 2018 +0100
Add H/2 stream timeouts
Avoid keeping H/2 streams alive indefinitely.
This adds timeouts for:
- How long we allow a stream to wait for a WINDOW_UPDATE, subject
to idle_send_timeout
- Total duration after we started transmitting a response,
subject to send_timeout
We currently do not make any attempt at sending a GOAWAY or a PING for
client inactivity. This may be something to reconsider at a later point.
diff --git a/bin/varnishd/http2/cache_http2.h b/bin/varnishd/http2/cache_http2.h
index 2883789..51b175b 100644
--- a/bin/varnishd/http2/cache_http2.h
+++ b/bin/varnishd/http2/cache_http2.h
@@ -121,6 +121,8 @@ struct h2_req {
enum h2_stream_e state;
struct h2_sess *h2sess;
struct req *req;
+ double t_send;
+ double t_winupd;
pthread_cond_t *cond;
VTAILQ_ENTRY(h2_req) list;
int64_t t_window;
diff --git a/bin/varnishd/http2/cache_http2_deliver.c b/bin/varnishd/http2/cache_http2_deliver.c
index 46b0f38..a9f43e9 100644
--- a/bin/varnishd/http2/cache_http2_deliver.c
+++ b/bin/varnishd/http2/cache_http2_deliver.c
@@ -254,6 +254,8 @@ h2_deliver(struct req *req, struct boc *boc, int sendbody)
if (sendbody && req->resp_len == 0)
sendbody = 0;
+ r2->t_send = req->t_prev;
+
H2_Send_Get(req->wrk, r2->h2sess, r2);
H2_Send(req->wrk, r2, H2_F_HEADERS,
(sendbody ? 0 : H2FF_HEADERS_END_STREAM) | H2FF_HEADERS_END_HEADERS,
diff --git a/bin/varnishd/http2/cache_http2_proto.c b/bin/varnishd/http2/cache_http2_proto.c
index 72d0342..f09bed9 100644
--- a/bin/varnishd/http2/cache_http2_proto.c
+++ b/bin/varnishd/http2/cache_http2_proto.c
@@ -889,6 +889,37 @@ h2_procframe(struct worker *wrk, struct h2_sess *h2,
return (h2_tx_rst(wrk, h2, h2e));
}
+static int
+h2_stream_tmo(struct h2_sess *h2, const struct h2_req *r2)
+{
+ int r = 0;
+
+ CHECK_OBJ_NOTNULL(h2, H2_SESS_MAGIC);
+ CHECK_OBJ_NOTNULL(r2, H2_REQ_MAGIC);
+
+ if (r2->t_winupd != 0 || r2->t_send != 0) {
+ Lck_Lock(&h2->sess->mtx);
+ if (r2->t_winupd != 0 &&
+ h2->sess->t_idle - r2->t_winupd >
+ cache_param->idle_send_timeout) {
+ VSLb(h2->vsl, SLT_Debug,
+ "H2: stream %u: Hit idle_send_timeout waiting "
+ "for WINDOW_UPDATE", r2->stream);
+ r = 1;
+ }
+
+ if (r == 0 && r2->t_send != 0 &&
+ h2->sess->t_idle - r2->t_send > cache_param->send_timeout) {
+ VSLb(h2->vsl, SLT_Debug,
+ "H2: stream %u: Hit send_timeout", r2->stream);
+ r = 1;
+ }
+ Lck_Unlock(&h2->sess->mtx);
+ }
+
+ return (r);
+}
+
/***********************************************************************
* Called in loop from h2_new_session()
*/
@@ -912,6 +943,7 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2)
h2_error h2e;
struct h2_req *r2, *r22;
char b[8];
+ int abort = 0;
ASSERT_RXTHR(h2);
(void)VTCP_blocking(*h2->htc->rfd);
@@ -925,6 +957,8 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2)
break;
case HTC_S_TIMEOUT:
VTAILQ_FOREACH_SAFE(r2, &h2->streams, list, r22) {
+ if (abort)
+ break;
switch (r2->state) {
case H2_S_CLOSED:
if (!r2->scheduled)
@@ -933,6 +967,10 @@ h2_rxframe(struct worker *wrk, struct h2_sess *h2)
case H2_S_OPEN:
case H2_S_CLOS_REM:
case H2_S_CLOS_LOC:
+ if (h2_stream_tmo(h2, r2)) {
+ abort = 1;
+ continue;
+ }
return (1);
default:
break;
diff --git a/bin/varnishd/http2/cache_http2_send.c b/bin/varnishd/http2/cache_http2_send.c
index a369df7..839193f 100644
--- a/bin/varnishd/http2/cache_http2_send.c
+++ b/bin/varnishd/http2/cache_http2_send.c
@@ -35,6 +35,7 @@
#include "http2/cache_http2.h"
#include "vend.h"
+#include "vtim.h"
static void
h2_send_get(struct worker *wrk, struct h2_sess *h2, struct h2_req *r2)
@@ -204,15 +205,14 @@ h2_do_window(struct worker *wrk, struct h2_req *r2,
Lck_Lock(&h2->sess->mtx);
if (r2->t_window <= 0 || h2->req0->t_window <= 0) {
+ r2->t_winupd = VTIM_real();
h2_send_rel(h2, r2);
while (r2->t_window <= 0 && h2_errcheck(r2, h2) == 0) {
r2->cond = &wrk->cond;
- // XXX: timeout handling (subject to send_timeout?)
AZ(Lck_CondWait(r2->cond, &h2->sess->mtx, 0));
r2->cond = NULL;
}
while (h2->req0->t_window <= 0 && h2_errcheck(r2, h2) == 0) {
- // XXX: timeout handling
AZ(Lck_CondWait(h2->cond, &h2->sess->mtx, 0));
}
@@ -235,6 +235,7 @@ h2_do_window(struct worker *wrk, struct h2_req *r2,
h2_win_charge(r2, h2, w);
assert (w > 0);
}
+ r2->t_winupd = 0;
Lck_Unlock(&h2->sess->mtx);
return (w);
}
More information about the varnish-commit
mailing list