diff --git a/judge/judger/run.py b/judge/judger/run.py index f13673ee..6ecc2d3f 100644 --- a/judge/judger/run.py +++ b/judge/judger/run.py @@ -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() diff --git a/judge/judger/settings.py b/judge/judger/settings.py index 6670e362..1f15b96b 100644 --- a/judge/judger/settings.py +++ b/judge/judger/settings.py @@ -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" +} diff --git a/judge/judger_controller/celery.py b/judge/judger_controller/celery.py index 5b90bdb9..18cf8867 100644 --- a/judge/judger_controller/celery.py +++ b/judge/judger_controller/celery.py @@ -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']) \ No newline at end of file + include=["judge.judger_controller.tasks"]) \ No newline at end of file diff --git a/judge/judger_controller/settings.py b/judge/judger_controller/settings.py index 2c69d805..a0d3e661 100644 --- a/judge/judger_controller/settings.py +++ b/judge/judger_controller/settings.py @@ -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" } \ No newline at end of file diff --git a/judge/judger_controller/tasks.py b/judge/judger_controller/tasks.py index f9187244..e8066892 100644 --- a/judge/judger_controller/tasks.py +++ b/judge/judger_controller/tasks.py @@ -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() diff --git a/oj/db_router.py b/oj/db_router.py new file mode 100644 index 00000000..bd174cdf --- /dev/null +++ b/oj/db_router.py @@ -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 \ No newline at end of file diff --git a/oj/local_settings.py b/oj/local_settings.py index 3c87b06c..da1a6727 100644 --- a/oj/local_settings.py +++ b/oj/local_settings.py @@ -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'] + diff --git a/problem/migrations/0007_remove_problem_last_update_time.py b/problem/migrations/0007_remove_problem_last_update_time.py new file mode 100644 index 00000000..eac32527 --- /dev/null +++ b/problem/migrations/0007_remove_problem_last_update_time.py @@ -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', + ), + ] diff --git a/problem/models.py b/problem/models.py index 25c85d36..d6ac77bb 100644 --- a/problem/models.py +++ b/problem/models.py @@ -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) # 来源 diff --git a/static/src/js/app/oj/problem/problem.js b/static/src/js/app/oj/problem/problem.js index 5b23c751..cb3127ae 100644 --- a/static/src/js/app/oj/problem/problem.js +++ b/static/src/js/app/oj/problem/problem.js @@ -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 += ('查看详情 '); diff --git a/submission/migrations/0001_initial.py b/submission/migrations/0001_initial.py new file mode 100644 index 00000000..10e8ff8f --- /dev/null +++ b/submission/migrations/0001_initial.py @@ -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', + }, + ), + ] diff --git a/submission/models.py b/submission/models.py index 9bad5790..a2fcfde8 100644 --- a/submission/models.py +++ b/submission/models.py @@ -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" diff --git a/submission/views.py b/submission/views.py index 26dd1c25..2ebc843e 100644 --- a/submission/views.py +++ b/submission/views.py @@ -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}) \ No newline at end of file + return render(request, "oj/problem/my_submission.html", + {"submission": submission, "problem": problem}) \ No newline at end of file diff --git a/template/admin/problem/add_problem.html b/template/admin/problem/add_problem.html index 63132ca1..04f8994b 100644 --- a/template/admin/problem/add_problem.html +++ b/template/admin/problem/add_problem.html @@ -15,11 +15,15 @@
+ +
+ +
diff --git a/template/oj/problem/my_submission.html b/template/oj/problem/my_submission.html index 81fbc506..524642f9 100644 --- a/template/oj/problem/my_submission.html +++ b/template/oj/problem/my_submission.html @@ -22,7 +22,7 @@ {% ifequal submission.result 0 %} -

时间 : {{ submission.accepted_answer_info.time }}ms 语言 : +

时间 : {{ submission.accepted_answer_time }}ms 语言 : {{ submission.language|translate_language }}

{% endifequal %} diff --git a/template/oj/problem/my_submissions_list.html b/template/oj/problem/my_submissions_list.html index b1c63884..8a9a235f 100644 --- a/template/oj/problem/my_submissions_list.html +++ b/template/oj/problem/my_submissions_list.html @@ -28,12 +28,12 @@ {% for item in submissions %} - {{ forloop.counter }} + {{ forloop.counter }} {{ item.create_time }} {{ item.result|translate_result }} - {% if item.accepted_answer_info.time %} - {{ item.accepted_answer_info.time }}ms + {% if item.accepted_answer_time %} + {{ item.accepted_answer_time }}ms {% else %} -- {% endif %} diff --git a/utils/templatetags/submission.py b/utils/templatetags/submission.py index 12bf2674..a80c25e6 100644 --- a/utils/templatetags/submission.py +++ b/utils/templatetags/submission.py @@ -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) \ No newline at end of file