woj-server/internal/service/runner/run_judge.go

246 lines
7.2 KiB
Go
Raw Normal View History

2024-01-06 19:21:37 +08:00
package runner
import (
"fmt"
"git.0x7f.app/WOJ/woj-server/internal/e"
"git.0x7f.app/WOJ/woj-server/pkg/file"
"git.0x7f.app/WOJ/woj-server/pkg/utils"
"go.uber.org/zap"
"os"
"path/filepath"
2024-01-27 17:37:27 +08:00
"strings"
2024-01-06 19:21:37 +08:00
"time"
)
type ProblemRunResult struct {
QueueId uint64
Status RuntimeStatus
}
type ProblemRunResults map[int]*ProblemRunResult
func (s *service) SandboxArgsBuilder(meta *JudgeMeta, id int) string {
2024-01-27 17:37:27 +08:00
var args []string
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=%s", "ret"))
args = append(args, fmt.Sprintf("--uid=%d", 1000))
args = append(args, fmt.Sprintf("--gid=%d", 1000))
2024-01-27 17:37:27 +08:00
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))
if meta.Cfg.Lang.JudgeInterpreter() != "" {
sourceFile := fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang)
args = append(args, fmt.Sprintf("--program=%s", meta.Cfg.Lang.JudgeInterpreter()))
args = append(args, fmt.Sprintf("--program_arg=/woj/user/%s", sourceFile))
} else {
args = append(args, fmt.Sprintf("--program=/woj/user/%s.out", meta.Run.User))
}
s.log.Debug("[run] sandbox args", zap.Strings("args", args))
2024-01-27 17:37:27 +08:00
return strings.Join(args, " ")
}
func (s *service) ProblemRun(meta *JudgeMeta) ProblemRunResults {
workDir := filepath.Join(UserDir, meta.Run.User)
dataDir := filepath.Join(ProblemDir, fmt.Sprintf("%d", meta.Run.Version), "data", "input")
runtimeArgs := RuntimeArgs{
2024-03-13 20:03:12 +08:00
Rootfs: RootfsRunDir,
// sh, woj_launcher:program, woj_launcher:killer, woj_launcher:stat
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((meta.Cfg.Lang.Runtime.Run.TimeLimit+1000)/1000+1+1) * time.Second,
}
2024-01-06 19:21:37 +08:00
result := make(ProblemRunResults)
for _, task := range meta.Cfg.All.Tasks {
f := func(id int) func() (interface{}, error) {
return func() (interface{}, error) {
2024-01-06 19:21:37 +08:00
testCase := filepath.Join(dataDir, fmt.Sprintf("%d.input", id))
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
ifoFile := filepath.Join(workDir, fmt.Sprintf("%d.info", id))
targetFile := fmt.Sprintf("%s.out", meta.Run.User)
targetPath := filepath.Join(workDir, targetFile)
sourceFile := fmt.Sprintf("%s.%s", meta.Run.User, meta.Run.Lang)
sourcePath := filepath.Join(workDir, sourceFile)
2024-01-27 17:37:27 +08:00
args := &RunArgs{
Program: ProgramArgs{
Args: []string{
2024-03-13 22:38:52 +08:00
"/bin/sh", "-c",
2024-01-27 17:37:27 +08:00
"cd /woj/user && /woj/framework/scripts/woj_launcher " +
s.SandboxArgsBuilder(meta, id),
2024-01-27 17:37:27 +08:00
},
},
Runtime: runtimeArgs,
2024-01-27 17:37:27 +08:00
}
2024-03-13 20:03:12 +08:00
args.Runtime.Mount = []MountInfo{
2024-01-27 17:37:27 +08:00
{
Source: testCase,
Destination: fmt.Sprintf("/woj/problem/data/input/%d.input", id),
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
{
Source: utils.If(meta.Cfg.Lang.JudgeInterpreter() != "", sourcePath, targetPath),
Destination: fmt.Sprintf("/woj/user/%s", utils.If(meta.Cfg.Lang.JudgeInterpreter() != "", sourceFile, targetFile)),
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
{
Source: ansFile,
Destination: fmt.Sprintf("/woj/user/%d.out.usr", id),
2024-03-13 20:03:12 +08:00
Readonly: false,
2024-01-27 17:37:27 +08:00
},
{
Source: ifoFile,
Destination: fmt.Sprintf("/woj/user/%d.info", id),
2024-03-13 20:03:12 +08:00
Readonly: false,
2024-01-27 17:37:27 +08:00
},
}
2024-01-06 19:21:37 +08:00
err := utils.NewMust().
DoAny(func() error { return os.Remove(ansFile) }).
DoAny(func() error { return os.Remove(ifoFile) }).
Do(func() error { return file.TouchErr(ansFile) }).
Do(func() error { return file.TouchErr(ifoFile) }).
Done()
if err != nil {
s.log.Info("[run] prepare failed", zap.Error(err), zap.Any("meta", *meta))
return nil, err
2024-01-06 19:21:37 +08:00
}
2024-03-13 20:03:12 +08:00
return s.JailRun(args)
2024-01-06 19:21:37 +08:00
}
}(task.Id)
queueId := s.pool.AddTask(f)
result[task.Id] = &ProblemRunResult{
QueueId: queueId,
}
2024-01-06 19:21:37 +08:00
}
for i := range result {
waitBuf := s.pool.WaitForTask(result[i].QueueId)
if waitBuf.Error != nil {
s.log.Error(
"[run] wait for problem run failed",
zap.Error(waitBuf.Error),
zap.Any("meta", *meta))
continue
}
val, ok := waitBuf.Value.(RuntimeStatus)
if !ok {
s.log.Error(
"[run] container run is not returning RuntimeStatus",
zap.Any("waitBuf", waitBuf),
zap.Any("meta", *meta))
continue
}
result[i].Status = val
2024-01-06 19:21:37 +08:00
}
return result
2024-01-06 19:21:37 +08:00
}
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{
2024-03-13 20:03:12 +08:00
Rootfs: RootfsFullDir,
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,
}
2024-01-06 19:21:37 +08:00
ids := make([]uint64, 0)
for _, task := range meta.Cfg.All.Tasks {
f := func(id int) func() (interface{}, error) {
return func() (interface{}, error) {
2024-01-06 19:21:37 +08:00
ansFile := filepath.Join(workDir, fmt.Sprintf("%d.out.usr", id))
jdgFile := filepath.Join(workDir, fmt.Sprintf("%d.judge", id))
2024-01-27 17:37:27 +08:00
args := &RunArgs{
Program: ProgramArgs{
Args: []string{
2024-03-13 22:38:52 +08:00
"/bin/sh", "-c",
fmt.Sprintf("cd /woj/user && make -f %s judge", script),
2024-01-27 17:37:27 +08:00
},
Env: []string{
fmt.Sprintf("TEST_NUM=%d", id),
fmt.Sprintf("CMP=%s", meta.Cfg.Lang.Judge.Cmp),
2024-01-27 17:37:27 +08:00
},
},
Runtime: runtimeArgs,
2024-01-27 17:37:27 +08:00
}
2024-03-13 20:03:12 +08:00
args.Runtime.Mount = []MountInfo{
2024-01-27 17:37:27 +08:00
{
Source: judgeDir,
Destination: "/woj/problem/judge",
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
{
Source: dataDir,
Destination: "/woj/problem/data",
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
{
Source: ansFile,
Destination: fmt.Sprintf("/woj/user/%d.out.usr", id),
2024-03-13 20:03:12 +08:00
Readonly: true,
2024-01-27 17:37:27 +08:00
},
{
Source: jdgFile,
Destination: fmt.Sprintf("/woj/user/%d.judge", id),
2024-03-13 20:03:12 +08:00
Readonly: false,
2024-01-27 17:37:27 +08:00
},
}
2024-01-06 19:21:37 +08:00
err := utils.NewMust().
DoAny(func() error { return os.Remove(jdgFile) }).
Do(func() error { return file.TouchErr(jdgFile) }).
Done()
if err != nil {
s.log.Info("[judge] judge prepare failed", zap.Error(err), zap.Any("meta", *meta))
return nil, err
2024-01-06 19:21:37 +08:00
}
2024-03-13 20:03:12 +08:00
return s.JailRun(args)
2024-01-06 19:21:37 +08:00
}
}(task.Id)
id := s.pool.AddTask(f)
ids = append(ids, id)
}
for _, id := range ids {
_ = s.pool.WaitForTask(id)
2024-01-06 19:21:37 +08:00
}
}
func (s *service) RunAndJudge(meta *JudgeMeta) (*JudgeStatus, int32, e.Status) {
// 1. run user program
results := s.ProblemRun(meta)
2024-01-06 19:21:37 +08:00
// 2. run judge
s.ProblemJudge(meta)
2024-01-06 19:21:37 +08:00
// 3. final JudgeStatus
status, pts := s.CheckResults(meta, results)
2024-01-06 19:21:37 +08:00
return status, pts, e.Success
2024-01-06 19:21:37 +08:00
}