Accept Merge Request #91 : (virusdefender-dev -> dev)

Merge Request: 修改判题数据库
Created By: @virusdefender
Accepted By: @virusdefender
URL: https://coding.net/u/virusdefender/p/qduoj/git/merge/91
This commit is contained in:
virusdefender 2015-08-17 13:02:13 +08:00
commit a9f4b370cc
17 changed files with 217 additions and 108 deletions

View File

@ -1,9 +1,7 @@
# coding=utf-8
import sys
import os
import pymongo
from bson.objectid import ObjectId
import json
import MySQLdb
from client import JudgeClient
from language import languages
@ -11,9 +9,7 @@ from compiler import compile_
from result import result
from settings import judger_workspace
sys.path.append(os.path.abspath(os.path.dirname(__file__) + '/' + '..'))
from judger_controller.settings import celery_mongodb_config, docker_mongodb_config
from settings import submission_db
# 简单的解析命令行参数
@ -25,19 +21,31 @@ time_limit = args[4]
memory_limit = args[6]
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)})
if not submission:
def db_conn():
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()
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"]
f = open(src_path, "w")
f.write(submission["code"].encode("utf8"))
f.write(code.encode("utf8"))
f.close()
# 编译
@ -45,23 +53,23 @@ try:
exe_path = compile_(language, src_path, judger_workspace + "run/")
except Exception as e:
print e
connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"]
data = {"result": result["compile_error"], "info": str(e)}
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data})
connection.close()
conn = db_conn()
cur = conn.cursor()
cur.execute("update submission set result=%s, info=%s where id=%s",
(result["compile_error"], str(e), submission_id))
conn.commit()
exit()
print "Compile successfully"
# 运行
try:
client = JudgeClient(language_code=submission["language"],
client = JudgeClient(language_code=language_code,
exe_path=exe_path,
max_cpu_time=int(time_limit),
max_real_time=int(time_limit) * 2,
max_memory=int(memory_limit),
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"]:
if item["result"]:
@ -69,15 +77,23 @@ try:
break
else:
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:
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 judge_result
connection = pymongo.MongoClient(host=docker_mongodb_config["host"], port=docker_mongodb_config["port"])
collection = connection["oj"]["oj_submission"]
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": judge_result})
connection.close()
conn = db_conn()
cur = conn.cursor()
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/"
# 这个是在docker 中访问数据库 ip 不一定和web服务器还有celery的一样
submission_db = {
"host": "192.168.42.1",
"port": 3306,
"db": "oj_submission",
"user": "root",
"password": "mypwd"
}

View File

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

View File

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

View File

@ -1,11 +1,10 @@
# coding=utf-8
# from __future__ import absolute_import
import MySQLdb
import subprocess
import pymongo
from bson import ObjectId
from ..judger.result import result
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
@ -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)
subprocess.call(command, shell=docker_config["shell"])
except Exception as e:
connection = pymongo.MongoClient(host=celery_mongodb_config["host"], port=celery_mongodb_config["port"])
collection = connection["oj"]["oj_submission"]
data = {"result": result["system_error"], "info": str(e)}
collection.find_one_and_update({"_id": ObjectId(submission_id)}, {"$set": data})
connection.close()
print e
conn = MySQLdb.connect(db=submission_db["db"],
user=submission_db["user"],
passwd=submission_db["password"],
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,27 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 下面是需要自己修改的
LOG_PATH = "LOG/"
# 注意这是web 服务器访问的地址,判题度武器访问的地址不一定一样,因为可能不在一台机器上
# 注意这是web 服务器访问的地址,判题访问的地址不一定一样,因为可能不在一台机器上
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'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
# 同理 这是 web 服务器的上传路径
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)
# 最后更新时间
last_update_time = models.DateTimeField(auto_now=True)
# last_update_time = models.DateTimeField(auto_now=True)
# 这个题是谁创建的
created_by = models.ForeignKey(User)
# 来源

View File

@ -46,7 +46,7 @@ require(["jquery", "codeMirror", "csrfToken", "bsAlert"], function ($, codeMirro
results[data.result].message +
'!   ';
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>');

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
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
import datetime
import pymongo
from bson.objectid import ObjectId
import json
from django.shortcuts import render
from rest_framework.views import APIView
from django.conf import settings
from judge.judger.result import result
from judge.judger_controller.tasks import judge
from account.decorators import login_required
from problem.models import Problem
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page
from .models import Submission
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):
@login_required
def post(self, request):
@ -34,23 +25,19 @@ class SubmissionAPIView(APIView):
serializer = CreateSubmissionSerializer(data=request.data)
if serializer.is_valid():
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:
problem = Problem.objects.get(id=data["problem_id"])
except Problem.DoesNotExist:
return error_response(u"题目不存在")
collection = _create_mongodb_connection()
submission_id = str(collection.insert_one(data).inserted_id)
submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
code=data["code"], problem_id=problem.id)
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:
return error_response(u"提交判题任务失败")
return success_response({"submission_id": submission_id})
return success_response({"submission_id": submission.id})
else:
return serializer_invalid_response(serializer)
@ -59,41 +46,36 @@ class SubmissionAPIView(APIView):
submission_id = request.GET.get("submission_id", None)
if not submission_id:
return error_response(u"参数错误")
submission = _create_mongodb_connection().find_one({"_id": ObjectId(submission_id), "user_id": request.user.id})
if submission:
response_data = {"result": submission["result"]}
if submission["result"] == 0:
response_data["accepted_answer_info"] = submission["accepted_answer_info"]
return success_response(response_data)
else:
try:
submission = Submission.objects.get(id=submission_id, user_id=request.user.id)
except Submission.DoesNotExist:
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
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:
problem = Problem.objects.get(id=problem_id, visible=True)
except Problem.DoesNotExist:
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",
{"submissions": submissions, "problem": problem})
@login_required
def my_submission(request, submission_id):
collection = _create_mongodb_connection()
submission = collection.find_one({"user_id": request.user.id, "_id": ObjectId(submission_id)},
projection=["result", "accepted_answer_info", "create_time",
"language", "code", "problem_id", "info"])
if not submission:
try:
submission = Submission.objects.get(id=submission_id)
except Submission.DoesNotExist:
return error_page(request, u"提交不存在")
try:
problem = Problem.objects.get(id=submission["problem_id"], visible=True)
problem = Problem.objects.get(id=submission.problem_id, visible=True)
except Problem.DoesNotExist:
return error_page(request, u"提交不存在")
return render(request, "oj/problem/my_submission.html", {"submission": submission, "problem": problem})
return render(request, "oj/problem/my_submission.html",
{"submission": submission, "problem": problem})

View File

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

View File

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

View File

@ -28,12 +28,12 @@
<tbody>
{% for item in submissions %}
<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.result|translate_result }}</td>
<td>
{% if item.accepted_answer_info.time %}
{{ item.accepted_answer_info.time }}ms
{% if item.accepted_answer_time %}
{{ item.accepted_answer_time }}ms
{% else %}
--
{% endif %}

View File

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