From 33375ee5a4d75032bd1571c5bbea2c893150be7f Mon Sep 17 00:00:00 2001 From: Himit_ZH <372347736@qq.com> Date: Fri, 7 Jan 2022 21:54:58 +0800 Subject: [PATCH] change judge params --- .../top/hcode/hoj/config/AsyncTaskConfig.java | 4 +- .../hoj/config/JudgeAsyncTaskConfig.java | 4 +- .../hcode/hoj/config/RestTemplateConfig.java | 4 +- .../admin/AdminJudgeController.java | 179 +---------------- .../hcode/hoj/judge/self/JudgeReceiver.java | 1 - .../hcode/hoj/schedule/ScheduleService.java | 2 + .../hoj/schedule/ScheduleServiceImpl.java | 29 +++ .../hoj/service/judge/RejudgeService.java | 10 + .../judge/impl/RejudgeServiceImpl.java | 188 ++++++++++++++++++ .../java/top/hcode/hoj/judge/JudgeRun.java | 2 +- .../java/top/hcode/hoj/judge/SandboxRun.java | 23 ++- .../hoj/judge/entity/JudgeGlobalDTO.java | 2 +- .../hcode/hoj/judge/task/DefaultJudge.java | 5 +- .../hoj/judge/task/InteractiveJudge.java | 62 +++--- .../hcode/hoj/judge/task/SpecialJudge.java | 5 +- .../top/hcode/hoj/util/ThreadPoolUtils.java | 4 +- 16 files changed, 299 insertions(+), 225 deletions(-) create mode 100644 hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/RejudgeService.java create mode 100644 hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/impl/RejudgeServiceImpl.java diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/AsyncTaskConfig.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/AsyncTaskConfig.java index f614acf7..7cc62f2a 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/AsyncTaskConfig.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/AsyncTaskConfig.java @@ -24,11 +24,11 @@ public class AsyncTaskConfig implements AsyncConfigurer { // 线程池维护线程的最少数量 taskExecutor.setCorePoolSize(10); // 线程池维护线程的最大数量 - taskExecutor.setMaxPoolSize(100); + taskExecutor.setMaxPoolSize(20); // 缓存队列 taskExecutor.setQueueCapacity(200); //活跃时间 - taskExecutor.setKeepAliveSeconds(10); + taskExecutor.setKeepAliveSeconds(3); // 对拒绝task的处理策略 //(1) 默认的ThreadPoolExecutor.AbortPolicy 处理程序遭到拒绝将抛出运行时RejectedExecutionException; //(2) ThreadPoolExecutor.CallerRunsPolicy 线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度 diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/JudgeAsyncTaskConfig.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/JudgeAsyncTaskConfig.java index e675544b..96b82946 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/JudgeAsyncTaskConfig.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/JudgeAsyncTaskConfig.java @@ -24,9 +24,9 @@ public class JudgeAsyncTaskConfig { //最大线程数 executor.setMaxPoolSize(10); //队列容量 - executor.setQueueCapacity(300); + executor.setQueueCapacity(500); //活跃时间 - executor.setKeepAliveSeconds(10); + executor.setKeepAliveSeconds(3); //线程名字前缀 executor.setThreadNamePrefix("JudgeExecutor-"); diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/RestTemplateConfig.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/RestTemplateConfig.java index 534767ad..5dc83369 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/RestTemplateConfig.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/config/RestTemplateConfig.java @@ -23,8 +23,8 @@ public class RestTemplateConfig { @Bean public ClientHttpRequestFactory simpleClientHttpRequestFactory() { SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); - factory.setReadTimeout(100000);//单位为ms - factory.setConnectTimeout(10000);//单位为ms + factory.setReadTimeout(600000);//单位为ms + factory.setConnectTimeout(50000);//单位为ms return factory; } } \ No newline at end of file diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminJudgeController.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminJudgeController.java index 41f70d2f..4f0bffc1 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminJudgeController.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/controller/admin/AdminJudgeController.java @@ -1,13 +1,8 @@ package top.hcode.hoj.controller.admin; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import org.apache.shiro.authz.annotation.RequiresAuthentication; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.transaction.annotation.Isolation; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.GetMapping; @@ -15,58 +10,25 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import top.hcode.hoj.common.result.CommonResult; -import top.hcode.hoj.judge.remote.RemoteJudgeDispatcher; -import top.hcode.hoj.judge.self.JudgeDispatcher; -import top.hcode.hoj.pojo.entity.judge.Judge; -import top.hcode.hoj.pojo.entity.judge.JudgeCase; -import top.hcode.hoj.pojo.entity.user.UserAcproblem; -import top.hcode.hoj.pojo.entity.contest.ContestRecord; -import top.hcode.hoj.pojo.entity.problem.Problem; -import top.hcode.hoj.service.contest.impl.ContestRecordServiceImpl; -import top.hcode.hoj.service.judge.impl.JudgeCaseServiceImpl; -import top.hcode.hoj.service.judge.impl.JudgeServiceImpl; -import top.hcode.hoj.service.problem.impl.ProblemServiceImpl; -import top.hcode.hoj.service.user.impl.UserAcproblemServiceImpl; -import top.hcode.hoj.utils.Constants; +import top.hcode.hoj.service.judge.impl.RejudgeServiceImpl; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; + +import javax.annotation.Resource; /** * @Author: Himit_ZH * @Date: 2021/1/3 14:09 - * @Description: + * @Description: 超管重判提交 */ @RestController @RequestMapping("/api/admin/judge") -@RefreshScope + public class AdminJudgeController { - @Autowired - private JudgeServiceImpl judgeService; + @Resource + private RejudgeServiceImpl rejudgeService; - @Autowired - private UserAcproblemServiceImpl userAcproblemService; - - @Autowired - private ContestRecordServiceImpl contestRecordService; - - @Autowired - private JudgeCaseServiceImpl judgeCaseService; - - @Autowired - private ProblemServiceImpl problemService; - - @Value("${hoj.judge.token}") - private String judgeToken; - - @Autowired - private JudgeDispatcher judgeDispatcher; - - @Autowired - private RemoteJudgeDispatcher remoteJudgeDispatcher; @GetMapping("/rejudge") @RequiresAuthentication @@ -74,60 +36,7 @@ public class AdminJudgeController { @RequiresPermissions("rejudge") @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED) public CommonResult rejudge(@RequestParam("submitId") Long submitId) { - Judge judge = judgeService.getById(submitId); - - boolean isContestSubmission = judge.getCid() != 0; - boolean resetContestRecordResult = true; - - // 如果是非比赛题目 - if (!isContestSubmission) { - // 重判前,需要将该题目对应记录表一并更新 - // 如果该题已经是AC通过状态,更新该题目的用户ac做题表 user_acproblem - if (judge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus().intValue()) { - QueryWrapper userAcproblemQueryWrapper = new QueryWrapper<>(); - userAcproblemQueryWrapper.eq("submit_id", judge.getSubmitId()); - userAcproblemService.remove(userAcproblemQueryWrapper); - } - } else { - // 将对应比赛记录设置成默认值 - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.eq("submit_id", submitId).setSql("status=null,score=null"); - resetContestRecordResult = contestRecordService.update(updateWrapper); - } - - // 清除该提交对应的测试点结果 - QueryWrapper judgeCaseQueryWrapper = new QueryWrapper<>(); - judgeCaseQueryWrapper.eq("submit_id", submitId); - judgeCaseService.remove(judgeCaseQueryWrapper); - - boolean hasSubmitIdRemoteRejudge = isHasSubmitIdRemoteRejudge(judge.getVjudgeSubmitId(), judge.getStatus()); - - // 设置默认值 - judge.setStatus(Constants.Judge.STATUS_PENDING.getStatus()); // 开始进入判题队列 - judge.setVersion(judge.getVersion() + 1); - judge.setJudger("") - .setTime(null) - .setMemory(null) - .setErrorMessage(null) - .setOiRankScore(null) - .setScore(null); - - boolean result = judgeService.updateById(judge); - - - if (result && resetContestRecordResult) { - // 调用判题服务 - Problem problem = problemService.getById(judge.getPid()); - if (problem.getIsRemote()) { // 如果是远程oj判题 - remoteJudgeDispatcher.sendTask(judge, judgeToken, problem.getProblemId(), - isContestSubmission, 1, hasSubmitIdRemoteRejudge); - } else { - judgeDispatcher.sendTask(judge, judgeToken, isContestSubmission, 1); - } - return CommonResult.successResponse(judge, "重判成功!该提交已进入判题队列!"); - } else { - return CommonResult.successResponse(judge, "重判失败!请重新尝试!"); - } + return rejudgeService.rejudge(submitId); } @GetMapping("/rejudge-contest-problem") @@ -136,74 +45,6 @@ public class AdminJudgeController { @RequiresPermissions("rejudge") @Transactional(rollbackFor = Exception.class) public CommonResult rejudgeContestProblem(@RequestParam("cid") Long cid, @RequestParam("pid") Long pid) { - - - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("cid", cid).eq("pid", pid); - List rejudgeList = judgeService.list(queryWrapper); - - if (rejudgeList.size() == 0) { - return CommonResult.errorResponse("当前该题目无提交,不可重判!"); - } - List submitIdList = new LinkedList<>(); - HashMap idMapStatus = new HashMap<>(); - // 全部设置默认值 - for (Judge judge : rejudgeList) { - idMapStatus.put(judge.getSubmitId(), judge.getStatus()); - judge.setStatus(Constants.Judge.STATUS_PENDING.getStatus()); // 开始进入判题队列 - judge.setVersion(judge.getVersion() + 1); - judge.setJudger("") - .setTime(null) - .setMemory(null) - .setErrorMessage(null) - .setOiRankScore(null) - .setScore(null); - submitIdList.add(judge.getSubmitId()); - } - boolean resetJudgeResult = judgeService.updateBatchById(rejudgeList); - // 清除每个提交对应的测试点结果 - QueryWrapper judgeCaseQueryWrapper = new QueryWrapper<>(); - judgeCaseQueryWrapper.in("submit_id", submitIdList); - judgeCaseService.remove(judgeCaseQueryWrapper); - // 将对应比赛记录设置成默认值 - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.in("submit_id", submitIdList).setSql("status=null,score=null"); - boolean resetContestRecordResult = contestRecordService.update(updateWrapper); - - if (resetContestRecordResult && resetJudgeResult) { - // 调用重判服务 - Problem problem = problemService.getById(pid); - if (problem.getIsRemote()) { // 如果是远程oj判题 - for (Judge judge : rejudgeList) { - // 进入重判队列,等待调用判题服务 - remoteJudgeDispatcher.sendTask(judge, judgeToken, problem.getProblemId(), - judge.getCid() != 0, 1, - isHasSubmitIdRemoteRejudge(judge.getVjudgeSubmitId(), idMapStatus.get(judge.getSubmitId()))); - } - } else { - for (Judge judge : rejudgeList) { - // 进入重判队列,等待调用判题服务 - judgeDispatcher.sendTask(judge, judgeToken, judge.getCid() != 0, 1); - } - } - - return CommonResult.successResponse(null, "重判成功!该题目对应的全部提交已进入判题队列!"); - } else { - return CommonResult.errorResponse("重判失败!请重新尝试!"); - } - + return rejudgeService.rejudgeContestProblem(cid, pid); } - - public boolean isHasSubmitIdRemoteRejudge(Long vjudgeSubmitId, int status) { - boolean isHasSubmitIdRemoteRejudge = false; - if (vjudgeSubmitId != null && - (status == Constants.Judge.STATUS_SUBMITTED_FAILED.getStatus() - || status == Constants.Judge.STATUS_COMPILING.getStatus() - || status == Constants.Judge.STATUS_PENDING.getStatus() - || status == Constants.Judge.STATUS_JUDGING.getStatus() - || status == Constants.Judge.STATUS_SYSTEM_ERROR.getStatus())) { - isHasSubmitIdRemoteRejudge = true; - } - return isHasSubmitIdRemoteRejudge; - } -} \ No newline at end of file +} diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/judge/self/JudgeReceiver.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/judge/self/JudgeReceiver.java index 2e6fd18c..6bd42264 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/judge/self/JudgeReceiver.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/judge/self/JudgeReceiver.java @@ -48,7 +48,6 @@ public class JudgeReceiver extends AbstractReceiver { @Override public void handleJudgeMsg(String taskJsonStr) { - JSONObject task = JSONUtil.parseObj(taskJsonStr); Judge judge = task.get("judge", Judge.class); String token = task.getStr("token"); diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleService.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleService.java index e5a1108f..bfbc8937 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleService.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleService.java @@ -14,4 +14,6 @@ public interface ScheduleService { void deleteUserSession(); void syncNoticeToRecentHalfYearUser(); + + void checkHalfAnHourPendingSubmission(); } diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleServiceImpl.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleServiceImpl.java index 7066d2ae..523632a6 100644 --- a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleServiceImpl.java +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/schedule/ScheduleServiceImpl.java @@ -15,6 +15,9 @@ import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import top.hcode.hoj.common.result.CommonResult; +import top.hcode.hoj.pojo.entity.judge.Judge; import top.hcode.hoj.pojo.entity.user.Session; import top.hcode.hoj.pojo.entity.user.UserInfo; import top.hcode.hoj.pojo.entity.user.UserRecord; @@ -22,6 +25,8 @@ import top.hcode.hoj.pojo.entity.msg.AdminSysNotice; import top.hcode.hoj.pojo.entity.common.File; import top.hcode.hoj.pojo.entity.msg.UserSysNotice; import top.hcode.hoj.service.common.impl.FileServiceImpl; +import top.hcode.hoj.service.judge.impl.JudgeServiceImpl; +import top.hcode.hoj.service.judge.impl.RejudgeServiceImpl; import top.hcode.hoj.service.user.UserInfoService; import top.hcode.hoj.service.user.UserRecordService; import top.hcode.hoj.service.msg.impl.AdminSysNoticeServiceImpl; @@ -85,6 +90,11 @@ public class ScheduleServiceImpl implements ScheduleService { @Resource private UserSysNoticeServiceImpl userSysNoticeService; + @Resource + private JudgeServiceImpl judgeService; + + @Resource + private RejudgeServiceImpl rejudgeService; /** * @MethodName deleteAvatar @@ -371,4 +381,23 @@ public class ScheduleServiceImpl implements ScheduleService { } + @Override + @Scheduled(cron = "0 0/30 * * * ?") + public void checkHalfAnHourPendingSubmission() { + DateTime dateTime = DateUtil.offsetMinute(new Date(), -30); + String strTime = DateFormatUtils.format(dateTime, "yyyy-MM-dd HH:mm:ss"); + + QueryWrapper judgeQueryWrapper = new QueryWrapper<>(); + judgeQueryWrapper.select("distinct submit_id"); + judgeQueryWrapper.eq("status", Constants.Judge.STATUS_PENDING.getStatus()); + judgeQueryWrapper.apply("UNIX_TIMESTAMP('" + strTime + "') > UNIX_TIMESTAMP(gmt_modified)"); + List judgeList = judgeService.list(judgeQueryWrapper); + if (!CollectionUtils.isEmpty(judgeList)) { + log.info("Half An Hour Check Pending Submission to Rejudge:" + Arrays.toString(judgeList.toArray())); + for (Judge judge : judgeList) { + rejudgeService.rejudge(judge.getSubmitId()); + } + } + } + } diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/RejudgeService.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/RejudgeService.java new file mode 100644 index 00000000..825005b3 --- /dev/null +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/RejudgeService.java @@ -0,0 +1,10 @@ +package top.hcode.hoj.service.judge; + +import top.hcode.hoj.common.result.CommonResult; + +public interface RejudgeService { + + CommonResult rejudge(Long submitId); + + CommonResult rejudgeContestProblem(Long cid,Long pid); +} diff --git a/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/impl/RejudgeServiceImpl.java b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/impl/RejudgeServiceImpl.java new file mode 100644 index 00000000..940b6e7f --- /dev/null +++ b/hoj-springboot/DataBackup/src/main/java/top/hcode/hoj/service/judge/impl/RejudgeServiceImpl.java @@ -0,0 +1,188 @@ +package top.hcode.hoj.service.judge.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Service; +import top.hcode.hoj.common.result.CommonResult; +import top.hcode.hoj.judge.remote.RemoteJudgeDispatcher; +import top.hcode.hoj.judge.self.JudgeDispatcher; +import top.hcode.hoj.pojo.entity.contest.ContestRecord; +import top.hcode.hoj.pojo.entity.judge.Judge; +import top.hcode.hoj.pojo.entity.judge.JudgeCase; +import top.hcode.hoj.pojo.entity.problem.Problem; +import top.hcode.hoj.pojo.entity.user.UserAcproblem; +import top.hcode.hoj.service.contest.impl.ContestRecordServiceImpl; +import top.hcode.hoj.service.judge.RejudgeService; +import top.hcode.hoj.service.problem.impl.ProblemServiceImpl; +import top.hcode.hoj.service.user.impl.UserAcproblemServiceImpl; +import top.hcode.hoj.utils.Constants; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +/** + * @Author: Himit_ZH + * @Date: 2022/1/7 18:12 + * @Description: + */ +@Service +@RefreshScope +public class RejudgeServiceImpl implements RejudgeService { + + @Resource + private JudgeServiceImpl judgeService; + + @Resource + private UserAcproblemServiceImpl userAcproblemService; + + @Resource + private ContestRecordServiceImpl contestRecordService; + + @Resource + private JudgeCaseServiceImpl judgeCaseService; + + @Resource + private ProblemServiceImpl problemService; + + @Value("${hoj.judge.token}") + private String judgeToken; + + @Resource + private JudgeDispatcher judgeDispatcher; + + @Resource + private RemoteJudgeDispatcher remoteJudgeDispatcher; + + @Override + public CommonResult rejudge(Long submitId) { + Judge judge = judgeService.getById(submitId); + + boolean isContestSubmission = judge.getCid() != 0; + boolean resetContestRecordResult = true; + + // 如果是非比赛题目 + if (!isContestSubmission) { + // 重判前,需要将该题目对应记录表一并更新 + // 如果该题已经是AC通过状态,更新该题目的用户ac做题表 user_acproblem + if (judge.getStatus().intValue() == Constants.Judge.STATUS_ACCEPTED.getStatus().intValue()) { + QueryWrapper userAcproblemQueryWrapper = new QueryWrapper<>(); + userAcproblemQueryWrapper.eq("submit_id", judge.getSubmitId()); + userAcproblemService.remove(userAcproblemQueryWrapper); + } + } else { + // 将对应比赛记录设置成默认值 + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.eq("submit_id", submitId).setSql("status=null,score=null"); + resetContestRecordResult = contestRecordService.update(updateWrapper); + } + + // 清除该提交对应的测试点结果 + QueryWrapper judgeCaseQueryWrapper = new QueryWrapper<>(); + judgeCaseQueryWrapper.eq("submit_id", submitId); + judgeCaseService.remove(judgeCaseQueryWrapper); + + boolean hasSubmitIdRemoteRejudge = isHasSubmitIdRemoteRejudge(judge.getVjudgeSubmitId(), judge.getStatus()); + + // 设置默认值 + judge.setStatus(Constants.Judge.STATUS_PENDING.getStatus()); // 开始进入判题队列 + judge.setVersion(judge.getVersion() + 1); + judge.setJudger("") + .setTime(null) + .setMemory(null) + .setErrorMessage(null) + .setOiRankScore(null) + .setScore(null); + + boolean result = judgeService.updateById(judge); + + + if (result && resetContestRecordResult) { + // 调用判题服务 + Problem problem = problemService.getById(judge.getPid()); + if (problem.getIsRemote()) { // 如果是远程oj判题 + remoteJudgeDispatcher.sendTask(judge, judgeToken, problem.getProblemId(), + isContestSubmission, 1, hasSubmitIdRemoteRejudge); + } else { + judgeDispatcher.sendTask(judge, judgeToken, isContestSubmission, 1); + } + return CommonResult.successResponse(judge, "重判成功!该提交已进入判题队列!"); + } else { + return CommonResult.successResponse(judge, "重判失败!请重新尝试!"); + } + } + + @Override + public CommonResult rejudgeContestProblem(Long cid, Long pid) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("cid", cid).eq("pid", pid); + List rejudgeList = judgeService.list(queryWrapper); + + if (rejudgeList.size() == 0) { + return CommonResult.errorResponse("当前该题目无提交,不可重判!"); + } + List submitIdList = new LinkedList<>(); + HashMap idMapStatus = new HashMap<>(); + // 全部设置默认值 + for (Judge judge : rejudgeList) { + idMapStatus.put(judge.getSubmitId(), judge.getStatus()); + judge.setStatus(Constants.Judge.STATUS_PENDING.getStatus()); // 开始进入判题队列 + judge.setVersion(judge.getVersion() + 1); + judge.setJudger("") + .setTime(null) + .setMemory(null) + .setErrorMessage(null) + .setOiRankScore(null) + .setScore(null); + submitIdList.add(judge.getSubmitId()); + } + boolean resetJudgeResult = judgeService.updateBatchById(rejudgeList); + // 清除每个提交对应的测试点结果 + QueryWrapper judgeCaseQueryWrapper = new QueryWrapper<>(); + judgeCaseQueryWrapper.in("submit_id", submitIdList); + judgeCaseService.remove(judgeCaseQueryWrapper); + // 将对应比赛记录设置成默认值 + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.in("submit_id", submitIdList).setSql("status=null,score=null"); + boolean resetContestRecordResult = contestRecordService.update(updateWrapper); + + if (resetContestRecordResult && resetJudgeResult) { + // 调用重判服务 + Problem problem = problemService.getById(pid); + if (problem.getIsRemote()) { // 如果是远程oj判题 + for (Judge judge : rejudgeList) { + // 进入重判队列,等待调用判题服务 + remoteJudgeDispatcher.sendTask(judge, judgeToken, problem.getProblemId(), + judge.getCid() != 0, 1, + isHasSubmitIdRemoteRejudge(judge.getVjudgeSubmitId(), idMapStatus.get(judge.getSubmitId()))); + } + } else { + for (Judge judge : rejudgeList) { + // 进入重判队列,等待调用判题服务 + judgeDispatcher.sendTask(judge, judgeToken, judge.getCid() != 0, 1); + } + } + + return CommonResult.successResponse(null, "重判成功!该题目对应的全部提交已进入判题队列!"); + } else { + return CommonResult.errorResponse("重判失败!请重新尝试!"); + } + } + + private boolean isHasSubmitIdRemoteRejudge(Long vjudgeSubmitId, int status) { + boolean isHasSubmitIdRemoteRejudge = false; + if (vjudgeSubmitId != null && + (status == Constants.Judge.STATUS_SUBMITTED_FAILED.getStatus() + || status == Constants.Judge.STATUS_COMPILING.getStatus() + || status == Constants.Judge.STATUS_PENDING.getStatus() + || status == Constants.Judge.STATUS_JUDGING.getStatus() + || status == Constants.Judge.STATUS_SYSTEM_ERROR.getStatus())) { + isHasSubmitIdRemoteRejudge = true; + } + return isHasSubmitIdRemoteRejudge; + } +} \ No newline at end of file diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/JudgeRun.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/JudgeRun.java index b8a87288..9b901b17 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/JudgeRun.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/JudgeRun.java @@ -74,7 +74,7 @@ public class JudgeRun { .userFileId(userFileId) .runDir(runDir) .testTime(testTime) - .maxMemory(problem.getMemoryLimit() * 1024L) + .maxMemory((long) problem.getMemoryLimit()) .maxTime((long) problem.getTimeLimit()) .maxStack(problem.getStackLimit()) .testCaseInfo(testCasesInfo) diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/SandboxRun.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/SandboxRun.java index 8abea6a2..7542ba19 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/SandboxRun.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/SandboxRun.java @@ -302,6 +302,7 @@ public class SandboxRun { List envs, String testCasePath, Long maxTime, + Long maxMemory, Long maxOutputSize, Integer maxStack, String exeName, @@ -332,7 +333,11 @@ public class SandboxRun { cmd.set("cpuLimit", maxTime * 1000 * 1000L); cmd.set("clockLimit", maxTime * 1000 * 1000L * 3); // byte - cmd.set("memoryLimit", MEMORY_LIMIT_MB * 1024 * 1024L); + if (maxMemory >= MEMORY_LIMIT_MB) { + cmd.set("memoryLimit", (maxMemory + 100) * 1024 * 1024L); + } else { + cmd.set("memoryLimit", MEMORY_LIMIT_MB * 1024 * 1024L); + } cmd.set("procLimit", maxProcessNumber); cmd.set("stackLimit", maxStack * 1024 * 1024L); @@ -413,6 +418,7 @@ public class SandboxRun { cmd.set("procLimit", maxProcessNumber); cmd.set("stackLimit", STACK_LIMIT_MB * 1024 * 1024L); + JSONObject spjExeFile = new JSONObject(); spjExeFile.set("src", spjExeSrc); @@ -475,6 +481,7 @@ public class SandboxRun { String userExeName, String userFileId, Long userMaxTime, + Long userMaxMemory, Integer userMaxStack, String testCaseInputPath, String testCaseInputFileName, @@ -509,10 +516,12 @@ public class SandboxRun { // ms-->ns pipeInputCmd.set("cpuLimit", userMaxTime * 1000 * 1000L); - pipeInputCmd.set("realCpuLimit", userMaxTime * 1000 * 1000L * 3); + pipeInputCmd.set("clockLimit", userMaxTime * 1000 * 1000L * 3); + // byte - pipeInputCmd.set("memoryLimit", MEMORY_LIMIT_MB * 1024 * 1024L); - pipeInputCmd.set("clockLimit", maxProcessNumber); + + pipeInputCmd.set("memoryLimit", (userMaxMemory + 100) * 1024 * 1024L); + pipeInputCmd.set("procLimit", maxProcessNumber); pipeInputCmd.set("stackLimit", userMaxStack * 1024 * 1024L); JSONObject exeFile = new JSONObject(); @@ -542,10 +551,10 @@ public class SandboxRun { pipeOutputCmd.set("files", JSONUtil.parseArray(outTmp, false)); // ms-->ns - pipeOutputCmd.set("cpuLimit", TIME_LIMIT_MS * 1000 * 1000L); - pipeOutputCmd.set("clockLimit", TIME_LIMIT_MS * 1000 * 1000L * 3); + pipeOutputCmd.set("cpuLimit", userMaxTime * 1000 * 1000L * 2); + pipeOutputCmd.set("clockLimit", userMaxTime * 1000 * 1000L * 3 * 2); // byte - pipeOutputCmd.set("memoryLimit", MEMORY_LIMIT_MB * 1024 * 1024L); + pipeOutputCmd.set("memoryLimit", (userMaxMemory + 100) * 1024 * 1024L * 2); pipeOutputCmd.set("procLimit", maxProcessNumber); pipeOutputCmd.set("stackLimit", STACK_LIMIT_MB * 1024 * 1024L); diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/entity/JudgeGlobalDTO.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/entity/JudgeGlobalDTO.java index 56cac770..00b3298d 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/entity/JudgeGlobalDTO.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/entity/JudgeGlobalDTO.java @@ -55,7 +55,7 @@ public class JudgeGlobalDTO implements Serializable { private Long maxTime; /** - * 当前题目评测的最大空间限制 kb + * 当前题目评测的最大空间限制 mb */ private Long maxMemory; diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/DefaultJudge.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/DefaultJudge.java index 550c947e..99cc9fe5 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/DefaultJudge.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/DefaultJudge.java @@ -30,6 +30,7 @@ public class DefaultJudge extends AbstractJudge { runConfig.getEnvs(), judgeDTO.getTestCaseInputPath(), judgeGlobalDTO.getTestTime(), + judgeGlobalDTO.getMaxMemory(), judgeDTO.getMaxOutputSize(), judgeGlobalDTO.getMaxStack(), runConfig.getExeName(), @@ -46,9 +47,9 @@ public class DefaultJudge extends AbstractJudge { if (sandBoxRes.getStatus().equals(Constants.Judge.STATUS_ACCEPTED.getStatus())) { // 对结果的时间损耗和空间损耗与题目限制做比较,判断是否mle和tle - if (sandBoxRes.getTime() >= judgeGlobalDTO.getMaxTime()) { + if (sandBoxRes.getTime() > judgeGlobalDTO.getMaxTime()) { result.set("status", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED.getStatus()); - } else if (sandBoxRes.getMemory() >= judgeGlobalDTO.getMaxMemory()) { + } else if (sandBoxRes.getMemory() > judgeGlobalDTO.getMaxMemory() * 1024) { result.set("status", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED.getStatus()); } else { // 与原测试数据输出的md5进行对比 AC或者是WA diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/InteractiveJudge.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/InteractiveJudge.java index 08463c92..bf8635af 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/InteractiveJudge.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/InteractiveJudge.java @@ -43,6 +43,7 @@ public class InteractiveJudge extends AbstractJudge { runConfig.getExeName(), judgeGlobalDTO.getUserFileId(), judgeGlobalDTO.getTestTime(), + judgeGlobalDTO.getMaxMemory(), judgeGlobalDTO.getMaxStack(), judgeDTO.getTestCaseInputPath(), testCaseInputFileName, @@ -69,37 +70,12 @@ public class InteractiveJudge extends AbstractJudge { StringBuilder errMsg = new StringBuilder(); int userExitCode = userSandBoxRes.getExitCode(); - - if (userSandBoxRes.getStatus().equals(Constants.Judge.STATUS_ACCEPTED.getStatus())) { - // 如果运行超过题目限制时间,直接TLE - if (userSandBoxRes.getTime() >= judgeGlobalDTO.getMaxTime()) { - result.set("status", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED.getStatus()); - } else if (userSandBoxRes.getMemory() >= judgeGlobalDTO.getMaxMemory()) { // 如果运行超过题目限制空间,直接MLE - result.set("status", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED.getStatus()); - } else { - // 根据交互程序的退出状态码及输出进行判断 - JSONObject interactiveCheckRes = checkInteractiveRes(interactiveSandBoxRes); - int code = interactiveCheckRes.getInt("code"); - if (code == SPJ_WA) { - result.set("status", Constants.Judge.STATUS_WRONG_ANSWER.getStatus()); - } else if (code == SPJ_AC) { - result.set("status", Constants.Judge.STATUS_ACCEPTED.getStatus()); - } else if (code == SPJ_PE) { - result.set("status", Constants.Judge.STATUS_PRESENTATION_ERROR.getStatus()); - } else if (code == SPJ_PC){ - result.set("status", Constants.Judge.STATUS_PARTIAL_ACCEPTED.getStatus()); - result.set("percentage", interactiveCheckRes.getDouble("percentage")); - } else { - result.set("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()); - } - - String spjErrMsg = interactiveCheckRes.getStr("errMsg"); - if (!StringUtils.isEmpty(spjErrMsg)) { - errMsg.append(spjErrMsg).append(" "); - } - } - } else if (userSandBoxRes.getStatus().equals(Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED.getStatus())) { + result.set("status", userSandBoxRes.getStatus()); + // 如果运行超过题目限制时间,直接TLE + if (userSandBoxRes.getTime() > judgeGlobalDTO.getMaxTime()) { result.set("status", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED.getStatus()); + } else if (userSandBoxRes.getMemory() > judgeGlobalDTO.getMaxMemory() * 1024) { // 如果运行超过题目限制空间,直接MLE + result.set("status", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED.getStatus()); } else if ((userExitCode != 0 && userExitCode != 13) || (userExitCode == 13 && interactiveSandBoxRes.getExitCode() == 0)) { // Broken Pipe result.set("status", Constants.Judge.STATUS_RUNTIME_ERROR.getStatus()); @@ -109,10 +85,28 @@ public class InteractiveJudge extends AbstractJudge { errMsg.append(String.format("Your program return exitCode: %s\n", userExitCode)); } } else { - result.set("status", interactiveSandBoxRes.getStatus()); - errMsg.append(interactiveSandBoxRes.getStderr()).append(" "); - if (interactiveSandBoxRes.getExitCode() !=0 && !StringUtils.isEmpty(interactiveSandBoxRes.getStderr())) { - errMsg.append(String.format("Interactive program exited with code: %s",interactiveSandBoxRes.getExitCode())); + // 根据交互程序的退出状态码及输出进行判断 + JSONObject interactiveCheckRes = checkInteractiveRes(interactiveSandBoxRes); + int code = interactiveCheckRes.getInt("code"); + if (code == SPJ_WA) { + result.set("status", Constants.Judge.STATUS_WRONG_ANSWER.getStatus()); + } else if (code == SPJ_AC) { + result.set("status", Constants.Judge.STATUS_ACCEPTED.getStatus()); + } else if (code == SPJ_PE) { + result.set("status", Constants.Judge.STATUS_PRESENTATION_ERROR.getStatus()); + } else if (code == SPJ_PC) { + result.set("status", Constants.Judge.STATUS_PARTIAL_ACCEPTED.getStatus()); + result.set("percentage", interactiveCheckRes.getDouble("percentage")); + } else { + result.set("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()); + } + + String spjErrMsg = interactiveCheckRes.getStr("errMsg"); + if (!StringUtils.isEmpty(spjErrMsg)) { + errMsg.append(spjErrMsg).append(" "); + } + if (interactiveSandBoxRes.getExitCode() != 0 && !StringUtils.isEmpty(interactiveSandBoxRes.getStderr())) { + errMsg.append(String.format("Interactive program exited with code: %s", interactiveSandBoxRes.getExitCode())); } } // kb diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/SpecialJudge.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/SpecialJudge.java index 16add7b9..ef7670ba 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/SpecialJudge.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/judge/task/SpecialJudge.java @@ -32,6 +32,7 @@ public class SpecialJudge extends AbstractJudge { runConfig.getEnvs(), judgeDTO.getTestCaseInputPath(), judgeGlobalDTO.getTestTime(), + judgeGlobalDTO.getMaxMemory(), judgeDTO.getMaxOutputSize(), judgeGlobalDTO.getMaxStack(), runConfig.getExeName(), @@ -53,9 +54,9 @@ public class SpecialJudge extends AbstractJudge { if (sandBoxRes.getStatus().equals(Constants.Judge.STATUS_ACCEPTED.getStatus())) { // 对结果的时间损耗和空间损耗与题目限制做比较,判断是否mle和tle - if (sandBoxRes.getTime() >= judgeGlobalDTO.getMaxTime()) { + if (sandBoxRes.getTime() > judgeGlobalDTO.getMaxTime()) { result.set("status", Constants.Judge.STATUS_TIME_LIMIT_EXCEEDED.getStatus()); - } else if (sandBoxRes.getMemory() >= judgeGlobalDTO.getMaxMemory()) { + } else if (sandBoxRes.getMemory() > judgeGlobalDTO.getMaxMemory() * 1024) { result.set("status", Constants.Judge.STATUS_MEMORY_LIMIT_EXCEEDED.getStatus()); } else { diff --git a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/ThreadPoolUtils.java b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/ThreadPoolUtils.java index 2a53b0a9..7d84f312 100644 --- a/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/ThreadPoolUtils.java +++ b/hoj-springboot/JudgeServer/src/main/java/top/hcode/hoj/util/ThreadPoolUtils.java @@ -18,9 +18,9 @@ public class ThreadPoolUtils { executorService = new ThreadPoolExecutor( cpuNum, // 核心线程数 cpuNum * 2, // 最大线程数。最多几个线程并发。 - 2,//当非核心线程无任务时,几秒后结束该线程 + 3,//当非核心线程无任务时,几秒后结束该线程 TimeUnit.SECONDS,// 结束线程时间单位 - new LinkedBlockingDeque<>(100 * cpuNum), //阻塞队列,限制等候线程数 + new LinkedBlockingDeque<>(200 * cpuNum), //阻塞队列,限制等候线程数 Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());//队列满了,尝试去和最早的竞争,也不会抛出异常! }