Skip to content

Commit 73199ee

Browse files
author
Tom Dyas
authored
refactor Core::new including command runner setup (#10993)
### Problem Core::new is a very convoluted function and it is hard to read what is actually going on in it. ### Solution Refactor the store and command runner setup into separate functions. (Also refactors the load of some certificates.) This refactor will make the subsequent introduction of remote caching in #10960 easier to comprehend. ### Result Existing tests pass.
1 parent bf62b0a commit 73199ee

File tree

1 file changed

+223
-133
lines changed

1 file changed

+223
-133
lines changed

src/rust/engine/src/context.rs

+223-133
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,204 @@ pub struct ExecutionStrategyOptions {
9999
}
100100

101101
impl Core {
102+
fn make_store(
103+
executor: &Executor,
104+
local_store_dir: &Path,
105+
enable_remote: bool,
106+
remoting_opts: &RemotingOptions,
107+
remote_store_servers: &[String],
108+
root_ca_certs: &Option<Vec<u8>>,
109+
oauth_bearer_token: &Option<String>,
110+
) -> Result<Store, String> {
111+
if enable_remote {
112+
Store::with_remote(
113+
executor.clone(),
114+
local_store_dir,
115+
remote_store_servers.to_vec(),
116+
remoting_opts.instance_name.clone(),
117+
root_ca_certs.clone(),
118+
oauth_bearer_token.clone(),
119+
remoting_opts.store_thread_count,
120+
remoting_opts.store_chunk_bytes,
121+
remoting_opts.store_chunk_upload_timeout,
122+
// TODO: Take a parameter
123+
store::BackoffConfig::new(Duration::from_millis(10), 1.0, Duration::from_millis(10))
124+
.unwrap(),
125+
remoting_opts.store_rpc_retries,
126+
remoting_opts.store_connection_limit,
127+
)
128+
} else {
129+
Store::local_only(executor.clone(), local_store_dir.to_path_buf())
130+
}
131+
}
132+
133+
fn make_local_execution_runner(
134+
store: &Store,
135+
executor: &Executor,
136+
local_execution_root_dir: &Path,
137+
named_caches_dir: &Path,
138+
process_execution_metadata: &ProcessMetadata,
139+
exec_strategy_opts: &ExecutionStrategyOptions,
140+
) -> Box<dyn CommandRunner> {
141+
let local_command_runner = process_execution::local::CommandRunner::new(
142+
store.clone(),
143+
executor.clone(),
144+
local_execution_root_dir.to_path_buf(),
145+
NamedCaches::new(named_caches_dir.to_path_buf()),
146+
exec_strategy_opts.cleanup_local_dirs,
147+
);
148+
149+
let maybe_nailgunnable_local_command_runner: Box<dyn process_execution::CommandRunner> =
150+
if exec_strategy_opts.local_enable_nailgun {
151+
Box::new(process_execution::nailgun::CommandRunner::new(
152+
local_command_runner,
153+
process_execution_metadata.clone(),
154+
local_execution_root_dir.to_path_buf(),
155+
executor.clone(),
156+
))
157+
} else {
158+
Box::new(local_command_runner)
159+
};
160+
161+
Box::new(BoundedCommandRunner::new(
162+
maybe_nailgunnable_local_command_runner,
163+
exec_strategy_opts.local_parallelism,
164+
))
165+
}
166+
167+
fn make_remote_execution_runner(
168+
store: &Store,
169+
process_execution_metadata: &ProcessMetadata,
170+
remoting_opts: &RemotingOptions,
171+
root_ca_certs: &Option<Vec<u8>>,
172+
oauth_bearer_token: &Option<String>,
173+
) -> Result<Box<dyn CommandRunner>, String> {
174+
Ok(Box::new(process_execution::remote::CommandRunner::new(
175+
// No problem unwrapping here because the global options validation
176+
// requires the remoting_opts.execution_server be present when
177+
// remoting_opts.execution_enable is set.
178+
&remoting_opts.execution_server.clone().unwrap(),
179+
remoting_opts.store_servers.clone(),
180+
process_execution_metadata.clone(),
181+
root_ca_certs.clone(),
182+
oauth_bearer_token.clone(),
183+
remoting_opts.execution_headers.clone(),
184+
store.clone(),
185+
// TODO if we ever want to configure the remote platform to be something else we
186+
// need to take an option all the way down here and into the remote::CommandRunner struct.
187+
Platform::Linux,
188+
remoting_opts.execution_overall_deadline,
189+
Duration::from_millis(100),
190+
)?))
191+
}
192+
193+
fn make_command_runner(
194+
store: &Store,
195+
executor: &Executor,
196+
local_execution_root_dir: &Path,
197+
named_caches_dir: &Path,
198+
local_store_dir: &Path,
199+
process_execution_metadata: &ProcessMetadata,
200+
root_ca_certs: &Option<Vec<u8>>,
201+
oauth_bearer_token: &Option<String>,
202+
exec_strategy_opts: &ExecutionStrategyOptions,
203+
remoting_opts: &RemotingOptions,
204+
) -> Result<Box<dyn CommandRunner>, String> {
205+
let local_command_runner = Core::make_local_execution_runner(
206+
store,
207+
executor,
208+
local_execution_root_dir,
209+
named_caches_dir,
210+
process_execution_metadata,
211+
&exec_strategy_opts,
212+
);
213+
214+
let command_runner: Box<dyn CommandRunner> = if remoting_opts.execution_enable {
215+
let remote_command_runner: Box<dyn process_execution::CommandRunner> = {
216+
Box::new(BoundedCommandRunner::new(
217+
Core::make_remote_execution_runner(
218+
store,
219+
process_execution_metadata,
220+
&remoting_opts,
221+
root_ca_certs,
222+
oauth_bearer_token,
223+
)?,
224+
exec_strategy_opts.remote_parallelism,
225+
))
226+
};
227+
228+
match exec_strategy_opts.speculation_strategy.as_ref() {
229+
"local_first" => Box::new(SpeculatingCommandRunner::new(
230+
local_command_runner,
231+
remote_command_runner,
232+
exec_strategy_opts.speculation_delay,
233+
)),
234+
"remote_first" => Box::new(SpeculatingCommandRunner::new(
235+
remote_command_runner,
236+
local_command_runner,
237+
exec_strategy_opts.speculation_delay,
238+
)),
239+
"none" => remote_command_runner,
240+
_ => unreachable!(),
241+
}
242+
} else {
243+
local_command_runner
244+
};
245+
246+
let maybe_cached_command_runner = if exec_strategy_opts.use_local_cache {
247+
let process_execution_store = ShardedLmdb::new(
248+
local_store_dir.join("processes"),
249+
5 * GIGABYTES,
250+
executor.clone(),
251+
DEFAULT_LEASE_TIME,
252+
)
253+
.map_err(|err| format!("Could not initialize store for process cache: {:?}", err))?;
254+
Box::new(process_execution::cache::CommandRunner::new(
255+
command_runner.into(),
256+
process_execution_store,
257+
store.clone(),
258+
process_execution_metadata.clone(),
259+
))
260+
} else {
261+
command_runner
262+
};
263+
264+
Ok(maybe_cached_command_runner)
265+
}
266+
267+
fn load_certificates(
268+
ca_certs_path: Option<PathBuf>,
269+
) -> Result<Vec<reqwest::Certificate>, String> {
270+
let certs = match ca_certs_path {
271+
Some(ref path) => {
272+
let mut content = String::new();
273+
std::fs::File::open(path)
274+
.and_then(|mut f| f.read_to_string(&mut content))
275+
.map_err(|err| {
276+
format!(
277+
"Error reading root CA certs file {}: {}",
278+
path.display(),
279+
err
280+
)
281+
})?;
282+
let pem_re = Regex::new(PEM_RE_STR).unwrap();
283+
let certs_res: Result<Vec<reqwest::Certificate>, _> = pem_re
284+
.find_iter(&content)
285+
.map(|mat| reqwest::Certificate::from_pem(mat.as_str().as_bytes()))
286+
.collect();
287+
certs_res.map_err(|err| {
288+
format!(
289+
"Error parsing PEM from root CA certs file {}: {}",
290+
path.display(),
291+
err
292+
)
293+
})?
294+
}
295+
None => Vec::new(),
296+
};
297+
Ok(certs)
298+
}
299+
102300
pub fn new(
103301
executor: Executor,
104302
tasks: Tasks,
@@ -146,152 +344,44 @@ impl Core {
146344
None
147345
};
148346

149-
let local_store_dir2 = local_store_dir.clone();
150347
let store = safe_create_dir_all_ioerror(&local_store_dir)
151348
.map_err(|e| format!("Error making directory {:?}: {:?}", local_store_dir, e))
152349
.and_then(|_| {
153-
if !remoting_opts.execution_enable || remote_store_servers.is_empty() {
154-
Store::local_only(executor.clone(), local_store_dir)
155-
} else {
156-
Store::with_remote(
157-
executor.clone(),
158-
local_store_dir,
159-
remote_store_servers,
160-
remoting_opts.instance_name.clone(),
161-
root_ca_certs.clone(),
162-
oauth_bearer_token.clone(),
163-
remoting_opts.store_thread_count,
164-
remoting_opts.store_chunk_bytes,
165-
remoting_opts.store_chunk_upload_timeout,
166-
// TODO: Take a parameter
167-
store::BackoffConfig::new(Duration::from_millis(10), 1.0, Duration::from_millis(10))
168-
.unwrap(),
169-
remoting_opts.store_rpc_retries,
170-
remoting_opts.store_connection_limit,
171-
)
172-
}
350+
Core::make_store(
351+
&executor,
352+
&local_store_dir,
353+
remoting_opts.execution_enable && !remote_store_servers.is_empty(),
354+
&remoting_opts,
355+
&remote_store_servers,
356+
&root_ca_certs,
357+
&oauth_bearer_token,
358+
)
173359
})
174360
.map_err(|e| format!("Could not initialize Store: {:?}", e))?;
175361

176362
let process_execution_metadata = ProcessMetadata {
177-
instance_name: remoting_opts.instance_name,
178-
cache_key_gen_version: remoting_opts.execution_process_cache_namespace,
179-
platform_properties: remoting_opts.execution_extra_platform_properties,
363+
instance_name: remoting_opts.instance_name.clone(),
364+
cache_key_gen_version: remoting_opts.execution_process_cache_namespace.clone(),
365+
platform_properties: remoting_opts.execution_extra_platform_properties.clone(),
180366
};
181367

182-
let local_command_runner = process_execution::local::CommandRunner::new(
183-
store.clone(),
184-
executor.clone(),
185-
local_execution_root_dir.clone(),
186-
NamedCaches::new(named_caches_dir),
187-
exec_strategy_opts.cleanup_local_dirs,
188-
);
189-
190-
let maybe_nailgunnable_local_command_runner: Box<dyn process_execution::CommandRunner> =
191-
if exec_strategy_opts.local_enable_nailgun {
192-
Box::new(process_execution::nailgun::CommandRunner::new(
193-
local_command_runner,
194-
process_execution_metadata.clone(),
195-
local_execution_root_dir,
196-
executor.clone(),
197-
))
198-
} else {
199-
Box::new(local_command_runner)
200-
};
201-
202-
let mut command_runner: Box<dyn process_execution::CommandRunner> =
203-
Box::new(BoundedCommandRunner::new(
204-
maybe_nailgunnable_local_command_runner,
205-
exec_strategy_opts.local_parallelism,
206-
));
207-
208-
if remoting_opts.execution_enable {
209-
let remote_command_runner: Box<dyn process_execution::CommandRunner> = {
210-
let command_runner: Box<dyn CommandRunner> = {
211-
Box::new(process_execution::remote::CommandRunner::new(
212-
// No problem unwrapping here because the global options validation
213-
// requires the remoting_opts.execution_server be present when
214-
// remoting_opts.execution_enable is set.
215-
&remoting_opts.execution_server.unwrap(),
216-
remoting_opts.store_servers.clone(),
217-
process_execution_metadata.clone(),
218-
root_ca_certs,
219-
oauth_bearer_token,
220-
remoting_opts.execution_headers,
221-
store.clone(),
222-
// TODO if we ever want to configure the remote platform to be something else we
223-
// need to take an option all the way down here and into the remote::CommandRunner struct.
224-
Platform::Linux,
225-
remoting_opts.execution_overall_deadline,
226-
Duration::from_millis(100),
227-
)?)
228-
};
368+
let command_runner = Core::make_command_runner(
369+
&store,
370+
&executor,
371+
&local_execution_root_dir,
372+
&named_caches_dir,
373+
&local_store_dir,
374+
&process_execution_metadata,
375+
&root_ca_certs,
376+
&oauth_bearer_token,
377+
&exec_strategy_opts,
378+
&remoting_opts,
379+
)?;
229380

230-
Box::new(BoundedCommandRunner::new(
231-
command_runner,
232-
exec_strategy_opts.remote_parallelism,
233-
))
234-
};
235-
command_runner = match exec_strategy_opts.speculation_strategy.as_ref() {
236-
"local_first" => Box::new(SpeculatingCommandRunner::new(
237-
command_runner,
238-
remote_command_runner,
239-
exec_strategy_opts.speculation_delay,
240-
)),
241-
"remote_first" => Box::new(SpeculatingCommandRunner::new(
242-
remote_command_runner,
243-
command_runner,
244-
exec_strategy_opts.speculation_delay,
245-
)),
246-
"none" => remote_command_runner,
247-
_ => unreachable!(),
248-
};
249-
}
250-
251-
if exec_strategy_opts.use_local_cache {
252-
let process_execution_store = ShardedLmdb::new(
253-
local_store_dir2.join("processes"),
254-
5 * GIGABYTES,
255-
executor.clone(),
256-
DEFAULT_LEASE_TIME,
257-
)
258-
.map_err(|err| format!("Could not initialize store for process cache: {:?}", err))?;
259-
command_runner = Box::new(process_execution::cache::CommandRunner::new(
260-
command_runner.into(),
261-
process_execution_store,
262-
store.clone(),
263-
process_execution_metadata,
264-
));
265-
}
266381
let graph = Arc::new(InvalidatableGraph(Graph::new()));
267382

268383
// These certs are for downloads, not to be confused with the ones used for remoting.
269-
let ca_certs = if let Some(ref path) = ca_certs_path {
270-
let mut content = String::new();
271-
std::fs::File::open(path)
272-
.and_then(|mut f| f.read_to_string(&mut content))
273-
.map_err(|err| {
274-
format!(
275-
"Error reading root CA certs file {}: {}",
276-
path.display(),
277-
err
278-
)
279-
})?;
280-
let pem_re = Regex::new(PEM_RE_STR).unwrap();
281-
let certs_res: Result<Vec<reqwest::Certificate>, _> = pem_re
282-
.find_iter(&content)
283-
.map(|mat| reqwest::Certificate::from_pem(mat.as_str().as_bytes()))
284-
.collect();
285-
certs_res.map_err(|err| {
286-
format!(
287-
"Error parsing PEM from root CA certs file {}: {}",
288-
path.display(),
289-
err
290-
)
291-
})?
292-
} else {
293-
Vec::new()
294-
};
384+
let ca_certs = Core::load_certificates(ca_certs_path)?;
295385

296386
let http_client_builder = ca_certs
297387
.iter()

0 commit comments

Comments
 (0)