diff --git a/source/common/router/router.cc b/source/common/router/router.cc index 1cb812071485..98c5a51a30f4 100644 --- a/source/common/router/router.cc +++ b/source/common/router/router.cc @@ -815,6 +815,9 @@ bool Filter::continueDecodeHeaders(Upstream::ThreadLocalCluster* cluster, createRetryState(*getEffectiveRetryPolicy(), headers, *cluster_, config_->factory_context_, callbacks_->dispatcher(), route_entry_->priority()); + absl::InlinedVector, 4> active_shadow_policies; + std::unique_ptr original_shadow_headers; + // Determine which shadow policies to use. It's possible that we don't do any shadowing due to // runtime keys. Also the method CONNECT doesn't support shadowing. auto method = headers.getMethodValue(); @@ -828,8 +831,10 @@ bool Filter::continueDecodeHeaders(Upstream::ThreadLocalCluster* cluster, for (const auto& shadow_policy : policies_to_evaluate) { const auto& policy_ref = *shadow_policy; if (FilterUtility::shouldShadow(policy_ref, config_->runtime_, callbacks_->streamId())) { - active_shadow_policies_.push_back(std::cref(policy_ref)); - shadow_headers_ = Http::createHeaderMap(*downstream_headers_); + active_shadow_policies.push_back(std::cref(policy_ref)); + if (original_shadow_headers == nullptr) { + original_shadow_headers = Http::createHeaderMap(headers); + } } } } @@ -852,14 +857,21 @@ bool Filter::continueDecodeHeaders(Upstream::ThreadLocalCluster* cluster, LinkedList::moveIntoList(std::move(upstream_request), upstream_requests_); upstream_requests_.front()->acceptHeadersFromRouter(end_stream); // Start the shadow streams. - for (const auto& shadow_policy_wrapper : active_shadow_policies_) { - const auto& shadow_policy = shadow_policy_wrapper.get(); + for (size_t i = 0; i < active_shadow_policies.size(); ++i) { + const auto& shadow_policy = active_shadow_policies[i].get(); const absl::optional shadow_cluster_name = getShadowCluster(shadow_policy, *downstream_headers_); if (!shadow_cluster_name.has_value()) { continue; } - auto shadow_headers = Http::createHeaderMap(*shadow_headers_); + std::unique_ptr shadow_headers; + if (i == active_shadow_policies.size() - 1) { + // For the last shadow policy, we can reuse the original headers to save a copy because + // copy whole headers map is not cheap. + shadow_headers = std::move(original_shadow_headers); + } else { + shadow_headers = Http::createHeaderMap(*original_shadow_headers); + } applyShadowPolicyHeaders(shadow_policy, *shadow_headers); const auto options = Http::AsyncClient::RequestOptions() @@ -883,9 +895,7 @@ bool Filter::continueDecodeHeaders(Upstream::ThreadLocalCluster* cluster, if (end_stream) { // This is a header-only request, and can be dispatched immediately to the shadow // without waiting. - Http::RequestMessagePtr request(new Http::RequestMessageImpl( - Http::createHeaderMap(*shadow_headers_))); - applyShadowPolicyHeaders(shadow_policy, request->headers()); + Http::RequestMessagePtr request(new Http::RequestMessageImpl(std::move(shadow_headers))); config_->shadowWriter().shadow(std::string(shadow_cluster_name.value()), std::move(request), options); } else { @@ -1091,10 +1101,6 @@ Http::FilterDataStatus Filter::decodeData(Buffer::Instance& data, bool end_strea Http::FilterTrailersStatus Filter::decodeTrailers(Http::RequestTrailerMap& trailers) { ENVOY_STREAM_LOG(debug, "router decoding trailers:\n{}", *callbacks_, trailers); - if (shadow_headers_) { - shadow_trailers_ = Http::createHeaderMap(trailers); - } - // upstream_requests_.size() cannot be > 1 because that only happens when a per // try timeout occurs with hedge_on_per_try_timeout enabled but the per // try timeout timer is not started until onRequestComplete(). It could be zero @@ -1109,7 +1115,7 @@ Http::FilterTrailersStatus Filter::decodeTrailers(Http::RequestTrailerMap& trail shadow_stream->removeDestructorCallback(); shadow_stream->removeWatermarkCallbacks(); shadow_stream->captureAndSendTrailers( - Http::createHeaderMap(*shadow_trailers_)); + Http::createHeaderMap(trailers)); } shadow_streams_.clear(); diff --git a/source/common/router/router.h b/source/common/router/router.h index c6c3dd77e904..2f5879a326f6 100644 --- a/source/common/router/router.h +++ b/source/common/router/router.h @@ -659,9 +659,6 @@ class Filter : Logger::Loggable, MetadataMatchCriteriaConstPtr metadata_match_; std::function modify_headers_; std::function modify_headers_from_upstream_lb_; - std::vector> active_shadow_policies_; - std::unique_ptr shadow_headers_; - std::unique_ptr shadow_trailers_; // The stream lifetime configured by request header. absl::optional dynamic_max_stream_duration_; // list of cookies to add to upstream headers