Skip to content

Commit 9ae4522

Browse files
committed
prepare for Rust 1.50+ by boxing large futures
Version 1.50 of the Rust compiler introduced a regression (rust-lang/rust#84873) that results in the compiler using extremely large amounts of memory (and eventually getting OOM killed) when compiling code involving very large nested types. This regression is triggered by a number of future types in the proxy. This branch introduces several `BoxService` layers, primarily around `Switch` layers, to reduce the size of future types, so that the proxy can successfully be compiled on Rust 1.50+. This branch does *not* update the toolchain version. The Rust 1.51 toolchain also introduces some new clippy lints, which trigger on some code patterns that are very common in the current proxy. Therefore, the diff from a compiler update will be much larger than just adding additional boxing. I'll land the compiler update in a separate branch after this merges.
1 parent 626b2ee commit 9ae4522

File tree

11 files changed

+88
-19
lines changed

11 files changed

+88
-19
lines changed

linkerd/app/gateway/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ where
117117
.push_tcp_endpoint()
118118
.push_tcp_logical(resolve.clone())
119119
.into_stack()
120+
// .push_on_response(svc::BoxService::layer())
120121
.push_request_filter(
121122
|(p, _): (Option<profiles::Receiver>, _)| -> Result<_, Error> {
122123
let profile = p.ok_or_else(discovery_rejected)?;
@@ -229,6 +230,8 @@ where
229230
)
230231
.push_http_server()
231232
.into_stack()
233+
.push_on_response(svc::BoxService::layer())
234+
.push(svc::BoxNewService::layer())
232235
.push_switch(
233236
|GatewayTransportHeader {
234237
target,
@@ -254,6 +257,8 @@ where
254257
},
255258
legacy_http,
256259
)
260+
.push_on_response(svc::BoxService::layer())
261+
.push(svc::BoxNewService::layer())
257262
.into_inner()
258263
}
259264

linkerd/app/inbound/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ where
234234
.push_http_router(profiles)
235235
.push_http_server()
236236
.stack
237+
.push_on_response(svc::BoxService::layer())
237238
.push_map_target(HttpAccept::from)
238239
.push(svc::UnwrapOr::layer(
239240
// When HTTP detection fails, forward the connection to the
@@ -242,13 +243,16 @@ where
242243
.push_tcp_forward(server_port)
243244
.stack
244245
.push_map_target(TcpEndpoint::from)
246+
.push_on_response(svc::BoxService::layer())
247+
.push(svc::BoxNewService::layer())
245248
.into_inner(),
246249
))
247250
.push_map_target(detect::allow_timeout)
248251
.push(detect::NewDetectService::layer(
249252
config.detect_protocol_timeout,
250253
http::DetectHttp::default(),
251254
))
255+
// .push_on_response(svc::BoxService::layer())
252256
.push_request_filter(require_id)
253257
.push(self.runtime.metrics.transport.layer_accept())
254258
.push_request_filter(TcpAccept::try_from)
@@ -257,6 +261,7 @@ where
257261
config.detect_protocol_timeout,
258262
))
259263
.instrument(|_: &_| debug_span!("proxy"))
264+
.push_on_response(svc::BoxService::layer())
260265
.push_switch(
261266
disable_detect,
262267
self.clone()
@@ -267,6 +272,8 @@ where
267272
.push_map_target(TcpAccept::port_skipped)
268273
.check_new_service::<T, _>()
269274
.instrument(|_: &T| debug_span!("forward"))
275+
.push_on_response(svc::BoxService::layer())
276+
.push(svc::BoxNewService::layer())
270277
.into_inner(),
271278
)
272279
.check_new_service::<T, I>()
@@ -276,12 +283,15 @@ where
276283
.push_direct(gateway)
277284
.stack
278285
.instrument(|_: &_| debug_span!("direct"))
286+
.push_on_response(svc::BoxService::layer())
287+
.push(svc::BoxNewService::layer())
279288
.into_inner(),
280289
)
281290
.instrument(|a: &T| {
282291
let OrigDstAddr(target_addr) = a.param();
283292
info_span!("server", port = target_addr.port())
284293
})
294+
// .push_on_response(svc::BoxService::layer())
285295
.into_inner()
286296
}
287297
}

linkerd/app/outbound/src/discover.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ impl<N> Outbound<N> {
2727
N: svc::NewService<(Option<profiles::Receiver>, tcp::Accept), Service = NSvc>
2828
+ Clone
2929
+ Send
30+
+ Sync
3031
+ 'static,
3132
NSvc: svc::Service<SensorIo<I>, Response = (), Error = Error> + Send + 'static,
3233
NSvc::Future: Send,
33-
P: profiles::GetProfile<profiles::LookupAddr> + Clone + Send + 'static,
34+
P: profiles::GetProfile<profiles::LookupAddr> + Clone + Send + Sync + 'static,
3435
P::Future: Send,
3536
P::Error: Send,
3637
{
@@ -74,6 +75,9 @@ impl<N> Outbound<N> {
7475
.push_cache(config.proxy.cache_max_idle_age)
7576
.instrument(|a: &tcp::Accept| info_span!("server", orig_dst = %a.orig_dst))
7677
.push_request_filter(|t: T| tcp::Accept::try_from(t.param()))
78+
// Boxing is necessary purely to limit the link-time overhead of
79+
// having enormous types.
80+
.push(svc::BoxNewService::layer())
7781
.check_new_service::<T, I>();
7882

7983
Outbound {

linkerd/app/outbound/src/endpoint.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,14 @@ impl<S> Outbound<S> {
205205
S::Response:
206206
tls::HasNegotiatedProtocol + io::AsyncRead + io::AsyncWrite + Send + Unpin + 'static,
207207
S::Future: Send + Unpin,
208-
I: io::AsyncRead + io::AsyncWrite + io::PeerAddr + fmt::Debug + Send + Unpin + 'static,
208+
I: io::AsyncRead
209+
+ io::AsyncWrite
210+
+ io::PeerAddr
211+
+ fmt::Debug
212+
+ Send
213+
+ Sync
214+
+ Unpin
215+
+ 'static,
209216
{
210217
let http = self
211218
.clone()

linkerd/app/outbound/src/http/detect.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,20 @@ impl<N> Outbound<N> {
2121
> + Clone,
2222
>
2323
where
24-
I: io::AsyncRead + io::AsyncWrite + io::PeerAddr + std::fmt::Debug + Send + Unpin + 'static,
25-
N: svc::NewService<T, Service = NSvc> + Clone + Send + 'static,
26-
NSvc: svc::Service<io::EitherIo<I, io::PrefixedIo<I>>, Response = ()> + Send + 'static,
24+
I: io::AsyncRead
25+
+ io::AsyncWrite
26+
+ io::PeerAddr
27+
+ std::fmt::Debug
28+
+ Send
29+
+ Sync
30+
+ Unpin
31+
+ 'static,
32+
N: svc::NewService<T, Service = NSvc> + Clone + Send + Sync + 'static,
33+
NSvc:
34+
svc::Service<io::EitherIo<I, io::PrefixedIo<I>>, Response = ()> + Send + Sync + 'static,
2735
NSvc::Error: Into<Error>,
2836
NSvc::Future: Send,
29-
H: svc::NewService<U, Service = HSvc> + Clone + Send + 'static,
37+
H: svc::NewService<U, Service = HSvc> + Clone + Send + Sync + 'static,
3038
HSvc: svc::Service<http::Request<http::BoxBody>, Response = http::Response<http::BoxBody>>,
3139
HSvc: Clone + Send + Sync + Unpin + 'static,
3240
HSvc::Error: Into<Error>,
@@ -82,7 +90,10 @@ impl<N> Outbound<N> {
8290
},
8391
skipped,
8492
)
85-
.check_new_service::<T, _>();
93+
.check_new_service::<T, _>()
94+
// Boxing is necessary purely to limit the link-time overhead of
95+
// having enormous types.
96+
.push(svc::BoxNewService::layer());
8697

8798
Outbound {
8899
config,

linkerd/app/outbound/src/http/endpoint.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@ impl<C> Outbound<C> {
1919
Error = Error,
2020
Future = impl Send,
2121
>,
22-
> + Clone,
22+
> + Clone
23+
+ Send
24+
+ Sync
25+
+ 'static,
2326
>
2427
where
2528
T: Clone + Send + Sync + 'static,
@@ -33,7 +36,7 @@ impl<C> Outbound<C> {
3336
C: svc::Service<T> + Clone + Send + Sync + Unpin + 'static,
3437
C::Response: io::AsyncRead + io::AsyncWrite + Send + Unpin,
3538
C::Error: Into<Error>,
36-
C::Future: Send + Unpin,
39+
C::Future: Send + Unpin + 'static,
3740
{
3841
let Self {
3942
config,
@@ -70,7 +73,9 @@ impl<C> Outbound<C> {
7073
"host",
7174
CANONICAL_DST_HEADER,
7275
]))
73-
.push_on_response(http::BoxResponse::layer());
76+
.push_on_response(http::BoxResponse::layer())
77+
// .push_on_response(svc::BoxService::layer())
78+
;
7479

7580
Outbound {
7681
config,

linkerd/app/outbound/src/http/logical.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,17 @@ impl<E> Outbound<E> {
3030
where
3131
B: http::HttpBody<Error = Error> + std::fmt::Debug + Default + Send + 'static,
3232
B::Data: Send + 'static,
33-
E: svc::NewService<Endpoint, Service = ESvc> + Clone + Send + 'static,
33+
E: svc::NewService<Endpoint, Service = ESvc> + Clone + Send + Sync + 'static,
3434
ESvc: svc::Service<http::Request<http::BoxBody>, Response = http::Response<http::BoxBody>>
3535
+ Send
3636
+ 'static,
3737
ESvc::Error: Into<Error>,
3838
ESvc::Future: Send,
39-
R: Resolve<ConcreteAddr, Error = Error, Endpoint = Metadata> + Clone + Send + 'static,
39+
R: Resolve<ConcreteAddr, Error = Error, Endpoint = Metadata>
40+
+ Clone
41+
+ Send
42+
+ Sync
43+
+ 'static,
4044
R::Resolution: Send,
4145
R::Future: Send + Unpin,
4246
{
@@ -152,7 +156,11 @@ impl<E> Outbound<E> {
152156
.push(http::strip_header::request::layer(DST_OVERRIDE_HEADER))
153157
.push(http::BoxResponse::layer()),
154158
)
155-
.instrument(|l: &Logical| debug_span!("logical", dst = %l.logical_addr));
159+
.instrument(|l: &Logical| debug_span!("logical", dst = %l.logical_addr))
160+
// Boxing is necessary purely to limit the link-time overhead of
161+
// having enormous types.
162+
.push(svc::BoxNewService::layer())
163+
.push_on_response(svc::BoxService::layer());
156164

157165
Outbound {
158166
config,

linkerd/app/outbound/src/http/server.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ impl<N> Outbound<N> {
1717
>
1818
where
1919
T: svc::Param<http::normalize_uri::DefaultAuthority>,
20-
N: svc::NewService<T, Service = NSvc> + Clone + Send + 'static,
20+
N: svc::NewService<T, Service = NSvc> + Clone + Send + Sync + 'static,
2121
NSvc: svc::Service<http::Request<http::BoxBody>, Response = http::Response<http::BoxBody>>,
2222
NSvc: Send + 'static,
2323
NSvc::Error: Into<Error>,
@@ -62,7 +62,10 @@ impl<N> Outbound<N> {
6262
.push(http::NewNormalizeUri::layer())
6363
// Record when a HTTP/1 URI originated in absolute form
6464
.push_on_response(http::normalize_uri::MarkAbsoluteForm::layer())
65-
.check_new_service::<T, http::Request<http::BoxBody>>();
65+
.check_new_service::<T, http::Request<http::BoxBody>>()
66+
// Boxing is necessary purely to limit the link-time overhead of
67+
// having enormous types.
68+
.push(svc::BoxNewService::layer());
6669

6770
Outbound {
6871
config,

linkerd/app/outbound/src/ingress.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ impl<H> Outbound<H> {
148148
// Boxing is necessary purely to limit the link-time overhead of
149149
// having enormous types.
150150
.push(svc::BoxNewService::layer())
151+
.push_on_response(svc::BoxService::layer())
151152
.check_new_service::<T, I>()
152153
.into_inner()
153154
}

linkerd/app/outbound/src/logical.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,17 @@ impl<C> Outbound<C> {
131131
tls::HasNegotiatedProtocol + io::AsyncRead + io::AsyncWrite + Send + Unpin + 'static,
132132
C::Future: Send + Unpin,
133133
R: Clone + Send + 'static,
134-
R: Resolve<ConcreteAddr, Endpoint = Metadata, Error = Error>,
134+
R: Resolve<ConcreteAddr, Endpoint = Metadata, Error = Error> + Sync,
135135
R::Resolution: Send,
136136
R::Future: Send + Unpin,
137-
I: io::AsyncRead + io::AsyncWrite + io::PeerAddr + fmt::Debug + Send + Unpin + 'static,
137+
I: io::AsyncRead
138+
+ io::AsyncWrite
139+
+ io::PeerAddr
140+
+ fmt::Debug
141+
+ Send
142+
+ Sync
143+
+ Unpin
144+
+ 'static,
138145
{
139146
let http = self
140147
.clone()

linkerd/app/outbound/src/tcp/logical.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,14 @@ where
3131
>
3232
where
3333
I: io::AsyncRead + io::AsyncWrite + std::fmt::Debug + Send + Unpin + 'static,
34-
R: Resolve<ConcreteAddr, Endpoint = Metadata, Error = Error> + Clone + Send + 'static,
34+
R: Resolve<ConcreteAddr, Endpoint = Metadata, Error = Error>
35+
+ Clone
36+
+ Send
37+
+ Sync
38+
+ 'static,
3539
R::Resolution: Send,
3640
R::Future: Send + Unpin,
41+
C: Send + Sync + 'static,
3742
{
3843
let Self {
3944
config,
@@ -101,7 +106,10 @@ where
101106
.push_cache(cache_max_idle_age)
102107
.check_new_service::<Logical, I>()
103108
.instrument(|_: &Logical| debug_span!("tcp"))
104-
.check_new_service::<Logical, I>();
109+
.check_new_service::<Logical, I>()
110+
// Boxing is necessary purely to limit the link-time overhead of
111+
// having enormous types.
112+
.push(svc::BoxNewService::layer());
105113

106114
Outbound {
107115
config,

0 commit comments

Comments
 (0)