修改判题数据库

This commit is contained in:
virusdefender 2015-08-17 12:48:10 +08:00
parent 3f76df3079
commit 537da5d795
18 changed files with 217 additions and 113 deletions

View File

@ -1,9 +1,7 @@
# coding=utf-8 # coding=utf-8
import sys import sys
import os import json
import pymongo import MySQLdb
from bson.objectid import ObjectId
from client import JudgeClient from client import JudgeClient
from language import languages from language import languages
@ -11,9 +9,7 @@ from compiler import compile_
from result import result from result import result
from settings import judger_workspace from settings import judger_workspace
sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/' + '..')) from settings import submission_db
from judger_controller.settings import celery_mongodb_config, docker_mongodb_config
# 简单的解析命令行参数 # 简单的解析命令行参数
@ -25,19 +21,31 @@ time_limit = args[4]
memory_limit = args[6] memory_limit = args[6]
test_case_id = args[8] test_case_id = args[8]
connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"]
submission = collection.find_one({"_id": ObjectId(submission_id)}) def db_conn():
if not submission: return MySQLdb.connect(db=submission_db["db"],
user=submission_db["user"],
passwd=submission_db["password"],
host=submission_db["host"],
port=submission_db["port"], charset="utf8")
conn = db_conn()
cur = conn.cursor()
cur.execute("select language, code from submission where id = %s", (submission_id,))
data = cur.fetchall()
if not data:
exit() exit()
connection.close() language_code = data[0][0]
code = data[0][1]
conn.close()
# 将代码写入文件 # 将代码写入文件
language = languages[submission["language"]] language = languages[language_code]
src_path = judger_workspace + "run/" + language["src_name"] src_path = judger_workspace + "run/" + language["src_name"]
f = open(src_path, "w") f = open(src_path, "w")
f.write(submission["code"].encode("utf8")) f.write(code.encode("utf8"))
f.close() f.close()
# 编译 # 编译
@ -45,23 +53,23 @@ try:
exe_path = compile_(language, src_path, judger_workspace + "run/") exe_path = compile_(language, src_path, judger_workspace + "run/")
except Exception as e: except Exception as e:
print e print e
connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"]) conn = db_conn()
collection = connection["oj"]["oj_submission"] cur = conn.cursor()
data = {"result": result["compile_error"], "info": str(e)} cur.execute("update submission set result=%s, info=%s where id=%s",
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data}) (result["compile_error"], str(e), submission_id))
connection.close() conn.commit()
exit() exit()
print "Compile successfully" print "Compile successfully"
# 运行 # 运行
try: try:
client = JudgeClient(language_code=submission["language"], client = JudgeClient(language_code=language_code,
exe_path=exe_path, exe_path=exe_path,
max_cpu_time=int(time_limit), max_cpu_time=int(time_limit),
max_real_time=int(time_limit) * 2, max_real_time=int(time_limit) * 2,
max_memory=int(memory_limit), max_memory=int(memory_limit),
test_case_dir=judger_workspace + "test_case/" + test_case_id + "/") test_case_dir=judger_workspace + "test_case/" + test_case_id + "/")
judge_result = {"result": result["accepted"], "info": client.run()} judge_result = {"result": result["accepted"], "info": client.run(), "accepted_answer_time": None}
for item in judge_result["info"]: for item in judge_result["info"]:
if item["result"]: if item["result"]:
@ -69,15 +77,23 @@ try:
break break
else: else:
l = sorted(judge_result["info"], key=lambda k: k["cpu_time"]) l = sorted(judge_result["info"], key=lambda k: k["cpu_time"])
judge_result["accepted_answer_info"] = {"time": l[-1]["cpu_time"]} judge_result["accepted_answer_time"] = l[-1]["cpu_time"]
except Exception as e: except Exception as e:
print e print e
judge_result = {"result": result["system_error"], "info": str(e)} conn = db_conn()
cur = conn.cursor()
cur.execute("update submission set result=%s, info=%s where id=%s", (result["system_error"], str(e), submission_id))
conn.commit()
exit()
print "Run successfully" print "Run successfully"
print judge_result print judge_result
connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"] conn = db_conn()
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": judge_result}) cur = conn.cursor()
connection.close() cur.execute("update submission set result=%s, info=%s, accepted_answer_time=%s where id=%s",
(judge_result["result"], json.dumps(judge_result["info"]), judge_result["accepted_answer_time"],
submission_id))
conn.commit()
conn.close()

View File

@ -15,3 +15,11 @@ lrun_gid = 1002
judger_workspace = "/var/judger/" judger_workspace = "/var/judger/"
# 这个是在docker 中访问数据库 ip 不一定和web服务器还有celery的一样
submission_db = {
"host": "192.168.59.3",
"port": 3306,
"db": "oj_submission",
"user": "root",
"password": "root"
}

View File

@ -4,6 +4,4 @@ from celery import Celery
from .settings import redis_config from .settings import redis_config
app = Celery("judge", broker='redis://%s:%s/%s' % (redis_config["host"], redis_config["port"], redis_config["db"]), app = Celery("judge", broker='redis://%s:%s/%s' % (redis_config["host"], redis_config["port"], redis_config["db"]),
include=["judge.judger_controller.tasks"]) include=["judge.judger_controller.tasks"])
Celery().conf.update(CELERY_ACCEPT_CONTENT = ['json'])

View File

@ -7,7 +7,7 @@ redis_config = {
docker_config = { docker_config = {
"image_name": "d622347336b8", "image_name": " a7673b55d263",
"docker_path": "docker", "docker_path": "docker",
"shell": True "shell": True
} }
@ -17,16 +17,10 @@ test_case_dir = "/root/test_case/"
source_code_dir = "/root/" source_code_dir = "/root/"
celery_mongodb_config = { submission_db = {
"host": "127.0.0.1", "host": "127.0.0.1",
"username": "root", "port": 3306,
"password": "root", "db": "oj_submission",
"port": 27017 "user": "root",
} "password": "root"
docker_mongodb_config = {
"host": "192.168.42.1",
"username": "root",
"password": "root",
"port": 27017
} }

View File

@ -1,11 +1,10 @@
# coding=utf-8 # coding=utf-8
# from __future__ import absolute_import # from __future__ import absolute_import
import MySQLdb
import subprocess import subprocess
import pymongo
from bson import ObjectId
from ..judger.result import result from ..judger.result import result
from ..judger_controller.celery import app from ..judger_controller.celery import app
from settings import docker_config, source_code_dir, test_case_dir, celery_mongodb_config from settings import docker_config, source_code_dir, test_case_dir, submission_db
@app.task @app.task
@ -24,8 +23,16 @@ def judge(submission_id, time_limit, memory_limit, test_case_id):
submission_id, str(time_limit), str(memory_limit), test_case_id) submission_id, str(time_limit), str(memory_limit), test_case_id)
subprocess.call(command, shell=docker_config["shell"]) subprocess.call(command, shell=docker_config["shell"])
except Exception as e: except Exception as e:
connection = pymongo.MongoClient(host=celery_mongodb_config["host"], port=celery_mongodb_config["port"]) print e
collection = connection["oj"]["oj_submission"] conn = MySQLdb.connect(db=submission_db["db"],
data = {"result": result["system_error"], "info": str(e)} user=submission_db["user"],
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data}) passwd=submission_db["password"],
connection.close() host=submission_db["host"],
port=submission_db["port"],
character="utf8")
cur = conn.cursor()
cur.execute("update submission set result=%s, info=%s where id=%s",
(result["system_error"], str(e), submission_id))
conn.commit()
conn.close()

30
oj/db_router.py Normal file
View File

@ -0,0 +1,30 @@
# coding=utf-8
class DBRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'submission':
return 'submission'
return "default"
def db_for_write(self, model, **hints):
if model._meta.app_label == 'submission':
return 'submission'
return "default"
def allow_relation(self, obj1, obj2, **hints):
return True
def allow_migrate(self, db, app_label, model=None, **hints):
if app_label == "submission":
if db == "submission":
r = True
else:
r = False
else:
if db == "default":
r = True
else:
r = False
print db, app_label, r
return r

View File

@ -7,24 +7,26 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 下面是需要自己修改的 # 下面是需要自己修改的
LOG_PATH = "LOG/" LOG_PATH = "LOG/"
# 注意这是web 服务器访问的地址,判题度武器访问的地址不一定一样,因为可能不在一台机器上 # 注意这是web 服务器访问的地址,判题访问的地址不一定一样,因为可能不在一台机器上
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'CONN_MAX_AGE': 0.3, 'CONN_MAX_AGE': 0.3,
},
'submission': {
'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql',
'HOST': "121.42.32.129",
'POST': 3306,
'USER': 'root',
'PASSWORD': 'mypwd'
} }
} }
# 这是web 服务器连接到mongodb 的地址
MONGODB = {
'HOST': '121.42.32.129',
'USERNAME': 'root',
'PASSWORD': 'root',
'PORT': 27017
}
DEBUG = True DEBUG = True
# 同理 这是 web 服务器的上传路径 # 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case') TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
DATABASE_ROUTERS = ['oj.db_router.DBRouter']

View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('problem', '0006_merge'),
]
operations = [
migrations.RemoveField(
model_name='problem',
name='last_update_time',
),
]

View File

@ -29,7 +29,7 @@ class AbstractProblem(models.Model):
# 创建时间 # 创建时间
create_time = models.DateTimeField(auto_now_add=True) create_time = models.DateTimeField(auto_now_add=True)
# 最后更新时间 # 最后更新时间
last_update_time = models.DateTimeField(auto_now=True) # last_update_time = models.DateTimeField(auto_now=True)
# 这个题是谁创建的 # 这个题是谁创建的
created_by = models.ForeignKey(User) created_by = models.ForeignKey(User)
# 来源 # 来源

View File

@ -156,8 +156,8 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
$id: "addProblem", $id: "addProblem",
title: "", title: "",
description: "", description: "",
cpu: 1000, timeLimit: 1000,
memory: 256, memoryLimit: 256,
samples: [{input: "", output: "", "visible": true}], samples: [{input: "", output: "", "visible": true}],
hint: "", hint: "",
visible: true, visible: true,

View File

@ -46,7 +46,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
results[data.result].message + results[data.result].message +
'!   '; '!   ';
if (!data.result) { if (!data.result) {
html += "CPU time: " + data.accepted_answer_info.time + "ms   "; html += "CPU time: " + data.accepted_answer_time + "ms   ";
} }
html += ('<a href="/my_submission/' + submissionId + '/" target="_blank">查看详情</a></div> </div>'); html += ('<a href="/my_submission/' + submissionId + '/" target="_blank">查看详情</a></div> </div>');

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import utils.shortcuts
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='Submission',
fields=[
('id', models.CharField(default=utils.shortcuts.rand_str, max_length=32, serialize=False, primary_key=True, db_index=True)),
('user_id', models.IntegerField()),
('create_time', models.DateTimeField(auto_now_add=True)),
('result', models.IntegerField(default=8)),
('language', models.IntegerField()),
('code', models.TextField()),
('problem_id', models.IntegerField()),
('info', models.TextField(null=True, blank=True)),
('accepted_answer_time', models.IntegerField(null=True, blank=True)),
('accepted_answer_info', models.TextField(null=True, blank=True)),
],
options={
'db_table': 'submission',
},
),
]

View File

@ -1 +1,23 @@
# coding=utf-8 # coding=utf-8
from django.db import models
from utils.shortcuts import rand_str
from judge.judger.result import result
class Submission(models.Model):
id = models.CharField(max_length=32, default=rand_str, primary_key=True, db_index=True)
user_id = models.IntegerField()
create_time = models.DateTimeField(auto_now_add=True)
result = models.IntegerField(default=result["waiting"])
language = models.IntegerField()
code = models.TextField()
problem_id = models.IntegerField()
# 这个字段可能存储很多数据 比如编译错误、系统错误的时候,存储错误原因字符串
# 正常运行的时候存储 lrun 的判题结果比如cpu时间内存之类的
info = models.TextField(blank=True, null=True)
accepted_answer_time = models.IntegerField(blank=True, null=True)
# 这个字段只有在题目是accepted 的时候才会用到,比赛题目的提交可能还会有得分等信息,存储在这里面
accepted_answer_info = models.TextField(blank=True, null=True)
class Meta:
db_table = "submission"

View File

@ -1,28 +1,19 @@
# coding=utf-8 # coding=utf-8
import datetime import json
import pymongo
from bson.objectid import ObjectId
from django.shortcuts import render from django.shortcuts import render
from rest_framework.views import APIView from rest_framework.views import APIView
from django.conf import settings
from judge.judger.result import result from judge.judger.result import result
from judge.judger_controller.tasks import judge from judge.judger_controller.tasks import judge
from account.decorators import login_required from account.decorators import login_required
from problem.models import Problem from problem.models import Problem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page
from .models import Submission
from .serializers import CreateSubmissionSerializer from .serializers import CreateSubmissionSerializer
def _create_mongodb_connection():
mongodb_setting = settings.MONGODB
connection = pymongo.MongoClient(host=mongodb_setting["HOST"], port=mongodb_setting["PORT"])
return connection["oj"]["oj_submission"]
class SubmissionAPIView(APIView): class SubmissionAPIView(APIView):
@login_required @login_required
def post(self, request): def post(self, request):
@ -34,23 +25,19 @@ class SubmissionAPIView(APIView):
serializer = CreateSubmissionSerializer(data=request.data) serializer = CreateSubmissionSerializer(data=request.data)
if serializer.is_valid(): if serializer.is_valid():
data = serializer.data data = serializer.data
# data["language"] = int(data["language"])
data["user_id"] = request.user.id
data["result"] = result["waiting"]
data["create_time"] = datetime.datetime.now()
try: try:
problem = Problem.objects.get(id=data["problem_id"]) problem = Problem.objects.get(id=data["problem_id"])
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"题目不存在")
collection = _create_mongodb_connection() submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
submission_id = str(collection.insert_one(data).inserted_id) code=data["code"], problem_id=problem.id)
try: try:
judge.delay(submission_id, problem.time_limit, problem.memory_limit, problem.test_case_id) judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception: except Exception:
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
return success_response({"submission_id": submission_id}) return success_response({"submission_id": submission.id})
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)
@ -59,41 +46,36 @@ class SubmissionAPIView(APIView):
submission_id = request.GET.get("submission_id", None) submission_id = request.GET.get("submission_id", None)
if not submission_id: if not submission_id:
return error_response(u"参数错误") return error_response(u"参数错误")
submission = _create_mongodb_connection().find_one({"_id": ObjectId(submission_id), "user_id": request.user.id}) try:
if submission: submission = Submission.objects.get(id=submission_id, user_id=request.user.id)
response_data = {"result": submission["result"]} except Submission.DoesNotExist:
if submission["result"] == 0:
response_data["accepted_answer_info"] = submission["accepted_answer_info"]
return success_response(response_data)
else:
return error_response(u"提交不存在") return error_response(u"提交不存在")
response_data = {"result": submission.result}
if submission.result == 0:
response_data["accepted_answer_time"] = submission.accepted_answer_time
return success_response(response_data)
@login_required @login_required
def problem_my_submissions_list_page(request, problem_id): def problem_my_submissions_list_page(request, problem_id):
collection = _create_mongodb_connection()
submissions = collection.find({"problem_id": int(problem_id), "user_id": request.user.id},
projection=["result", "accepted_answer_info", "create_time", "language"],
sort=[["create_time", -pymongo.ASCENDING]])
try: try:
problem = Problem.objects.get(id=problem_id, visible=True) problem = Problem.objects.get(id=problem_id, visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"问题不存在") return error_page(request, u"问题不存在")
submissions = Submission.objects.filter(user_id=request.user.id, problem_id=problem.id).order_by("-create_time")
return render(request, "oj/problem/my_submissions_list.html", return render(request, "oj/problem/my_submissions_list.html",
{"submissions": submissions, "problem": problem}) {"submissions": submissions, "problem": problem})
@login_required @login_required
def my_submission(request, submission_id): def my_submission(request, submission_id):
collection = _create_mongodb_connection() try:
submission = collection.find_one({"user_id": request.user.id, "_id": ObjectId(submission_id)}, submission = Submission.objects.get(id=submission_id)
projection=["result", "accepted_answer_info", "create_time", except Submission.DoesNotExist:
"language", "code", "problem_id", "info"])
if not submission:
return error_page(request, u"提交不存在") return error_page(request, u"提交不存在")
try: try:
problem = Problem.objects.get(id=submission["problem_id"], visible=True) problem = Problem.objects.get(id=submission.problem_id, visible=True)
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_page(request, u"提交不存在") return error_page(request, u"提交不存在")
return render(request, "oj/problem/my_submission.html",
return render(request, "oj/problem/my_submission.html", {"submission": submission, "problem": problem}) {"submission": submission, "problem": problem})

View File

@ -15,12 +15,12 @@
<div class="col-md-3"> <div class="col-md-3">
<div class="form-group"><label>时间限制(ms)</label> <div class="form-group"><label>时间限制(ms)</label>
<input type="number" name="cpu" class="form-control" ms-duplex="cpu"> <input type="number" name="cpu" class="form-control" ms-duplex="timeLimit">
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<div class="form-group"><label>内存限制(MB)</label> <div class="form-group"><label>内存限制(MB)</label>
<input type="number" name="memory" class="form-control" ms-duplex="memory"> <input type="number" name="memory" class="form-control" ms-duplex="memoryLimit">
</div> </div>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">

View File

@ -22,7 +22,7 @@
</span> </span>
</h4> </h4>
{% ifequal submission.result 0 %} {% ifequal submission.result 0 %}
<p>时间 : {{ submission.accepted_answer_info.time }}ms 语言 : <p>时间 : {{ submission.accepted_answer_time }}ms 语言 :
{{ submission.language|translate_language }} {{ submission.language|translate_language }}
</p> </p>
{% endifequal %} {% endifequal %}

View File

@ -28,12 +28,12 @@
<tbody> <tbody>
{% for item in submissions %} {% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}"> <tr class="{{ item.result|translate_result_class }}">
<th scope="row"><a href="/my_submission/{{ item|translate_id }}/">{{ forloop.counter }}</a></th> <th scope="row"><a href="/my_submission/{{ item.id }}/">{{ forloop.counter }}</a></th>
<td>{{ item.create_time }}</td> <td>{{ item.create_time }}</td>
<td>{{ item.result|translate_result }}</td> <td>{{ item.result|translate_result }}</td>
<td> <td>
{% if item.accepted_answer_info.time %} {% if item.accepted_answer_time %}
{{ item.accepted_answer_info.time }}ms {{ item.accepted_answer_time }}ms
{% else %} {% else %}
-- --
{% endif %} {% endif %}

View File

@ -17,10 +17,6 @@ def translate_result(value):
return results[value] return results[value]
def translate_id(submission_item):
return submission_item["_id"]
def translate_language(value): def translate_language(value):
return {1: "C", 2: "C++", 3: "Java"}[value] return {1: "C", 2: "C++", 3: "Java"}[value]
@ -35,6 +31,5 @@ def translate_result_class(value):
register = template.Library() register = template.Library()
register.filter("translate_result", translate_result) register.filter("translate_result", translate_result)
register.filter("translate_id", translate_id)
register.filter("translate_language", translate_language) register.filter("translate_language", translate_language)
register.filter("translate_result_class", translate_result_class) register.filter("translate_result_class", translate_result_class)