feat: unify argument passing and errors in runner
This commit is contained in:
parent
81b42f782e
commit
bb53ae280f
@ -19,7 +19,7 @@ func (h *handler) Build(_ context.Context, t *asynq.Task) error {
|
||||
}
|
||||
|
||||
h.log.Debug("build", zap.Any("payload", p))
|
||||
meta := runner.JudgeMeta{Version: p.ProblemVersionID}
|
||||
meta := runner.JudgeMeta{Run: runner.JudgeMetaRun{Version: p.ProblemVersionID}}
|
||||
|
||||
status, ctx := func() (e.Status, string) {
|
||||
url, status := h.storageService.Get(p.StorageKey, time.Second*60*5)
|
||||
|
@ -15,6 +15,14 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
statusSystemError = runner.JudgeStatus{
|
||||
Message: "System Error",
|
||||
CompileMessage: "",
|
||||
Tasks: []runner.TaskStatus{{Verdict: runner.VerdictSystemError, Message: "System Error"}},
|
||||
}
|
||||
)
|
||||
|
||||
func (h *handler) Judge(_ context.Context, t *asynq.Task) error {
|
||||
var p model.SubmitJudgePayload
|
||||
if err := json.Unmarshal(t.Payload(), &p); err != nil {
|
||||
@ -23,45 +31,59 @@ func (h *handler) Judge(_ context.Context, t *asynq.Task) error {
|
||||
|
||||
user := utils.RandomString(16)
|
||||
h.log.Debug("judge", zap.Any("payload", p), zap.String("user", user))
|
||||
meta := runner.JudgeMeta{Version: p.ProblemVersionID, User: user, Lang: p.Submission.Language}
|
||||
|
||||
SystemError := &runner.JudgeStatus{
|
||||
Message: "System Error",
|
||||
Tasks: []runner.TaskStatus{{Verdict: runner.VerdictSystemError, Message: "API Error"}},
|
||||
meta := runner.JudgeMeta{
|
||||
Run: runner.JudgeMetaRun{
|
||||
Version: p.ProblemVersionID,
|
||||
User: user,
|
||||
Lang: p.Submission.Language,
|
||||
},
|
||||
}
|
||||
|
||||
status, point, ctx := func() (e.Status, int32, *runner.JudgeStatus) {
|
||||
|
||||
// 1. write user code
|
||||
userCode := filepath.Join(runner.UserDir, user, fmt.Sprintf("%s.%s", user, p.Submission.Language))
|
||||
if !file.Touch(userCode) {
|
||||
return e.InternalError, 0, SystemError
|
||||
return e.InternalError, 0, &statusSystemError
|
||||
}
|
||||
err := file.Write(userCode, []byte(p.Submission.Code))
|
||||
if err != nil {
|
||||
return e.InternalError, 0, SystemError
|
||||
return e.InternalError, 0, &statusSystemError
|
||||
}
|
||||
|
||||
// 2. check problem
|
||||
if !h.runnerService.ProblemExists(&meta) {
|
||||
url, status := h.storageService.Get(p.StorageKey, time.Second*60*5)
|
||||
if status != e.Success {
|
||||
return status, 0, SystemError
|
||||
return status, 0, &statusSystemError
|
||||
}
|
||||
|
||||
_, status = h.runnerService.NewProblem(&meta, url, false)
|
||||
if status != e.Success {
|
||||
return status, 0, SystemError
|
||||
return status, 0, &statusSystemError
|
||||
}
|
||||
}
|
||||
|
||||
// 3. compile
|
||||
// 3. validate
|
||||
if ret, status := h.runnerService.ValidatePath(&meta); status != e.Success {
|
||||
return status, 0, ret
|
||||
}
|
||||
|
||||
// 4. extract config
|
||||
if status := h.runnerService.GetConfig(&meta, true); status != e.Success {
|
||||
return e.RunnerProblemParseFailed, 0, &runner.JudgeStatus{
|
||||
Message: fmt.Sprintf("System Error: Problem Malformed (%d:%s)", status, status.String()),
|
||||
CompileMessage: "",
|
||||
Tasks: []runner.TaskStatus{{Verdict: runner.VerdictSystemError, Message: "System Error"}},
|
||||
}
|
||||
}
|
||||
|
||||
// 5. compile
|
||||
compileResult, status := h.runnerService.Compile(&meta)
|
||||
if status != e.Success {
|
||||
return status, 0, compileResult
|
||||
}
|
||||
|
||||
// 4. run and judge
|
||||
// 6. run and judge
|
||||
result, point, status := h.runnerService.RunAndJudge(&meta)
|
||||
return status, point, result
|
||||
}()
|
||||
|
@ -22,10 +22,20 @@ const (
|
||||
ContainerImageRun = "git.0x7f.app/woj/ubuntu-run:latest"
|
||||
)
|
||||
|
||||
type JudgeMetaRun struct {
|
||||
Version uint // problem version id
|
||||
User string // user id
|
||||
Lang string // language
|
||||
}
|
||||
|
||||
type JudgeMetaConfig struct {
|
||||
All *Config
|
||||
Lang *ConfigLanguage
|
||||
}
|
||||
|
||||
type JudgeMeta struct {
|
||||
Version uint
|
||||
User string
|
||||
Lang string
|
||||
Run JudgeMetaRun
|
||||
Cfg JudgeMetaConfig
|
||||
}
|
||||
|
||||
func init() {
|
||||
@ -41,33 +51,47 @@ func init() {
|
||||
}
|
||||
|
||||
func (s *service) ProblemExists(meta *JudgeMeta) bool {
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
return file.Exist(problemPath)
|
||||
}
|
||||
|
||||
func (s *service) ValidatePath(meta *JudgeMeta) e.Status {
|
||||
func (s *service) ValidatePath(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
gen := func(status e.Status) (*JudgeStatus, e.Status) {
|
||||
return &JudgeStatus{
|
||||
Message: fmt.Sprintf("System Error: Problem/User Files Not Found (%d:%s)", status, status.String()),
|
||||
CompileMessage: "",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "System Error"}},
|
||||
}, status
|
||||
}
|
||||
|
||||
if !s.ProblemExists(meta) {
|
||||
s.log.Info("problem not exists", zap.Uint("version", meta.Version))
|
||||
return e.RunnerProblemNotExist
|
||||
s.log.Error("problem not exists", zap.Uint("version", meta.Run.Version))
|
||||
return gen(e.RunnerProblemNotExist)
|
||||
}
|
||||
|
||||
userPath := filepath.Join(UserDir, meta.User, fmt.Sprintf("%s.%s", meta.User, meta.Lang))
|
||||
userPath := filepath.Join(UserDir, meta.Run.User, fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang))
|
||||
if !file.Exist(userPath) {
|
||||
s.log.Info("user program not exists", zap.String("user", meta.User), zap.String("lang", meta.Lang))
|
||||
return e.RunnerUserNotExist
|
||||
s.log.Error("user program not exists", zap.String("user", meta.Run.User), zap.String("lang", meta.Run.Lang))
|
||||
return gen(e.RunnerUserNotExist)
|
||||
}
|
||||
|
||||
return e.Success
|
||||
return nil, e.Success
|
||||
}
|
||||
|
||||
func (s *service) GetConfig(meta *JudgeMeta, skipCheck bool) (*Config, *ConfigLanguage, e.Status) {
|
||||
func (s *service) GetConfig(meta *JudgeMeta, skipCheck bool) e.Status {
|
||||
config, err := s.ParseConfig(meta, skipCheck)
|
||||
if err != nil {
|
||||
return nil, nil, e.RunnerProblemParseFailed
|
||||
return e.RunnerProblemParseFailed
|
||||
}
|
||||
cLang, ok := config.FilterLanguage(meta.Lang)
|
||||
|
||||
lang, ok := config.FilterLanguage(meta.Run.Lang)
|
||||
if !ok {
|
||||
return nil, nil, e.RunnerLanguageNotSupported
|
||||
return e.RunnerLanguageNotSupported
|
||||
}
|
||||
return config, cLang, e.Success
|
||||
|
||||
meta.Cfg = JudgeMetaConfig{
|
||||
All: config,
|
||||
Lang: lang,
|
||||
}
|
||||
return e.Success
|
||||
}
|
||||
|
@ -14,62 +14,44 @@ import (
|
||||
)
|
||||
|
||||
func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
// 1. ensure problem/user exists
|
||||
status := s.ValidatePath(meta)
|
||||
if status != e.Success {
|
||||
return &JudgeStatus{Message: "check failed"}, status
|
||||
}
|
||||
// 1. prepare judge environment
|
||||
workDir := filepath.Join(UserDir, meta.Run.User)
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
|
||||
|
||||
config, cLang, status := s.GetConfig(meta, true)
|
||||
if status != e.Success {
|
||||
s.log.Error("[compile] parse config failed", zap.Any("meta", *meta))
|
||||
return &JudgeStatus{
|
||||
Message: "parse config failed",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "parse config failed"}},
|
||||
}, e.RunnerProblemParseFailed
|
||||
}
|
||||
sourceFile := filepath.Join(workDir, fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.Run.User))
|
||||
|
||||
// 2. prepare judge environment
|
||||
workDir := filepath.Join(UserDir, meta.User)
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge")
|
||||
|
||||
sourceFile := filepath.Join(workDir, fmt.Sprintf("%s.%s", meta.User, meta.Lang))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.User))
|
||||
|
||||
logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", meta.User))
|
||||
logFile := filepath.Join(workDir, fmt.Sprintf("%s.compile.log", meta.Run.User))
|
||||
log, err := os.Create(logFile)
|
||||
if err != nil {
|
||||
s.log.Error("[compile] create log file failed", zap.Error(err))
|
||||
return &JudgeStatus{
|
||||
Message: "create log file failed",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "create log file failed"}},
|
||||
Message: "System Error: Unable to create log file",
|
||||
CompileMessage: "",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictSystemError, Message: "System Error"}},
|
||||
}, e.RunnerUserCompileFailed
|
||||
}
|
||||
defer func(log *os.File) {
|
||||
_ = log.Close()
|
||||
}(log)
|
||||
|
||||
// 3. compile
|
||||
// 2. compile
|
||||
err = utils.NewMust().
|
||||
DoAny(func() error { return os.Remove(targetFile) }).
|
||||
Do(func() error { return file.TouchErr(targetFile) }).
|
||||
Do(func() error {
|
||||
l, ok := config.FilterLanguage(meta.Lang)
|
||||
if !ok {
|
||||
return e.RunnerProblemParseFailed.AsError()
|
||||
}
|
||||
script := l.JudgeScript()
|
||||
script := meta.Cfg.Lang.JudgeScript()
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{
|
||||
Args: []string{"sh", "-c", fmt.Sprintf("cd /woj/user && make -f %s compile", script)},
|
||||
Env: []string{fmt.Sprintf("USER_PROG=%s", meta.User), fmt.Sprintf("LANG=%s", meta.Lang)},
|
||||
Env: []string{fmt.Sprintf("USER_PROG=%s", meta.Run.User), fmt.Sprintf("LANG=%s", meta.Run.Lang)},
|
||||
},
|
||||
Runtime: RuntimeArgs{
|
||||
Image: ContainerImageFull,
|
||||
Pid: int64(cLang.Runtime.Compile.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(cLang.Runtime.Compile.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((cLang.Runtime.Compile.TimeLimit+1000)/1000) * time.Second,
|
||||
Pid: int64(meta.Cfg.Lang.Runtime.Compile.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(meta.Cfg.Lang.Runtime.Compile.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Compile.TimeLimit+1000)/1000) * time.Second,
|
||||
},
|
||||
IO: IOArgs{
|
||||
Output: log,
|
||||
@ -85,13 +67,13 @@ func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
},
|
||||
{
|
||||
Source: sourceFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.%s", meta.User, meta.Lang),
|
||||
Destination: fmt.Sprintf("/woj/user/%s.%s", meta.Run.User, meta.Run.Lang),
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
{
|
||||
Source: targetFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.User),
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.Run.User),
|
||||
Type: "bind",
|
||||
Options: []string{"rbind"},
|
||||
},
|
||||
@ -102,6 +84,7 @@ func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
}).
|
||||
Done()
|
||||
|
||||
status := e.Success
|
||||
if err != nil {
|
||||
s.log.Info("[compile] compile failed", zap.Error(err), zap.Any("meta", *meta))
|
||||
status = e.RunnerUserCompileFailed
|
||||
@ -115,8 +98,9 @@ func (s *service) Compile(meta *JudgeMeta) (*JudgeStatus, e.Status) {
|
||||
|
||||
if !file.Exist(targetFile) || file.Empty(targetFile) {
|
||||
return &JudgeStatus{
|
||||
Message: "compile failed",
|
||||
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
||||
Message: "Compile Failed",
|
||||
CompileMessage: msgText,
|
||||
Tasks: []TaskStatus{{Verdict: VerdictCompileError, Message: msgText}}},
|
||||
utils.If(status == e.Success, e.RunnerUserCompileFailed, status)
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ func (c *Config) FilterLanguage(lang string) (*ConfigLanguage, bool) {
|
||||
}
|
||||
|
||||
func (s *service) ParseConfig(meta *JudgeMeta, skipCheck bool) (*Config, error) {
|
||||
base := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
base := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
file := filepath.Join(base, "config.json")
|
||||
|
||||
data, err := os.ReadFile(file)
|
||||
|
@ -14,8 +14,8 @@ import (
|
||||
)
|
||||
|
||||
func (s *service) DownloadProblem(meta *JudgeMeta, url string) e.Status {
|
||||
zipPath := filepath.Join(TmpDir, fmt.Sprintf("%d.zip", meta.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
zipPath := filepath.Join(TmpDir, fmt.Sprintf("%d.zip", meta.Run.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
|
||||
err := down.Down(zipPath, url)
|
||||
if err != nil {
|
||||
@ -37,21 +37,21 @@ func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e
|
||||
return e.RunnerProblemNotExist
|
||||
}
|
||||
|
||||
mark := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), ".mark.prebuild")
|
||||
mark := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), ".mark.prebuild")
|
||||
if force {
|
||||
_ = os.Remove(mark)
|
||||
} else if file.Exist(mark) {
|
||||
return e.Success
|
||||
}
|
||||
|
||||
prebuildScript := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge", "prebuild.Makefile")
|
||||
prebuildScript := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge", "prebuild.Makefile")
|
||||
if !file.Exist(prebuildScript) {
|
||||
s.log.Info("[new] prebuild script not found", zap.String("path", prebuildScript), zap.Uint("version", meta.Version))
|
||||
s.log.Info("[new] prebuild script not found", zap.String("path", prebuildScript), zap.Uint("version", meta.Run.Version))
|
||||
return e.Success
|
||||
}
|
||||
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge")
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
|
||||
|
||||
args := &RunArgs{
|
||||
Program: ProgramArgs{
|
||||
@ -83,7 +83,7 @@ func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e
|
||||
err := s.pool.WaitForTask(id)
|
||||
|
||||
if err != nil {
|
||||
s.log.Warn("[new] prebuild problem failed", zap.Error(err), zap.Uint("version", meta.Version))
|
||||
s.log.Warn("[new] prebuild problem failed", zap.Error(err), zap.Uint("version", meta.Run.Version))
|
||||
return e.RunnerProblemPrebuildFailed
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ func (s *service) PrebuildProblem(meta *JudgeMeta, config *Config, force bool) e
|
||||
|
||||
func (s *service) NewProblem(meta *JudgeMeta, url string, force bool) (*Config, e.Status) {
|
||||
if force {
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version))
|
||||
problemPath := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version))
|
||||
_ = os.RemoveAll(problemPath)
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ func (s *service) NewProblem(meta *JudgeMeta, url string, force bool) (*Config,
|
||||
|
||||
cfg, err := s.ParseConfig(meta, false)
|
||||
if err != nil {
|
||||
s.log.Info("[new] parse problem failed", zap.Error(err), zap.Uint("version", meta.Version))
|
||||
s.log.Info("[new] parse problem failed", zap.Error(err), zap.Uint("version", meta.Run.Version))
|
||||
return &Config{}, e.RunnerProblemParseFailed
|
||||
}
|
||||
|
||||
|
@ -13,43 +13,43 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func (s *service) SandboxArgsBuilder(meta *JudgeMeta, cLang *ConfigLanguage, id int) string {
|
||||
func (s *service) SandboxArgsBuilder(meta *JudgeMeta, id int) string {
|
||||
var args []string
|
||||
|
||||
args = append(args, fmt.Sprintf("--memory_limit=%d", cLang.Runtime.Run.MemoryLimit))
|
||||
args = append(args, fmt.Sprintf("--nproc_limit=%d", cLang.Runtime.Run.NProcLimit))
|
||||
args = append(args, fmt.Sprintf("--time_limit=%d", cLang.Runtime.Run.TimeLimit))
|
||||
args = append(args, fmt.Sprintf("--sandbox_template=%s", cLang.Lang))
|
||||
args = append(args, fmt.Sprintf("--memory_limit=%d", meta.Cfg.Lang.Runtime.Run.MemoryLimit))
|
||||
args = append(args, fmt.Sprintf("--nproc_limit=%d", meta.Cfg.Lang.Runtime.Run.NProcLimit))
|
||||
args = append(args, fmt.Sprintf("--time_limit=%d", meta.Cfg.Lang.Runtime.Run.TimeLimit))
|
||||
args = append(args, fmt.Sprintf("--sandbox_template=%s", meta.Cfg.Lang.Lang))
|
||||
args = append(args, fmt.Sprintf("--sandbox_action=ret"))
|
||||
args = append(args, fmt.Sprintf("--uid=1000"))
|
||||
args = append(args, fmt.Sprintf("--gid=1000"))
|
||||
args = append(args, fmt.Sprintf("--file_input=/woj/problem/data/input/%d.input", id))
|
||||
args = append(args, fmt.Sprintf("--file_output=/woj/user/%d.out.usr", id))
|
||||
args = append(args, fmt.Sprintf("--file_info=/woj/user/%d.info", id))
|
||||
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.User))
|
||||
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.Run.User))
|
||||
|
||||
return strings.Join(args, " ")
|
||||
}
|
||||
|
||||
func (s *service) ProblemRun(meta *JudgeMeta, config *Config, cLang *ConfigLanguage) {
|
||||
workDir := filepath.Join(UserDir, meta.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "data", "input")
|
||||
func (s *service) ProblemRun(meta *JudgeMeta) {
|
||||
workDir := filepath.Join(UserDir, meta.Run.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data", "input")
|
||||
|
||||
runtimeArgs := RuntimeArgs{
|
||||
Image: ContainerImageRun,
|
||||
// sh, woj_launcher:program, woj_launcher:killer, woj_launcher:stat
|
||||
Pid: int64(cLang.Runtime.Run.NProcLimit + 4),
|
||||
Memory: uint64(cLang.Runtime.Run.MemoryLimit * 1024 * 1024),
|
||||
Pid: int64(meta.Cfg.Lang.Runtime.Run.NProcLimit + 4),
|
||||
Memory: uint64(meta.Cfg.Lang.Runtime.Run.MemoryLimit * 1024 * 1024),
|
||||
// woj-sandbox killer will add 1 more second, here we add 1 also
|
||||
Timeout: time.Duration((cLang.Runtime.Run.TimeLimit+1000)/1000+1+1) * time.Second,
|
||||
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Run.TimeLimit+1000)/1000+1+1) * time.Second,
|
||||
}
|
||||
|
||||
ids := make([]int, 0)
|
||||
for _, task := range config.Tasks {
|
||||
for _, task := range meta.Cfg.All.Tasks {
|
||||
f := func(id int) func() error {
|
||||
return func() error {
|
||||
testCase := filepath.Join(dataDir, fmt.Sprintf("%d.input", id))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.User))
|
||||
targetFile := filepath.Join(workDir, fmt.Sprintf("%s.out", meta.Run.User))
|
||||
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
|
||||
ifoFile := filepath.Join(workDir, fmt.Sprintf("%d.info", id))
|
||||
|
||||
@ -58,7 +58,7 @@ func (s *service) ProblemRun(meta *JudgeMeta, config *Config, cLang *ConfigLangu
|
||||
Args: []string{
|
||||
"sh", "-c",
|
||||
"cd /woj/user && /woj/framework/scripts/woj_launcher " +
|
||||
s.SandboxArgsBuilder(meta, cLang, id),
|
||||
s.SandboxArgsBuilder(meta, id),
|
||||
},
|
||||
},
|
||||
Runtime: runtimeArgs,
|
||||
@ -72,7 +72,7 @@ func (s *service) ProblemRun(meta *JudgeMeta, config *Config, cLang *ConfigLangu
|
||||
},
|
||||
{
|
||||
Source: targetFile,
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.User),
|
||||
Destination: fmt.Sprintf("/woj/user/%s.out", meta.Run.User),
|
||||
Type: "bind",
|
||||
Options: []string{"rbind", "ro"},
|
||||
},
|
||||
@ -114,21 +114,21 @@ func (s *service) ProblemRun(meta *JudgeMeta, config *Config, cLang *ConfigLangu
|
||||
}
|
||||
}
|
||||
|
||||
func (s *service) ProblemJudge(meta *JudgeMeta, config *Config, cLang *ConfigLanguage) {
|
||||
workDir := filepath.Join(UserDir, meta.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Version), "judge")
|
||||
script := cLang.JudgeScript()
|
||||
func (s *service) ProblemJudge(meta *JudgeMeta) {
|
||||
workDir := filepath.Join(UserDir, meta.Run.User)
|
||||
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data")
|
||||
judgeDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "judge")
|
||||
script := meta.Cfg.Lang.JudgeScript()
|
||||
|
||||
runtimeArgs := RuntimeArgs{
|
||||
Image: ContainerImageFull,
|
||||
Pid: int64(cLang.Runtime.Check.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(cLang.Runtime.Check.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((cLang.Runtime.Check.TimeLimit+1000)/1000) * time.Second,
|
||||
Pid: int64(meta.Cfg.Lang.Runtime.Check.NProcLimit + 2), // bash + make
|
||||
Memory: uint64(meta.Cfg.Lang.Runtime.Check.MemoryLimit * 1024 * 1024),
|
||||
Timeout: time.Duration((meta.Cfg.Lang.Runtime.Check.TimeLimit+1000)/1000) * time.Second,
|
||||
}
|
||||
|
||||
ids := make([]int, 0)
|
||||
for _, task := range config.Tasks {
|
||||
for _, task := range meta.Cfg.All.Tasks {
|
||||
f := func(id int) func() error {
|
||||
return func() error {
|
||||
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
|
||||
@ -142,7 +142,7 @@ func (s *service) ProblemJudge(meta *JudgeMeta, config *Config, cLang *ConfigLan
|
||||
},
|
||||
Env: []string{
|
||||
fmt.Sprintf("TEST_NUM=%d", id),
|
||||
fmt.Sprintf("CMP=%s", cLang.Judge.Cmp),
|
||||
fmt.Sprintf("CMP=%s", meta.Cfg.Lang.Judge.Cmp),
|
||||
},
|
||||
},
|
||||
Runtime: runtimeArgs,
|
||||
@ -197,26 +197,14 @@ func (s *service) ProblemJudge(meta *JudgeMeta, config *Config, cLang *ConfigLan
|
||||
}
|
||||
|
||||
func (s *service) RunAndJudge(meta *JudgeMeta) (*JudgeStatus, int32, e.Status) {
|
||||
// 1. ensure problem/user exists
|
||||
status := s.ValidatePath(meta)
|
||||
if status != e.Success {
|
||||
return &JudgeStatus{Message: "check failed"}, 0, status
|
||||
}
|
||||
// 1. run user program
|
||||
s.ProblemRun(meta)
|
||||
|
||||
// 2. config
|
||||
config, cLang, status := s.GetConfig(meta, true)
|
||||
if status != e.Success {
|
||||
return &JudgeStatus{Message: status.String()}, 0, status
|
||||
}
|
||||
// 2. run judge
|
||||
s.ProblemJudge(meta)
|
||||
|
||||
// 3. run user program
|
||||
s.ProblemRun(meta, config, cLang)
|
||||
|
||||
// 4. run judge
|
||||
s.ProblemJudge(meta, config, cLang)
|
||||
|
||||
// 5. check result
|
||||
result, pts := s.CheckResults(meta, config, cLang)
|
||||
// 3. check result
|
||||
result, pts := s.CheckResults(meta)
|
||||
|
||||
return result, pts, e.Success
|
||||
}
|
||||
|
@ -32,6 +32,10 @@ type Service interface {
|
||||
ParseConfig(meta *JudgeMeta, skipCheck bool) (*Config, error)
|
||||
// ProblemExists check if problem exists
|
||||
ProblemExists(meta *JudgeMeta) bool
|
||||
// ValidatePath check if problem/user exists
|
||||
ValidatePath(meta *JudgeMeta) (*JudgeStatus, e.Status)
|
||||
// GetConfig return config and filter language config, will fill result to meta.Config
|
||||
GetConfig(meta *JudgeMeta, skipCheck bool) e.Status
|
||||
|
||||
HealthCheck() error
|
||||
Shutdown() error
|
||||
|
@ -47,8 +47,9 @@ type TaskStatus struct {
|
||||
}
|
||||
|
||||
type JudgeStatus struct {
|
||||
Message string `json:"message"`
|
||||
Tasks []TaskStatus `json:"tasks"`
|
||||
Message string `json:"message"`
|
||||
CompileMessage string `json:"compile_message"`
|
||||
Tasks []TaskStatus `json:"tasks"`
|
||||
}
|
||||
|
||||
func (t *TaskStatus) getInfoText(infoFile string) *TaskStatus {
|
||||
@ -193,19 +194,19 @@ func (t *TaskStatus) checkJudge(pts *map[int]int32) *TaskStatus {
|
||||
return t
|
||||
}
|
||||
|
||||
func (s *service) CheckResults(meta *JudgeMeta, config *Config, cLang *ConfigLanguage) (*JudgeStatus, int32) {
|
||||
func (s *service) CheckResults(meta *JudgeMeta) (*JudgeStatus, int32) {
|
||||
// CE will be processed in phase compile
|
||||
|
||||
pts := map[int]int32{}
|
||||
for _, task := range config.Tasks {
|
||||
for _, task := range meta.Cfg.All.Tasks {
|
||||
pts[task.Id] = task.Points
|
||||
}
|
||||
|
||||
var results []TaskStatus
|
||||
dir := filepath.Join(UserDir, meta.User)
|
||||
dir := filepath.Join(UserDir, meta.Run.User)
|
||||
var sum int32 = 0
|
||||
|
||||
for i := 1; i <= len(config.Tasks); i++ {
|
||||
for i := 1; i <= len(meta.Cfg.All.Tasks); i++ {
|
||||
result := TaskStatus{Id: i, Verdict: VerdictAccepted, Points: 0}
|
||||
|
||||
info := filepath.Join(dir, fmt.Sprintf("%d.info", i))
|
||||
@ -213,8 +214,8 @@ func (s *service) CheckResults(meta *JudgeMeta, config *Config, cLang *ConfigLan
|
||||
|
||||
result.getInfoText(info).
|
||||
getInfo().
|
||||
checkTime(cLang).
|
||||
checkMemory(cLang).
|
||||
checkTime(meta.Cfg.Lang).
|
||||
checkMemory(meta.Cfg.Lang).
|
||||
checkExit().
|
||||
getJudgeText(judge).
|
||||
getJudge().
|
||||
|
Loading…
Reference in New Issue
Block a user