Skip to content

Commit

Permalink
refactor: ♻️ refactor container and container daemon
Browse files Browse the repository at this point in the history
  • Loading branch information
Eason0729 committed Dec 20, 2023
1 parent b145680 commit 645b020
Show file tree
Hide file tree
Showing 12 changed files with 117 additions and 119 deletions.
2 changes: 1 addition & 1 deletion judger/src/init/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn init() {
if config.platform.output_limit >= config.platform.available_memory.try_into().unwrap() {
log::error!("config.platform.output_limit is too larget or config.platform.available_memory is too low");
std::process::exit(1);
}
}

if config.platform.output_limit * 8 >= config.platform.available_memory.try_into().unwrap() {
log::warn!("config.platform.output_limit is consider too high");
Expand Down
2 changes: 1 addition & 1 deletion judger/src/init/logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ pub fn init() {
)
})
.filter(Some("judger"), level)
.init();
.try_init().ok();
}
141 changes: 64 additions & 77 deletions judger/src/langs/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,11 @@ impl ArtifactFactory {

let mut process = container
.execute(
spec.compile_args
&spec
.compile_args
.iter()
.map(|x| x.as_str())
.collect::<Vec<&str>>(),
.collect::<Vec<_>>(),
spec.compile_limit.clone().apply_platform(),
)
.await?;
Expand All @@ -83,17 +84,21 @@ impl ArtifactFactory {

let process = process.wait().await?;

if !process.succeed() {
#[cfg(debug_assertions)]
log::warn!("{}", process.status);
return Ok(CompiledArtifact::Fail(process));
}

Ok(CompiledArtifact::Success(CompiledInner {
container,
// if !process.succeed() {
// #[cfg(debug_assertions)]
// log::warn!("{}", process.status);
// return Ok(CompiledArtifact{
// process,
// spec,
// container:None
// });
// }

Ok(CompiledArtifact {
process,
spec,
stdout: process.stdout,
}))
container,
})
}
}

Expand All @@ -117,7 +122,7 @@ impl CompileLog {
/// parse log from raw string, slient error(generate blank message) when malformatted
///
/// according to plugin specification, log should be in following format
///
///
/// ```text
/// 0:trace message
/// 1:debug message
Expand Down Expand Up @@ -146,55 +151,36 @@ impl CompileLog {
}

/// Wrapper for container which contain compiled program in its volume
///
///
/// TODO: CompiledInner<'a> was actually derive from ExitProc, consider remove CompiledInner<'a>
/// and replace it with ExitProc
pub enum CompiledArtifact<'a> {
Fail(ExitProc),
Success(CompiledInner<'a>),
pub struct CompiledArtifact<'a> {
process: ExitProc,
container: Container<'a>,
spec: &'a LangSpec,
}

impl<'a> CompiledArtifact<'a> {
/// get JudgerCode if the task is surely at state neither AC or WA
pub fn get_expection(&self) -> Option<JudgerCode> {
match self {
CompiledArtifact::Fail(_) => Some(JudgerCode::Ce),
CompiledArtifact::Success(_) => None,
if !self.process.succeed() {
Some(JudgerCode::Ce)
} else {
None
}
}
pub fn log(&'a self) -> Box<dyn Iterator<Item = CompileLog> + 'a + Send> {
match self {
CompiledArtifact::Fail(proc) => Box::new(
proc.stdout
.split(|x| *x == b'\n')
.filter_map(|x| match x.is_empty() {
true => None,
false => Some(CompileLog::from_raw(x)),
}),
),
CompiledArtifact::Success(inner) => Box::new(
inner
.stdout
.split(|x| *x == b'\n')
.filter_map(|x| match x.is_empty() {
true => None,
false => Some(CompileLog::from_raw(x)),
}),
),
}
}
fn inner(&mut self) -> Option<&mut CompiledInner<'a>> {
match self {
CompiledArtifact::Fail(_) => None,
CompiledArtifact::Success(x) => Some(x),
}
Box::new(
self.process
.stdout
.split(|x| *x == b'\n')
.filter_map(|x| match x.is_empty() {
true => None,
false => Some(CompileLog::from_raw(x)),
}),
)
}
}
pub struct CompiledInner<'a> {
container: Container<'a>,
spec: &'a LangSpec,
stdout: Vec<u8>,
}

impl<'a> CompiledArtifact<'a> {
// run compiled program with input and limit
Expand All @@ -204,21 +190,21 @@ impl<'a> CompiledArtifact<'a> {
time: u64,
memory: u64,
) -> Result<TaskResult, Error> {
let inner = self.inner().unwrap();
let mut limit = inner.spec.judge_limit.clone().apply_platform();
debug_assert!(self.process.succeed());
let spec = self.spec;
let mut limit = spec.judge_limit.clone().apply_platform();

limit.cpu_us *= time;
limit.user_mem *= memory;

let mut process = inner
let mut process = self
.container
.execute(
inner
.spec
&spec
.judge_args
.iter()
.map(|x| x.as_str())
.collect::<Vec<&str>>(),
.collect::<Vec<_>>(),
limit,
)
.await?;
Expand All @@ -227,6 +213,7 @@ impl<'a> CompiledArtifact<'a> {

let process = process.wait().await?;

// TODO: We should handle SysError here
if !process.succeed() {
// log::debug!("process status: {:?}", process.status);
return Ok(TaskResult::Fail(JudgerCode::Re));
Expand All @@ -240,21 +227,21 @@ impl<'a> CompiledArtifact<'a> {
time: u64,
memory: u64,
) -> Result<ExecResult, Error> {
let inner = self.inner().unwrap();
let mut limit = inner.spec.judge_limit.clone().apply_platform();
debug_assert!(self.process.succeed());
let spec = self.spec;
let mut limit = spec.judge_limit.clone().apply_platform();

limit.cpu_us *= time;
limit.user_mem *= memory;

let mut process = inner
let mut process = self
.container
.execute(
inner
.spec
&spec
.judge_args
.iter()
.map(|x| x.as_str())
.collect::<Vec<&str>>(),
.collect::<Vec<_>>(),
limit,
)
.await?;
Expand All @@ -263,27 +250,29 @@ impl<'a> CompiledArtifact<'a> {

let process = process.wait().await?;

Ok(ExecResult { process })
Ok(ExecResult(process))
}
}

pub struct ExecResult {
process: ExitProc,
}
/// Wrapper for result of process(ended exec process)
///
/// provide information about process's exitcode, stdout, stderr
pub struct ExecResult(ExitProc);

impl ExecResult {
pub fn time(&self) -> &CpuStatistics {
&self.process.cpu
&self.0.cpu
}
pub fn mem(&self) -> &MemStatistics {
&self.process.mem
&self.0.mem
}
pub fn stdout(&self) -> &[u8] {
&self.process.stdout
&self.0.stdout
}
}
// Wrapper for result of process(ended judge process)
// provide information about process's exitcode, resource usage, stdout, stderr
/// Wrapper for result of process(ended judge process)
///
/// provide abliity to report resource usage, exit status, AC or WA
pub enum TaskResult {
Fail(JudgerCode),
Success(ExitProc),
Expand All @@ -296,17 +285,12 @@ impl TaskResult {
TaskResult::Success(x) => Some(x),
}
}
}

impl TaskResult {
pub fn process(&self) -> Option<&ExitProc> {
match self {
TaskResult::Fail(_) => None,
TaskResult::Success(x) => Some(x),
}
}
}
impl TaskResult {
/// get JudgerCode if the task is surely at state neither AC or WA
pub fn get_expection(&mut self) -> Option<JudgerCode> {
match self {
Expand All @@ -328,6 +312,7 @@ impl TaskResult {
},
}
}
// determine whether the output(stdout) match
pub fn assert(&mut self, input: &[u8], mode: JudgeMatchRule) -> bool {
let newline = b'\n';
let space = b' ';
Expand All @@ -353,9 +338,11 @@ impl TaskResult {
}
}
}
pub fn time(&self) -> &CpuStatistics {
/// get cpu statistics
pub fn cpu(&self) -> &CpuStatistics {
&self.process().unwrap().cpu
}
/// get memory statistics
pub fn mem(&self) -> &MemStatistics {
&self.process().unwrap().mem
}
Expand Down
2 changes: 1 addition & 1 deletion judger/src/langs/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::sandbox::Limit;

use super::InitError;

// Language specification
/// Language specification
pub struct LangSpec {
pub info: String,
pub extension: String,
Expand Down
2 changes: 1 addition & 1 deletion judger/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use grpc::prelude::judger_server::JudgerServer;
use init::config::CONFIG;

pub mod grpc;
pub mod server;
pub mod init;
pub mod langs;
pub mod sandbox;
pub mod server;
pub mod test;

#[tokio::main]
Expand Down
19 changes: 5 additions & 14 deletions judger/src/sandbox/container.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use crate::{

use super::{daemon::ContainerDaemon, process::RunningProc, Error, Limit};

/// cgroup counter
///
/// The first container would be mount at /sys/fs/cgroup/mdoj/0
static CG_COUNTER: AtomicUsize = AtomicUsize::new(0);

// Container abstraction, call nsjail to execute process, limiter to limit resources
Expand All @@ -31,19 +34,7 @@ impl<'a> Drop for Container<'a> {
}

impl<'a> Container<'a> {
pub async fn new(
id: String,
daemon: &'a ContainerDaemon,
root: PathBuf,
) -> Result<Container<'a>, Error> {
let container_root = daemon.tmp.join(id.clone());

fs::create_dir(container_root.clone()).await?;
fs::create_dir(container_root.clone().join("src")).await?;

Ok(Container { id, daemon, root })
}
pub async fn execute(&self, args: Vec<&str>, limit: Limit) -> Result<RunningProc, Error> {
pub async fn execute(&self, args: &[&str], limit: Limit) -> Result<RunningProc, Error> {
let config = CONFIG.get().unwrap();

log::trace!("Preparing container with id :{} for new process", self.id);
Expand Down Expand Up @@ -71,7 +62,7 @@ impl<'a> Container<'a> {
.done()
.common()
.cmds(args)
.build()?;
.build()?;

let limiter = Limiter::new(&cg_name, limit)?;

Expand Down
Loading

0 comments on commit 645b020

Please sign in to comment.