Skip to content

Commit 5291b24

Browse files
committed
Sped up the compilation/execution of snippets by using previously
started and idle docker containers, rather than starting a new one for each request. By sleeping for a long time in entrypoint.sh, containers stay idle. Cargo is called through cargo.sh, which cares of exporting env vars and killing the container once it's done. Thus, there's no need to drop a container that has been used. However idle containers need to me manually terminated: DockerContainers Drop impl takes care of that.
1 parent 6502544 commit 5291b24

File tree

5 files changed

+300
-59
lines changed

5 files changed

+300
-59
lines changed

compiler/base/Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ RUN cd / && \
4141
WORKDIR /playground
4242

4343
ADD Cargo.toml /playground/Cargo.toml
44+
ADD cargo.sh /playground/cargo.sh
4445
ADD crate-information.json /playground/crate-information.json
4546
RUN cargo fetch
4647

compiler/base/cargo.sh

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
POSITIONAL=()
6+
7+
while [[ $# -gt 0 ]]; do
8+
case $1 in
9+
--env)
10+
export $2
11+
shift 2
12+
;;
13+
*)
14+
POSITIONAL+=("$1")
15+
shift
16+
;;
17+
esac
18+
done
19+
20+
eval set -- "${POSITIONAL[@]}"
21+
22+
timeout=${PLAYGROUND_TIMEOUT:-10}
23+
24+
modify-cargo-toml
25+
26+
timeout --signal=KILL ${timeout} cargo "$@" || pkill sleep
27+
28+
pkill sleep

compiler/base/entrypoint.sh

+1-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
11
#!/bin/bash
22

3-
set -eu
4-
5-
timeout=${PLAYGROUND_TIMEOUT:-10}
6-
7-
modify-cargo-toml
8-
timeout --signal=KILL ${timeout} "$@"
3+
sleep 365d

ui/src/main.rs

+22-12
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,12 @@ use serde::Serialize;
4949
use serde::de::DeserializeOwned;
5050
use snafu::{ResultExt, Snafu};
5151

52-
use sandbox::Sandbox;
52+
use sandbox::{Channel, DockerContainers, Sandbox};
5353

5454
const DEFAULT_ADDRESS: &str = "127.0.0.1";
5555
const DEFAULT_PORT: u16 = 5000;
5656
const DEFAULT_LOG_FILE: &str = "access-log.csv";
57+
const DEFAULT_DOCKER_CONTAINER_POOL_SIZE: usize = 10;
5758

5859
mod sandbox;
5960
mod asm_cleanup;
@@ -78,6 +79,9 @@ fn main() {
7879
let port = env::var("PLAYGROUND_UI_PORT").ok().and_then(|p| p.parse().ok()).unwrap_or(DEFAULT_PORT);
7980
let logfile = env::var("PLAYGROUND_LOG_FILE").unwrap_or_else(|_| DEFAULT_LOG_FILE.to_string());
8081
let cors_enabled = env::var_os("PLAYGROUND_CORS_ENABLED").is_some();
82+
let docker_containers_pool_size = env::var("DOCKER_CONTAINER_POOL_SIZE").ok().and_then(|v| v.parse().ok()).unwrap_or(DEFAULT_DOCKER_CONTAINER_POOL_SIZE);
83+
84+
let containers = Arc::new(DockerContainers::new(docker_containers_pool_size));
8185

8286
let files = Staticfile::new(&root).expect("Unable to open root directory");
8387
let mut files = Chain::new(files);
@@ -94,8 +98,10 @@ fn main() {
9498

9599
let mut mount = Mount::new();
96100
mount.mount("/", files);
97-
mount.mount("/compile", compile);
98-
mount.mount("/execute", execute);
101+
let containers_clone = containers.clone();
102+
mount.mount("/compile", move |req: &mut Request| compile(req, &containers_clone));
103+
let containers_clone = containers.clone();
104+
mount.mount("/execute", move |req: &mut Request| handle(req, &containers_clone));
99105
mount.mount("/format", format);
100106
mount.mount("/clippy", clippy);
101107
mount.mount("/miri", miri);
@@ -107,7 +113,8 @@ fn main() {
107113
mount.mount("/meta/version/clippy", meta_version_clippy);
108114
mount.mount("/meta/version/miri", meta_version_miri);
109115
mount.mount("/meta/gist", gist_router);
110-
mount.mount("/evaluate.json", evaluate);
116+
let containers_clone = containers.clone();
117+
mount.mount("/evaluate.json", move |req: &mut Request| evaluate(req, &containers_clone));
111118

112119
let mut chain = Chain::new(mount);
113120
let file_logger = FileLogger::new(logfile).expect("Unable to create file logger");
@@ -158,21 +165,23 @@ impl iron::typemap::Key for GhToken {
158165
type Value = Self;
159166
}
160167

161-
fn compile(req: &mut Request) -> IronResult<Response> {
168+
fn compile(req: &mut Request, containers: &DockerContainers) -> IronResult<Response> {
162169
with_sandbox(req, |sandbox, req: CompileRequest| {
163-
let req = try!(req.try_into());
170+
let req: sandbox::CompileRequest = try!(req.try_into());
171+
let container = containers.pop(req.channel).unwrap();
164172
sandbox
165-
.compile(&req)
173+
.compile(&req, &container)
166174
.map(CompileResponse::from)
167175
.eager_context(Compilation)
168176
})
169177
}
170178

171-
fn execute(req: &mut Request) -> IronResult<Response> {
179+
fn handle(req: &mut Request, containers: &DockerContainers) -> IronResult<Response> {
172180
with_sandbox(req, |sandbox, req: ExecuteRequest| {
173-
let req = try!(req.try_into());
181+
let req: sandbox::ExecuteRequest = try!(req.try_into());
182+
let container = containers.pop(req.channel).unwrap();
174183
sandbox
175-
.execute(&req)
184+
.execute(&req, &container)
176185
.map(ExecuteResponse::from)
177186
.eager_context(Execution)
178187
})
@@ -285,11 +294,12 @@ fn meta_gist_get(req: &mut Request) -> IronResult<Response> {
285294

286295
// This is a backwards compatibilty shim. The Rust homepage and the
287296
// documentation use this to run code in place.
288-
fn evaluate(req: &mut Request) -> IronResult<Response> {
297+
fn evaluate(req: &mut Request, containers: &DockerContainers) -> IronResult<Response> {
289298
with_sandbox(req, |sandbox, req: EvaluateRequest| {
290299
let req = req.try_into()?;
300+
let container = containers.pop(Channel::Stable).unwrap();
291301
sandbox
292-
.execute(&req)
302+
.execute(&req, &container)
293303
.map(EvaluateResponse::from)
294304
.eager_context(Evaluation)
295305
})

0 commit comments

Comments
 (0)