Skip to content

Commit

Permalink
(wip) checker compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
shine00chang committed Oct 9, 2024
1 parent feb08dc commit da218b5
Show file tree
Hide file tree
Showing 18 changed files with 166 additions and 202 deletions.
1 change: 1 addition & 0 deletions packages/api-server/src/routes/v1/contest.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import { userAuthHook } from '../../hooks/authentication.hooks.js'
import { contestInfoHook } from '../../hooks/contest.hooks.js'
import { requestUserProfile } from '../../utils/auth.utils.js'
import {fetchUser} from '../../services/user.services.js'
/*=*/

async function contestProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void> {
problemRoutes.addHook('onRequest', contestInfoHook)
Expand Down
13 changes: 10 additions & 3 deletions packages/api-server/src/routes/v1/domain.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ import {
} from '../../services/domain.services.js'
import { isSuperAdmin } from '../../auth/role.auth.js'
import { hasDomainPrivilege } from '../../auth/scope.auth.js'
import { type FastifyTypeBox } from '../../types.js'
import { createDomainProblem, deleteDomainProblem, fetchDomainProblems, updateDomainProblem } from '../../services/problem.services.js'
import { type FastifyTypeBox } from '../../types.js' /*=*/
import { deleteDomainProblem, fetchDomainProblems } from '../../services/problem.services.js'
import { fetchDomainProblem } from '@argoncs/common'
import { createTestingSubmission } from '../../services/submission.services.js'
import { createPolygonUploadSession, createUploadSession } from '../../services/testcase.services.js'
import { createPolygonUploadSession } from '../../services/testcase.services.js'
import { UnauthorizedError, badRequestSchema, forbiddenSchema, methodNotAllowedSchema, notFoundSchema, unauthorizedSchema } from 'http-errors-enhanced'
import { createContest, createContestSeries, fetchDomainContestSeries, fetchDomainContests } from '../../services/contest.services.js'
import { userAuthHook } from '../../hooks/authentication.hooks.js'
/*=*/

async function domainMemberRoutes (memberRoutes: FastifyTypeBox): Promise<void> {
memberRoutes.post(
Expand Down Expand Up @@ -134,6 +135,7 @@ async function domainMemberRoutes (memberRoutes: FastifyTypeBox): Promise<void>
}

async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void> {
/*
problemRoutes.post(
'/',
{
Expand All @@ -158,6 +160,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
return await reply.status(201).send(created)
}
)
*/

problemRoutes.get(
'/',
Expand All @@ -182,6 +185,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
}
)

/*
problemRoutes.put(
'/:problemId',
{
Expand All @@ -207,6 +211,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
return await reply.status(200).send({ modified })
}
)
*/

problemRoutes.delete(
'/:problemId',
Expand Down Expand Up @@ -286,6 +291,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
}
)

/*
problemRoutes.get(
'/:problemId/upload-session',
{
Expand All @@ -309,6 +315,7 @@ async function domainProblemRoutes (problemRoutes: FastifyTypeBox): Promise<void
await reply.status(200).send({ uploadId })
}
)
*/

problemRoutes.get(
'/polygon-upload-session',
Expand Down
8 changes: 6 additions & 2 deletions packages/api-server/src/services/problem.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ import { testcaseExists } from './testcase.services.js'

import { nanoid } from 'nanoid'

/*
export async function createDomainProblem ({ newProblem, domainId }: { newProblem: NewProblem, domainId: string }): Promise<{ problemId: string }> {
const problemId = nanoid()
const problem: Problem = { ...newProblem, id: problemId, domainId }
await domainProblemCollection.insertOne(problem)
return { problemId }
}
*/

/*
export async function updateDomainProblem ({ problemId, domainId, problem }: { problemId: string, domainId: string, problem: Partial<NewProblem> }): Promise<{ modified: boolean }> {
if (problem.testcases != null) {
const testcasesVerifyQueue: Array<Promise<void>> = []
problem.testcases.forEach((testcase) => {
testcasesVerifyQueue.push(testcaseExists({ problemId, domainId, filename: testcase.input.name, versionId: testcase.input.versionId }))
testcasesVerifyQueue.push(testcaseExists({ problemId, domainId, filename: testcase.output.name, versionId: testcase.output.versionId }))
testcasesVerifyQueue.push(testcaseExists({ problemId, filename: testcase.input.name, versionId: testcase.input.versionId }))
testcasesVerifyQueue.push(testcaseExists({ problemId, filename: testcase.output.name, versionId: testcase.output.versionId }))
})
await Promise.all(testcasesVerifyQueue)
}
Expand All @@ -32,6 +35,7 @@ export async function updateDomainProblem ({ problemId, domainId, problem }: { p
return { modified: modifiedCount > 0 }
}
*/

export async function deleteDomainProblem ({ problemId, domainId }: { problemId: string, domainId: string }): Promise<void> {
const session = mongoClient.startSession()
Expand Down
7 changes: 4 additions & 3 deletions packages/api-server/src/services/testcase.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import { fetchDomainProblem, minio, uploadSessionCollection } from '@argoncs/com
import path = require('node:path')
import { nanoid } from 'nanoid'

export async function testcaseExists ({ problemId, domainId, filename, versionId }: { problemId: string, domainId: string, filename: string, versionId: string }): Promise<void> {
const objectName = path.join(domainId, problemId, filename)
export async function testcaseExists ({ problemId, filename, versionId }: { problemId: string, filename: string, versionId: string }): Promise<void> {
try {
const stat = await minio.statObject('testcases', objectName, { versionId })
const stat = await minio.statObject('testcases', path.join(problemId, filename), { versionId })

if (stat == null || stat.versionId !== versionId) {
throw new NotFoundError('One of the testcases not found')
Expand All @@ -17,12 +16,14 @@ export async function testcaseExists ({ problemId, domainId, filename, versionId
}
}

/*
export async function createUploadSession ({ problemId, domainId }: { problemId: string, domainId: string }): Promise<{ uploadId: string }> {
const id = nanoid(32)
await fetchDomainProblem({ problemId, domainId }) // Could throw not found
await uploadSessionCollection.insertOne({ id, problemId, domainId, createdAt: (new Date()).getTime() })
return { uploadId: id }
}
*/

export async function createPolygonUploadSession ({ domainId }: { domainId: string }): Promise<{ uploadId: string }> {
const id = nanoid(32)
Expand Down
117 changes: 0 additions & 117 deletions packages/judge-daemon/bits/stdc++.h

This file was deleted.

30 changes: 25 additions & 5 deletions packages/judge-daemon/src/services/compile.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { promises as fs } from 'node:fs'

import { runInSandbox } from './sandbox.services.js'

import { type CompilingTask, SandboxStatus, type CompileSucceeded, type CompileFailed, CompilingStatus, type CompilingCheckerTask } from '@argoncs/types'
import { type CompilingTask, SandboxStatus, type CompileSucceeded, type CompileFailed, CompilingStatus, type CompilingCheckerTask, CompilingCheckerResult } from '@argoncs/types'
import { minio } from '@argoncs/common'
import { languageConfigs } from '../../configs/language.configs.js'

Expand Down Expand Up @@ -50,7 +50,7 @@ export async function compileSubmission ({ task, boxId }: { task: CompilingTask,
}
}

export async function compileChecker ({ task, boxId }: { task: CompilingCheckerTask, boxId: number })
export async function compileChecker ({ task, boxId }: { task: CompilingCheckerTask, boxId: number }): Promise<CompilingCheckerResult>
{
const workDir = `/var/local/lib/isolate/${boxId}/box`
const srcPath = path.join(workDir, 'checker.cpp')
Expand All @@ -74,9 +74,29 @@ export async function compileChecker ({ task, boxId }: { task: CompilingCheckerT
})

console.log('compiled checker')
if (result.status !== SandboxStatus.Succeeded)
throw `Checker compilation for problem ${task.problemId} failed`

await minio.fPutObject('checkers', task.problemId, binaryPath)
if (result.status !== SandboxStatus.Succeeded)
return {
status: CompilingStatus.Failed,
log: (await fs.readFile(logPath)).toString()
}

const { versionId } = await minio.putObject('checkers', task.problemId, binaryPath)

if (versionId === null)
return {
status: CompilingStatus.Failed,
log: 'failed to put into bucket'
}

console.log("checker put'ed")

const log = (await fs.readFile(logPath)).toString()
return {
status: CompilingStatus.Succeeded,
checker: {
name: task.problemId,
versionId
}
}
}
5 changes: 1 addition & 4 deletions packages/judge-daemon/src/services/grading.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ export async function gradeSubmission ({ task, boxId }: { task: GradingTask, box
await fetchTestcase({ objectName: task.testcase.input.objectName, versionId: task.testcase.input.versionId, destPath: inputPath })
await fetchTestcase({ objectName: task.testcase.output.objectName, versionId: task.testcase.output.versionId, destPath: answerPath })
await makeExecutable(path.join(workDir, config.binaryFile))
await fetchChecker({
objectName: task.checker.objectName,
versionId: task.checker.versionId,
destPath: checkerPath })
await fetchChecker({ objectName: task.checker.objectName, versionId: task.checker.versionId, destPath: checkerPath })

let command = config.executeCommand
command = command.replaceAll('{binary_path}', config.binaryFile)
Expand Down
9 changes: 4 additions & 5 deletions packages/judge-daemon/src/services/storage.services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,21 @@ export async function fetchBinary ({ objectName, destPath }: { objectName: strin
async function cacheChecker ({ objectName, versionId }: { objectName: string, versionId: string }): Promise<void> {
// TODO: try catch. checker may not exist, throw something.
try {
const key = path.join(cacheDir, 'checkers', objectName, versionId)
const key = path.join(cacheDir, 'checkers', objectName)
const size = (await minio.statObject('checkers', objectName, { versionId })).size


// @ts-expect-error typing bug
minio.fGetObject('checkers', objectName, key, { versionId })
cache.set(key, key, { size })

} catch (err) {
console.log('cache checker error:', err)
throw "not found cache"
throw "none such checker"
}
}

export async function fetchChecker ({ objectName, versionId, destPath }: { objectName: string, versionId: string, destPath: string }): Promise<void> {
const key = path.join(cacheDir, 'checkers', objectName, versionId)
const key = path.join(cacheDir, 'checkers', objectName)
if (cache.get(key) != null) {
await fs.copyFile(key, destPath); return
}
Expand All @@ -102,7 +101,7 @@ export async function fetchChecker ({ objectName, versionId, destPath }: { objec
await fs.copyFile(key, destPath)
}
} else {
downloading.set(key, cacheTestcase({ objectName, versionId }))
downloading.set(key, cacheChecker({ objectName, versionId }))
await downloading.get(key)
downloading.delete(key)
await fs.copyFile(key, destPath)
Expand Down
17 changes: 11 additions & 6 deletions packages/judge-daemon/src/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { destroySandbox, initSandbox } from './services/sandbox.services.js'
import { gradeSubmission } from './services/grading.services.js'
import { compileChecker, compileSubmission } from './services/compile.services.js'

import { type GradingTask, type CompilingTask, JudgerTaskType, type GradingResultMessage, JudgerResultType, type CompilingResultMessage, CompilingCheckerTask } from '@argoncs/types'
import { type GradingTask, type CompilingTask, JudgerTaskType, type GradingResultMessage, JudgerResultType, type CompilingResultMessage, CompilingCheckerTask, CompilingCheckerResultMessage } from '@argoncs/types'
import { rabbitMQ, judgerTasksQueue, judgerExchange, judgerResultsKey, sentry, connectRabbitMQ, connectMinIO } from '@argoncs/common'

import os = require('node:os')
Expand Down Expand Up @@ -68,21 +68,26 @@ export async function startJudger (): Promise<void>
//await initSandbox({ boxId })

if (task.type === JudgerTaskType.CompilingChecker) {
compileChecker({ task, boxId });
const result: CompilingCheckerResultMessage = {
type: JudgerResultType.CompilingChecker,
result: await compileChecker({ task, boxId }),
problemId: task.problemId,
}
rabbitMQ.publish(judgerExchange, judgerResultsKey, Buffer.from(JSON.stringify(result)))
} else
if (task.type === JudgerTaskType.Grading) {
const result = {
const result: GradingResultMessage = {
type: JudgerResultType.Grading,
result: (await gradeSubmission({ task, boxId })),
result: await gradeSubmission({ task, boxId }),
submissionId: task.submissionId,
testcaseIndex: task.testcaseIndex
}
rabbitMQ.publish(judgerExchange, judgerResultsKey, Buffer.from(JSON.stringify(result)))
} else
if (task.type === JudgerTaskType.Compiling) {
const result = {
const result: CompilingResultMessage = {
type: JudgerResultType.Compiling,
result: (await compileSubmission({ task, boxId })),
result: await compileSubmission({ task, boxId }),
submissionId: task.submissionId
}
rabbitMQ.publish(judgerExchange, judgerResultsKey, Buffer.from(JSON.stringify(result)))
Expand Down
Loading

0 comments on commit da218b5

Please sign in to comment.