Compare commits

...
2 Commits
Author SHA1 Message Date
xuyue 46d3fe2dbe Update home.vue
Deploy / deploy (push) Canceled after 0s
2026-11-02 22:28:04 +08:00
xuyueandClaude Opus 5.5 bc42ade705 fix(判题): SQL 题判题也排队占名额,和别的判题一起抢那两个核时不再被误判超时
SQL 子进程在 worker 里跑,原来不经判题名额(judge/slots.ts):两道 SQL、两道沙箱判题、
再加流程图试运行可以同时压在服务器两个核上,SQL 的时限按墙钟算,挤的时候本来不超时的
语句会被判成超时。现在和沙箱判题占同一个池,一个名额管整份提交,租约按每个测试点
最长可能占的时间算。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 21:57:05 +08:00
3 changed files with 30 additions and 3 deletions

No files matched your search

+20 -1
View File
@@ -14,7 +14,7 @@ import type { JudgeJobData } from './job'
import { isAccepted, JudgeStatus, type JudgeStatusValue } from './status'
import { parseProblemTemplate, shiftCompileLines } from './template'
import { withJudgeSlot } from './slots'
import { runSqlCase } from './sql'
import { runSqlCase, sqlCaseBudgetMs } from './sql'
import { nativeRuntimeError, parsePythonTraceback, type RuntimeErrorInfo } from './runtime-diagnosis'
import { compileError, judge, JudgeUnreachableError, type JudgeCase, type JudgeResponse } from './sandbox'
import { readInfo } from '../services/test-case'
@@ -625,6 +625,25 @@ async function judgeSqlSubmission(problem: typeof schema.problem.$inferSelect, s
const keys = Object.keys(info.test_cases ?? {}).sort((a, b) => Number(a) - Number(b))
if (keys.length === 0) throw new Error('题目没有任何测试点')
/**
* 和沙箱判题占同一个池的名额(judge/slots.ts):SQL 子进程在 worker 里跑,同样吃服务器
* 那两个核,原来不排队 —— 两道 SQL 加两道沙箱判题、再加流程图试运行一起压上去,
* 按墙钟算的 SQL 时限就会把本来不超时的语句判成超时。一个名额管整份提交,和沙箱那边一样。
* 租约按每个测试点最长可能占的时间算,再加 30 秒
*/
const holdMs = keys.length * sqlCaseBudgetMs(problem.timeLimit) + 30_000
return withJudgeSlot('judge', { holdMs }, () => judgeSqlCases(problem, keys, info, refSql, studentSql, mode, sqlConfig))
}
async function judgeSqlCases(
problem: typeof schema.problem.$inferSelect,
keys: string[],
info: NonNullable<Awaited<ReturnType<typeof readInfo>>>,
refSql: string,
studentSql: string,
mode: 'query' | 'modify',
sqlConfig: Record<string, unknown>,
): Promise<JudgeResponse> {
const cases: JudgeCase[] = []
for (const [index, key] of keys.entries()) {
const inputName = info.test_cases![key]!.input_name
+8
View File
@@ -172,6 +172,14 @@ async function runJob<T>(job: SqlJob, budget: JobBudget): Promise<SqlJobOutcome<
}
}
/**
* 一个测试点最长可能占多久:受信阶段的预算 + 启动余量,进了学生阶段换成题目时限 + 余量。
* 判题名额的租约(judge/slots.ts)按它算,租约比这短的话跑到一半名额会被别人拿走
*/
export function sqlCaseBudgetMs(timeLimitMs: number) {
return trustedBudgetMs(timeLimitMs) + STARTUP_SLACK_MS + timeLimitMs + STUDENT_SLACK_MS
}
export function runSqlCase(job: Extract<SqlJob, { kind: 'judge' }>) {
return runJob<CaseResult>(job, {
trustedMs: trustedBudgetMs(job.timeLimitMs),
+2 -2
View File
@@ -206,13 +206,13 @@ onUnmounted(stopRolling)
</div>
<div class="lucky">
<b class="lucky-title">抽一个人</b>
<b class="lucky-title">抽签</b>
<n-select v-model:value="luckyClass" :options="classOptions" filterable placeholder="选班级" aria-label="班级" class="lucky-select" />
<span :key="pulseKey" class="lucky-name" :class="{ pulse: !isRolling && luckyGuy }">
{{ luckyGuy }}
</span>
<n-button type="primary" :disabled="!luckyClass || isRolling" @click="draw">
{{ luckyGuy ? '再抽一个' : '抽' }}
{{ luckyGuy ? '再抽一个' : '抽一个人' }}
</n-button>
</div>
</template>