Skip to content

Commit b3ecbde

Browse files
authored
Merge pull request #132 from traP-jp/feat/#131-local-judge
✨ fix many(implemented LocalJudge in traopy)
2 parents 6b3403f + a89aaef commit b3ecbde

File tree

26 files changed

+618
-584
lines changed

26 files changed

+618
-584
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ tonic = "0.12.3"
1616
tonic-types = "0.12.3"
1717
tonic-web = "0.12.3"
1818
tonic-build = "0.12.3"
19-
pyo3 = { version = "0.23.4", features = ["extension-module"] }
19+
pyo3 = { version = "0.23.4", features = ["extension-module", "experimental-async"] }
2020
pyo3-stub-gen = "0.7.0"
2121

2222

lib/judge_core/src/job.rs

Lines changed: 33 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,89 +1,56 @@
11
use crate::identifiers::ResourceId;
22
use futures::future::Future;
33
use std::process::Output;
4-
use tokio::sync::broadcast;
54

6-
/// JobAPI is a set of shell environment and cache of outcome files of previous jobs.
7-
///
8-
/// Instances must be initialized once per submission.
9-
pub trait JobApi<JobOutcome: Clone>: Clone {
10-
/// Greater the priority is, sooner the job will be executed.
11-
///
12-
/// Files created by this job will be deleted immediately after all returned JobOutcome are dropped.
13-
///
14-
/// Outer future only creates a kind of reservasion for shell environment and returns inner future synchronously.
15-
fn run_future(
5+
pub trait JobApi<ReservationToken, OutcomeToken: Clone>: Clone {
6+
fn reserve_execution(
167
&self,
17-
job_conf: ExecutionJob<JobOutcome>,
18-
) -> impl Future<
19-
Output = Result<
20-
impl Future<Output = Result<ExecutionJobFinished<JobOutcome>, ExecutionJobError>>,
21-
ExecutionJobPreparationError,
22-
>,
23-
>;
8+
count: usize,
9+
) -> impl Future<Output = Result<Vec<ReservationToken>, ReservationError>>;
2410

2511
fn place_file(
2612
&self,
27-
job_conf: FilePlacementJob,
28-
) -> impl Future<Output = Result<JobOutcome, FilePlacementJobError>>;
29-
}
30-
31-
#[derive(Debug, Clone)]
32-
pub enum ExecutionJobFinished<JobOutcome: Clone> {
33-
/// Job finished successfully.
34-
Succeeded(JobOutcome, Output),
35-
/// Job failed expectedly.
36-
FailedExpectedly((JobOutcome, Output)),
37-
/// Preceding job failed expectedly.
38-
PrecedingJobFailedExpectedly,
39-
}
13+
file_conf: FileConf,
14+
) -> impl Future<Output = Result<OutcomeToken, FilePlacementError>>;
4015

41-
#[derive(Debug, Clone)]
42-
pub enum JobOutcomeAcquisitionResult<JobOutcome: Clone> {
43-
/// Received JobOutcome successfully.
44-
Succeeded(JobOutcome),
45-
/// Failed to receive JobOutcome expectedly.
46-
FailedExpectedly,
47-
/// Failed to receive JobOutcome unexpectedly.
48-
FailedUnexpectedly(String),
49-
}
50-
51-
pub struct JobOutcomeLink<JobOutcome: Clone> {
52-
pub job_outcome_rx: broadcast::Receiver<JobOutcomeAcquisitionResult<JobOutcome>>,
53-
pub envvar_name: String,
16+
fn execute(
17+
&self,
18+
reservation: ReservationToken,
19+
dependencies: Vec<Dependency<OutcomeToken>>,
20+
) -> impl Future<Output = Result<(OutcomeToken, Output), ExecutionError>>;
5421
}
5522

56-
pub struct ExecutionJob<JobOutcome: Clone> {
57-
pub script: String,
58-
pub depends_on_with_names: Vec<JobOutcomeLink<JobOutcome>>,
23+
#[derive(Debug, Clone, thiserror::Error)]
24+
pub enum ReservationError {
25+
#[error("Failed to reserve execution with error: {0}")]
26+
ReserveFailed(String),
5927
}
6028

6129
#[derive(Debug, Clone, thiserror::Error)]
62-
pub enum ExecutionJobPreparationError {
63-
#[error("Internal error while preparing a job: {0}")]
64-
InternalError(String),
30+
pub enum FilePlacementError {
31+
#[error("Failed to place file with error: {0}")]
32+
PlaceFailed(String),
33+
#[error("Invalid resource ID: {0}")]
34+
InvalidResourceId(ResourceId),
6535
}
6636

6737
#[derive(Debug, Clone, thiserror::Error)]
68-
pub enum ExecutionJobError {
69-
#[error("Internal error while running a job: {0}")]
38+
pub enum ExecutionError {
39+
#[error("Internal error while executing a job: {0}")]
7040
InternalError(String),
71-
#[error("Preceding job failed unexpectedly: {0}")]
72-
PrecedingJobFailed(String),
41+
#[error("Judge process failed with error: {0}")]
42+
JudgeFailed(String),
7343
}
7444

75-
pub enum FilePlacementJob {
76-
PlaceEmptyDirectory,
77-
/// Content of the text file
78-
PlaceRuntimeTextFile(String),
79-
/// Global project-wide unique identifier
80-
PlaceTextFile(ResourceId),
45+
#[derive(Debug, Clone)]
46+
pub enum FileConf {
47+
EmptyDirectory,
48+
Text(ResourceId),
49+
RuntimeText(String),
8150
}
8251

83-
#[derive(Debug, thiserror::Error)]
84-
pub enum FilePlacementJobError {
85-
#[error("Invalid resource id: {0}")]
86-
InvalidResourceId(ResourceId),
87-
#[error("Internal error while placing a file: {0}")]
88-
InternalError(String),
52+
#[derive(Debug, Clone)]
53+
pub struct Dependency<OutcomeToken> {
54+
pub envvar: String,
55+
pub outcome: OutcomeToken,
8956
}

lib/judge_core/src/judge_output.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,53 +11,58 @@ pub enum JudgeStatus {
1111
CE,
1212
}
1313

14-
#[derive(Debug, Clone, Serialize, Deserialize)]
14+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
1515
pub enum ContinueStatus {
1616
Continue,
1717
Stop,
1818
}
1919

2020
#[derive(Debug, Clone, Serialize, Deserialize)]
21-
pub struct DisplayableJudgeResult {
21+
pub struct DisplayableExecutionResult {
2222
pub status: JudgeStatus,
2323
pub time: f64,
2424
pub memory: f64,
2525
pub score: i64,
2626
pub message: Option<String>,
27-
pub continue_status: ContinueStatus,
2827
}
2928

3029
/// This returns from exec container as stdout
3130
#[derive(Debug, Clone, Serialize, Deserialize)]
32-
pub enum JudgeReport {
31+
pub enum ExecutionResult {
3332
/// Frontend-displayable execution result
34-
Displayable(DisplayableJudgeResult),
33+
Displayable(DisplayableExecutionResult),
3534
/// Not displayed to frontend (e.g. for validation)
3635
Hidden,
3736
}
3837

38+
#[derive(Debug, Clone, Serialize, Deserialize)]
39+
pub struct ExecutionReport {
40+
pub result: ExecutionResult,
41+
pub continue_status: ContinueStatus,
42+
}
43+
3944
/// This is the final response from judge
4045
#[derive(Debug, Clone, Serialize, Deserialize)]
4146
pub enum ExecutionResponse {
42-
Report(JudgeReport),
47+
Report(ExecutionReport),
4348
EarlyExit,
44-
Error(String),
4549
}
4650

4751
#[derive(Debug, Clone, thiserror::Error)]
48-
pub enum JudgeOutputParseError {
52+
pub enum ExecutionOutputParseError {
4953
#[error("Invalid JSON: {0}")]
5054
InvalidJson(String),
5155
#[error("Non-zero exit code")]
5256
NonZeroExitCode,
5357
}
5458

55-
pub fn parse(output: &std::process::Output) -> Result<JudgeReport, JudgeOutputParseError> {
56-
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
59+
pub fn parse(output: &std::process::Output) -> Result<ExecutionReport, ExecutionOutputParseError> {
60+
let stdout = String::from_utf8(output.stdout.clone())
61+
.map_err(|e| ExecutionOutputParseError::InvalidJson(e.to_string()))?;
5762
if !output.status.success() {
58-
return Err(JudgeOutputParseError::NonZeroExitCode);
63+
return Err(ExecutionOutputParseError::NonZeroExitCode);
5964
}
60-
let judge_report: JudgeReport = serde_json::from_str(&stdout)
61-
.map_err(|e| JudgeOutputParseError::InvalidJson(e.to_string()))?;
62-
Ok(judge_report)
65+
let execution_report: ExecutionReport = serde_json::from_str(&stdout)
66+
.map_err(|e| ExecutionOutputParseError::InvalidJson(e.to_string()))?;
67+
Ok(execution_report)
6368
}

lib/judge_core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ pub mod job;
33
pub mod judge_output;
44
pub mod problem_registry;
55
pub mod procedure;
6+
pub mod registered_procedure_converter;
67
pub mod runner;
78
pub mod writer_schema_transpiler;

lib/judge_core/src/problem_registry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub trait ProblemRegistryServer {
1717
}
1818

1919
/// ProblemRegistryClient fetches contents of problems from the registry in judge server.
20-
pub trait ProblemRegistryClient {
20+
pub trait ProblemRegistryClient: Clone {
2121
fn fetch(
2222
&self,
2323
resource_id: ResourceId,

lib/judge_core/src/procedure/registered.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,37 @@
11
use crate::identifiers::{DepId, ResourceId};
22

3+
#[derive(Debug, Clone)]
34
pub struct Procedure {
45
pub runtime_texts: Vec<RuntimeText>,
56
pub texts: Vec<Text>,
67
pub empty_directories: Vec<EmptyDirectory>,
78
pub executions: Vec<Execution>,
89
}
910

11+
#[derive(Debug, Clone)]
1012
pub struct RuntimeText {
1113
pub label: String,
1214
pub dep_id: DepId,
1315
}
1416

17+
#[derive(Debug, Clone)]
1518
pub struct Text {
1619
pub resource_id: ResourceId,
1720
pub dep_id: DepId,
1821
}
1922

23+
#[derive(Debug, Clone)]
2024
pub struct EmptyDirectory {
2125
pub dep_id: DepId,
2226
}
2327

28+
#[derive(Debug, Clone)]
2429
pub struct Execution {
25-
pub script: String,
2630
pub depends_on: Vec<DependsOn>,
2731
pub dep_id: DepId,
2832
}
2933

34+
#[derive(Debug, Clone)]
3035
pub struct DependsOn {
3136
pub dep_id: DepId,
3237
pub envvar_name: String,

lib/judge_core/src/procedure/runtime.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,37 @@
11
use crate::identifiers::{ResourceId, RuntimeId};
22

3+
#[derive(Debug, Clone)]
34
pub struct Procedure {
45
pub runtime_texts: Vec<RuntimeText>,
56
pub texts: Vec<Text>,
67
pub empty_directories: Vec<EmptyDirectory>,
78
pub executions: Vec<Execution>,
89
}
910

11+
#[derive(Debug, Clone)]
1012
pub struct RuntimeText {
1113
pub content: String,
1214
pub runtime_id: RuntimeId,
1315
}
1416

17+
#[derive(Debug, Clone)]
1518
pub struct Text {
1619
pub resource_id: ResourceId,
1720
pub runtime_id: RuntimeId,
1821
}
1922

23+
#[derive(Debug, Clone)]
2024
pub struct EmptyDirectory {
2125
pub runtime_id: RuntimeId,
2226
}
2327

28+
#[derive(Debug, Clone)]
2429
pub struct Execution {
25-
pub script: String,
2630
pub depends_on: Vec<DependsOn>,
2731
pub runtime_id: RuntimeId,
2832
}
2933

34+
#[derive(Debug, Clone)]
3035
pub struct DependsOn {
3136
pub runtime_id: RuntimeId,
3237
pub envvar_name: String,

lib/judge_core/src/procedure/writer_schema.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
44
pub struct Procedure {
55
pub resources: Vec<ResourceKind>,
66
pub executions: Vec<Execution>,
7-
pub scripts: Vec<Script>,
7+
pub scripts: Vec<Text>,
88
}
99

1010
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -38,12 +38,6 @@ pub struct RuntimeText {
3838
pub label: String,
3939
}
4040

41-
#[derive(Debug, Clone, Serialize, Deserialize)]
42-
pub struct Script {
43-
pub content: String,
44-
pub name: String,
45-
}
46-
4741
#[derive(Debug, Clone, Serialize, Deserialize)]
4842
pub struct Text {
4943
pub name: String,

0 commit comments

Comments
 (0)