青島大學OnlineJudge如何judge程式

在OnlineJudge的Dockerfile

Step1)在OnlineJudge/submission/views/oj.py的SubmissionAPI的post中的Submission.objects.create,使用者需要評判的程式放到資料表Submission的code欄位,呼叫judge_task.send函式。

Step2)judge_task函式定義在judge.tasks (OnlineJudge/judge/tasks.py),將submission_id與problem_id傳入JudgeDispatcher(submission_id, problem_id).judge()

Step3)JudgeDispatcher(submission_id, problem_id).judge()定義在OnlineJudge/judge/dispatcher.py,根據submission_id從資料庫取出語言、程式碼放於字典data,使用字典data為輸入,呼叫self._request(urljoin(server.service_url, "/judge"), data=data),呼叫網址為「server.service_url, "/judge"」的JudgeServer

Step4)在JudgeServer/server/server.py,瀏覽「/judge」執行getattr(JudgeServer, path)(**data)相當於呼叫JudgeServer.judge函式以**data為輸入,data為request.json(相當於上一步的data輸入self._request(urljoin(server.service_url, "/judge"), data=data))

Step5)JudgeServer.judge函式也是定義在JudgeServer/server/server.py,呼叫judge_client.JudgeClient.run編譯與執行程式。

Step6)在JudgeServer/server/judge_client.py,judge_client.JudgeClient.run函式,呼叫self._pool.apply_async(_run, (self, test_case_file_id)),相當於呼叫_run函式,以測試資料的id為輸入。

Step7)在JudgeServer/server/judge_client.py,_run函式會呼叫_judge_one函式,_judge_one函式會呼叫_judger.run,編譯與執行程式,結果回傳給 run_result,呼叫self._compare_output函式判斷是否AC通過。

Step8)而_judger.run為何可以編譯並執行程式,需要分析_judge模組(結合Python與C語言),在JudgeServer/Dockerfile,可以發現「cd /tmp && git clone -b newnew --depth 1 https://github.com/QingdaoU/Judger && cd Judger 」下載Jodger的原始碼,使用「mkdir build && cd build && cmake .. && make && make install 」使用cmake編譯與make安裝Judger函式庫。使用「 cd ../bindings/Python && python3 setup.py install」安裝Python函式庫。

Step9)cmake使用Judger/CMakeLists.txt進行編譯產生函式庫libjudger.so,安裝在/usr/lib/judger資料夾下,Judge資料夾下的src與src/rules的C語言程式,這些C語言負責編譯與執行程式,並回傳結果。

Step10)執行「python3 setup.py install」會使用Judger/bindings/Python/_judger/__init__.py 建立Python函式庫_judger,呼叫_judger.run就會呼叫/usr/lib/judger/libjudger.so。

參考資料

青島大學OnlineJudge(https://github.com/QingdaoU)

Flask 的routing說明(https://flask.programmingpedia.net/en/tutorial/2415/routing)