Repository: trafficserver Updated Branches: refs/heads/master 2b64392d8 -> 15d3887b0
[TS-2314] - New config to allow unsatifiable Range: request to go straight to Origin Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/15d3887b Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/15d3887b Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/15d3887b Branch: refs/heads/master Commit: 15d3887b03a3f8e70436cd995a3ada0963a77423 Parents: 2b64392 Author: Sudheer Vinukonda <[email protected]> Authored: Mon Sep 22 23:45:42 2014 +0000 Committer: Sudheer Vinukonda <[email protected]> Committed: Mon Sep 22 23:45:42 2014 +0000 ---------------------------------------------------------------------- .../configuration/records.config.en.rst | 17 ++++- proxy/http/HttpSM.cc | 70 ++++++++++++++------ proxy/http/HttpSM.h | 1 + proxy/http/HttpTransact.cc | 4 +- proxy/http/HttpTransact.h | 4 +- 5 files changed, 71 insertions(+), 25 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/15d3887b/doc/reference/configuration/records.config.en.rst ---------------------------------------------------------------------- diff --git a/doc/reference/configuration/records.config.en.rst b/doc/reference/configuration/records.config.en.rst index cec4de6..defcefe 100644 --- a/doc/reference/configuration/records.config.en.rst +++ b/doc/reference/configuration/records.config.en.rst @@ -1086,8 +1086,21 @@ Cache Control .. ts:cv:: CONFIG proxy.config.cache.enable_read_while_writer INT 1 :reloadable: - Enables (``1``) or disables (``0``) ability to a read cached object while the another connection is completing the write to cache for - the same object. Several other configuration values need to be set for this to become active. See :ref:`reducing-origin-server-requests-avoiding-the-thundering-herd` + Specifies when to enable the ability to read a cached object while another + connection is completing the write to cache for that same object. The goal + here is to avoid multiple origin connections for the same cacheable object + upon a cache miss. The possible values of this config are: + + - ``0`` = never allow + - ``1`` = always allowed + - ``2`` = allowed, only if the ``Range`` requested can be satisfied from cache + + The ``2`` option is useful to avoid delaying requests which can not easily + be satisfied by the partially written response. + + Several other configuration values need to be set for this to be + usable. See :ref:`Reducing Origin Server Requests + <http-proxy-caching.en.html#reducing-origin-server-requests-avoiding-the-thundering-herd>`. .. ts:cv:: CONFIG proxy.config.cache.force_sector_size INT 0 :reloadable: http://git-wip-us.apache.org/repos/asf/trafficserver/blob/15d3887b/proxy/http/HttpSM.cc ---------------------------------------------------------------------- diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 166cb7e..7d44149 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -327,7 +327,8 @@ HttpSM::HttpSM() pushed_response_hdr_bytes(0), pushed_response_body_bytes(0), plugin_tag(0), plugin_id(0), hooks_set(false), cur_hook_id(TS_HTTP_LAST_HOOK), cur_hook(NULL), - cur_hooks(0), callout_state(HTTP_API_NO_CALLOUT), terminate_sm(false), kill_this_async_done(false) + cur_hooks(0), callout_state(HTTP_API_NO_CALLOUT), terminate_sm(false), + kill_this_async_done(false), parse_range_done(false) { static int scatter_init = 0; @@ -4114,6 +4115,12 @@ HttpSM::parse_range_and_compare(MIMEField *field, int64_t content_length) return; } + if (parse_range_done) { + Debug("http_range", "parse_range already done, t_state.range_setup %d", t_state.range_setup); + return; + } + parse_range_done = true; + n_values = 0; value = csv.get_first(field, &value_len); while (value) { @@ -4129,6 +4136,9 @@ HttpSM::parse_range_and_compare(MIMEField *field, int64_t content_length) value += 6; // skip leading 'bytes=' value_len -= 6; + // assume range_in_cache + t_state.range_in_cache = true; + for (; value; value = csv.get_next(&value_len)) { if (!(tmp = (const char *) memchr(value, '-', value_len))) { t_state.range_setup = HttpTransact::RANGE_NONE; @@ -4211,6 +4221,17 @@ HttpSM::parse_range_and_compare(MIMEField *field, int64_t content_length) ranges[nr]._start = start; ranges[nr]._end = end; ++nr; + + if (!cache_sm.cache_read_vc->is_pread_capable() && cache_config_read_while_writer==2) { + // write in progress, check if request range not in cache yet + HTTPInfo::FragOffset* frag_offset_tbl = t_state.cache_info.object_read->get_frag_table(); + int frag_offset_cnt = t_state.cache_info.object_read->get_frag_offset_count(); + + if (!frag_offset_tbl || (frag_offset_tbl[frag_offset_cnt - 1] < end)) { + Debug("http_range", "request range in cache, end %" PRId64 ", frg_offset_cnt %d, frag_size %" PRId64, end, frag_offset_cnt, frag_offset_tbl[frag_offset_cnt - 1]); + t_state.range_in_cache = false; + } + } } if (nr > 0) { @@ -4224,6 +4245,7 @@ HttpSM::parse_range_and_compare(MIMEField *field, int64_t content_length) t_state.range_setup = HttpTransact::RANGE_NOT_SATISFIABLE; Lfaild: + t_state.range_in_cache = false; t_state.num_range_fields = -1; delete []ranges; return; @@ -4295,26 +4317,32 @@ HttpSM::do_range_setup_if_necessary() if (t_state.method == HTTP_WKSIDX_GET && t_state.hdr_info.client_request.version_get() == HTTPVersion(1, 1)) { do_range_parse(field); - // if only one range entry and pread is capable, no need transform range - if (t_state.range_setup == HttpTransact::RANGE_REQUESTED && - t_state.num_range_fields == 1 && - cache_sm.cache_read_vc->is_pread_capable()) - t_state.range_setup = HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED; - - if (t_state.range_setup == HttpTransact::RANGE_REQUESTED && - api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == NULL) { - Debug("http_trans", "Unable to accelerate range request, fallback to transform"); - content_type = t_state.cache_info.object_read->response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &field_content_type_len); - //create a Range: transform processor for requests of type Range: bytes=1-2,4-5,10-100 (eg. multiple ranges) - range_trans = transformProcessor.range_transform(mutex, - t_state.ranges, - t_state.num_range_fields, - &t_state.hdr_info.transform_response, - content_type, - field_content_type_len, - t_state.cache_info.object_read->object_size_get() - ); - api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans); + if (t_state.range_setup == HttpTransact::RANGE_REQUESTED) { + + if (!t_state.range_in_cache) { + Debug("http_range", "range can't be satisifed from cache, force origin request"); + t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_MISS; + return; + } + + // if only one range entry and pread is capable, no need transform range + if (t_state.num_range_fields == 1 && + (cache_sm.cache_read_vc->is_pread_capable() || t_state.range_in_cache)) { + t_state.range_setup = HttpTransact::RANGE_NOT_TRANSFORM_REQUESTED; + } else if (api_hooks.get(TS_HTTP_RESPONSE_TRANSFORM_HOOK) == NULL) { + Debug("http_trans", "Unable to accelerate range request, fallback to transform"); + content_type = t_state.cache_info.object_read->response_get()->value_get(MIME_FIELD_CONTENT_TYPE, MIME_LEN_CONTENT_TYPE, &field_content_type_len); + //create a Range: transform processor for requests of type Range: bytes=1-2,4-5,10-100 (eg. multiple ranges) + range_trans = transformProcessor.range_transform(mutex, + t_state.ranges, + t_state.num_range_fields, + &t_state.hdr_info.transform_response, + content_type, + field_content_type_len, + t_state.cache_info.object_read->object_size_get() + ); + api_hooks.append(TS_HTTP_RESPONSE_TRANSFORM_HOOK, range_trans); + } } } } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/15d3887b/proxy/http/HttpSM.h ---------------------------------------------------------------------- diff --git a/proxy/http/HttpSM.h b/proxy/http/HttpSM.h index 015a59b..e143ab8 100644 --- a/proxy/http/HttpSM.h +++ b/proxy/http/HttpSM.h @@ -520,6 +520,7 @@ protected: // when the flag is set bool terminate_sm; bool kill_this_async_done; + bool parse_range_done; virtual int kill_this_async_hook(int event, void *data); void kill_this(); void update_stats(); http://git-wip-us.apache.org/repos/asf/trafficserver/blob/15d3887b/proxy/http/HttpTransact.cc ---------------------------------------------------------------------- diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc index 568b2d3..293a168 100644 --- a/proxy/http/HttpTransact.cc +++ b/proxy/http/HttpTransact.cc @@ -67,6 +67,7 @@ static char range_type[] = "multipart/byteranges; boundary=RANGE_SEPARATOR"; extern HttpBodyFactory *body_factory; extern int cache_config_vary_on_user_agent; +extern int cache_config_read_while_writer; static const char local_host_ip_str[] = "127.0.0.1"; @@ -2863,8 +2864,9 @@ HttpTransact::build_response_from_cache(State* s, HTTPWarningCode warning_code) s->cache_info.action = CACHE_DO_NO_ACTION; s->next_action = SM_ACTION_INTERNAL_CACHE_NOOP; break; - } else if (s->range_setup == RANGE_NOT_HANDLED) { + } else if ((s->range_setup == RANGE_NOT_HANDLED) || !s->range_in_cache) { // we switch to tunneling for Range requests if it is out of order. + // or if the range can't be satisfied from the cache // In that case we fetch the entire source so it's OK to switch // this late. DebugTxn("http_seq", "[HttpTransact::HandleCacheOpenReadHit] Out-of-order Range request - tunneling"); http://git-wip-us.apache.org/repos/asf/trafficserver/blob/15d3887b/proxy/http/HttpTransact.h ---------------------------------------------------------------------- diff --git a/proxy/http/HttpTransact.h b/proxy/http/HttpTransact.h index 59b76ef..f35d0fe 100644 --- a/proxy/http/HttpTransact.h +++ b/proxy/http/HttpTransact.h @@ -1017,6 +1017,7 @@ public: OverridableHttpConfigParams my_txn_conf; // Storage for plugins, to avoid malloc bool transparent_passthrough; + bool range_in_cache; // Methods void @@ -1112,7 +1113,8 @@ public: range_output_cl(0), ranges(NULL), txn_conf(NULL), - transparent_passthrough(false) + transparent_passthrough(false), + range_in_cache(false) { int i; char *via_ptr = via_string;
