fix(sandbox): optimize tar preparation, file limit thresholds, and multi-cmd support
This commit is contained in:
parent
9b23765848
commit
e751c9a237
|
|
@ -10,13 +10,17 @@ import (
|
||||||
"maps"
|
"maps"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/criyle/go-judge/pb"
|
"github.com/criyle/go-judge/pb"
|
||||||
"github.com/joint-online-judge/JOJ3/internal/stage"
|
"github.com/joint-online-judge/JOJ3/internal/stage"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tarThreshold = 128 * 1024
|
const (
|
||||||
|
tarSizeThreshold = 128 * 1024 // 128 KB
|
||||||
|
tarCountThreshold = 100 // 100 files
|
||||||
|
)
|
||||||
|
|
||||||
func (e *Sandbox) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
func (e *Sandbox) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
@ -28,13 +32,12 @@ func (e *Sandbox) Run(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < len(cmds); i += 1 {
|
for i := 0; i < len(cmds); i += 1 {
|
||||||
cmd := &cmds[i]
|
if cmd := &cmds[i]; cmd.CopyIn == nil {
|
||||||
if cmd.CopyIn == nil {
|
|
||||||
cmd.CopyIn = make(map[string]stage.CmdFile)
|
cmd.CopyIn = make(map[string]stage.CmdFile)
|
||||||
}
|
}
|
||||||
for k, v := range cmd.CopyInCached {
|
for k, v := range cmds[i].CopyInCached {
|
||||||
if fileID, ok := e.cachedMap[v]; ok {
|
if fileID, ok := e.cachedMap[v]; ok {
|
||||||
cmd.CopyIn[k] = stage.CmdFile{FileID: &fileID}
|
cmds[i].CopyIn[k] = stage.CmdFile{FileID: &fileID}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -49,8 +52,7 @@ func prepareTar(cmds []stage.Cmd) (bool, []byte) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
for i := range cmds {
|
for i := range cmds {
|
||||||
if cmds[i].CopyInDir != "" &&
|
if shouldTar(&cmds[i]) {
|
||||||
estimateCopyInSize(&cmds[i]) >= tarThreshold {
|
|
||||||
tarData, keysInTar := createCopyInTar(&cmds[i])
|
tarData, keysInTar := createCopyInTar(&cmds[i])
|
||||||
if tarData == nil {
|
if tarData == nil {
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
@ -68,6 +70,11 @@ func prepareTar(cmds []stage.Cmd) (bool, []byte) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func shouldTar(cmd *stage.Cmd) bool {
|
||||||
|
size, count := estimateCopyIn(cmd)
|
||||||
|
return size >= tarSizeThreshold || count >= tarCountThreshold
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Sandbox) runUnary(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
func (e *Sandbox) runUnary(cmds []stage.Cmd) ([]stage.ExecutorResult, error) {
|
||||||
pbCmds := convertPBCmd(cmds)
|
pbCmds := convertPBCmd(cmds)
|
||||||
for i, pbCmd := range pbCmds {
|
for i, pbCmd := range pbCmds {
|
||||||
|
|
@ -100,35 +107,38 @@ func (e *Sandbox) runWithTar(cmds []stage.Cmd, tarData []byte) ([]stage.Executor
|
||||||
fid := fileIDResp.GetFileID()
|
fid := fileIDResp.GetFileID()
|
||||||
slog.Debug("sandbox tar uploaded", "fileID", fid, "tarSize", len(tarData))
|
slog.Debug("sandbox tar uploaded", "fileID", fid, "tarSize", len(tarData))
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
deleteReq := &pb.FileID{}
|
||||||
|
deleteReq.SetFileID(fid)
|
||||||
|
if _, err := e.execClient.FileDelete(context.TODO(), deleteReq); err != nil {
|
||||||
|
slog.Warn("sandbox tar file delete", "fileID", fid, "error", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
tarFileName := "/w/__joj3_copyin.tar"
|
tarFileName := "/w/__joj3_copyin.tar"
|
||||||
script := fmt.Sprintf(
|
script := fmt.Sprintf(
|
||||||
"/bin/tar xf %s -C / --no-same-owner && rm %s && exec \"$@\"",
|
"/bin/tar xf %s -C / --no-same-owner && rm -f %s && exec \"$@\"",
|
||||||
tarFileName, tarFileName,
|
tarFileName, tarFileName,
|
||||||
)
|
)
|
||||||
|
|
||||||
cmds[0].CopyIn[tarFileName] = stage.CmdFile{FileID: &fid}
|
for i := range cmds {
|
||||||
cmds[0].Args = append([]string{
|
if cmds[i].CopyIn == nil {
|
||||||
"/bin/sh", "-c", script, "--",
|
cmds[i].CopyIn = make(map[string]stage.CmdFile)
|
||||||
}, cmds[0].Args...)
|
}
|
||||||
|
cmds[i].CopyIn[tarFileName] = stage.CmdFile{FileID: &fid}
|
||||||
|
cmds[i].Args = append([]string{
|
||||||
|
"/bin/sh", "-c", script, "_",
|
||||||
|
}, cmds[i].Args...)
|
||||||
|
}
|
||||||
|
|
||||||
slog.Debug("sandbox tar exec", "cmd", cmds[0].Args[:3])
|
slog.Debug("sandbox tar exec", "cmd", cmds[0].Args[:3])
|
||||||
|
|
||||||
results, err := e.runUnary(cmds)
|
return e.runUnary(cmds)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteReq := &pb.FileID{}
|
|
||||||
deleteReq.SetFileID(fid)
|
|
||||||
if _, err := e.execClient.FileDelete(context.TODO(), deleteReq); err != nil {
|
|
||||||
slog.Warn("sandbox tar file delete", "fileID", fid, "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return results, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func estimateCopyInSize(cmd *stage.Cmd) int {
|
func estimateCopyIn(cmd *stage.Cmd) (int, int) {
|
||||||
total := 0
|
totalSize := 0
|
||||||
|
totalCount := 0
|
||||||
if cmd.CopyInDir != "" {
|
if cmd.CopyInDir != "" {
|
||||||
_ = filepath.Walk(cmd.CopyInDir,
|
_ = filepath.Walk(cmd.CopyInDir,
|
||||||
func(path string, info os.FileInfo, err error) error {
|
func(path string, info os.FileInfo, err error) error {
|
||||||
|
|
@ -140,7 +150,8 @@ func estimateCopyInSize(cmd *stage.Cmd) int {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if _, exists := cmd.CopyIn[relPath]; !exists {
|
if _, exists := cmd.CopyIn[relPath]; !exists {
|
||||||
total += int(info.Size())
|
totalSize += int(info.Size())
|
||||||
|
totalCount++
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -151,13 +162,22 @@ func estimateCopyInSize(cmd *stage.Cmd) int {
|
||||||
}
|
}
|
||||||
if f.Src != nil {
|
if f.Src != nil {
|
||||||
if fi, err := os.Stat(*f.Src); err == nil {
|
if fi, err := os.Stat(*f.Src); err == nil {
|
||||||
total += int(fi.Size())
|
totalSize += int(fi.Size())
|
||||||
|
totalCount++
|
||||||
}
|
}
|
||||||
} else if f.Content != nil {
|
} else if f.Content != nil {
|
||||||
total += len(*f.Content)
|
totalSize += len(*f.Content)
|
||||||
|
totalCount++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total
|
return totalSize, totalCount
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatTarPath(p string) string {
|
||||||
|
if filepath.IsAbs(p) {
|
||||||
|
return strings.TrimPrefix(p, "/")
|
||||||
|
}
|
||||||
|
return "w/" + p
|
||||||
}
|
}
|
||||||
|
|
||||||
func createCopyInTar(cmd *stage.Cmd) ([]byte, []string) {
|
func createCopyInTar(cmd *stage.Cmd) ([]byte, []string) {
|
||||||
|
|
@ -193,20 +213,14 @@ func createCopyInTar(cmd *stage.Cmd) ([]byte, []string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hdr.Name = relPath
|
hdr.Name = formatTarPath(relPath)
|
||||||
if !filepath.IsAbs(hdr.Name) {
|
|
||||||
hdr.Name = "w/" + hdr.Name
|
|
||||||
}
|
|
||||||
return tw.WriteHeader(hdr)
|
return tw.WriteHeader(hdr)
|
||||||
}
|
}
|
||||||
hdr, err := tar.FileInfoHeader(info, "")
|
hdr, err := tar.FileInfoHeader(info, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
hdr.Name = relPath
|
hdr.Name = formatTarPath(relPath)
|
||||||
if !filepath.IsAbs(hdr.Name) {
|
|
||||||
hdr.Name = "w/" + hdr.Name
|
|
||||||
}
|
|
||||||
if info.IsDir() {
|
if info.IsDir() {
|
||||||
hdr.Name += "/"
|
hdr.Name += "/"
|
||||||
}
|
}
|
||||||
|
|
@ -235,12 +249,8 @@ func createCopyInTar(cmd *stage.Cmd) ([]byte, []string) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if f.Content != nil {
|
if f.Content != nil {
|
||||||
name := k
|
|
||||||
if !filepath.IsAbs(name) {
|
|
||||||
name = "w/" + name
|
|
||||||
}
|
|
||||||
hdr := &tar.Header{
|
hdr := &tar.Header{
|
||||||
Name: name,
|
Name: formatTarPath(k),
|
||||||
Mode: 0o644,
|
Mode: 0o644,
|
||||||
Size: int64(len(*f.Content)),
|
Size: int64(len(*f.Content)),
|
||||||
}
|
}
|
||||||
|
|
@ -267,10 +277,7 @@ func createCopyInTar(cmd *stage.Cmd) ([]byte, []string) {
|
||||||
slog.Error("create copyIn tar file info header", "key", k, "error", err)
|
slog.Error("create copyIn tar file info header", "key", k, "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
hdr.Name = k
|
hdr.Name = formatTarPath(k)
|
||||||
if !filepath.IsAbs(hdr.Name) {
|
|
||||||
hdr.Name = "w/" + hdr.Name
|
|
||||||
}
|
|
||||||
if err := tw.WriteHeader(hdr); err != nil {
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
slog.Error("create copyIn tar write header", "key", k, "error", err)
|
slog.Error("create copyIn tar write header", "key", k, "error", err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user