summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server/prolog_session.py7
-rw-r--r--server/user_session.py34
2 files changed, 39 insertions, 2 deletions
diff --git a/server/prolog_session.py b/server/prolog_session.py
index c21d929..039f40a 100644
--- a/server/prolog_session.py
+++ b/server/prolog_session.py
@@ -37,9 +37,11 @@ class PrologSession(object):
No properties are accessible; use getters and setters instead.
Values are passed by value instead of by reference (deep copy!).
"""
- def __init__(self):
+ def __init__(self, user_session):
+ self._user_session = user_session # the owning session
self._access_lock = threading.Lock()
self._engine_id = None
+ self._problem_id = -1
def run(self, code):
with self._access_lock:
@@ -78,6 +80,7 @@ class PrologSession(object):
if self._engine_id is not None:
prolog.engine.stop(self._engine_id)
self._engine_id = None
+ self._problem_id = -1
return [], 'ok', False
def __del__(self):
@@ -116,4 +119,6 @@ class PrologSession(object):
if status == 'ok':
more_messages, status, have_more = self.query(query)
messages.extend(more_messages)
+ self._problem_id = problem_id
+ self._user_session.update_solution(problem_id, [], program)
return messages, status, have_more
diff --git a/server/user_session.py b/server/user_session.py
index bb4179d..d8cdf1d 100644
--- a/server/user_session.py
+++ b/server/user_session.py
@@ -9,6 +9,7 @@ from . import prolog_session
from . import problems
import db
from errors.session import NoSuchSession, AuthenticationFailed
+import psycopg2.extras
__all__ = ['get_session_by_id', 'get_or_create_session', 'UserSession']
@@ -49,7 +50,7 @@ class UserSession(object):
def get_prolog(self):
with self._access_lock:
if self.prolog_session is None:
- self.prolog_session = prolog_session.PrologSession() # lazy init
+ self.prolog_session = prolog_session.PrologSession(self) # lazy init
return self.prolog_session
def get_problem_data(self, language, problem_group, problem):
@@ -79,6 +80,37 @@ class UserSession(object):
conn.commit()
db.return_connection(conn)
+ def update_solution(self, problem_id, trace, solution):
+ if (trace is None) and (solution is None):
+ return
+ conn = db.get_connection()
+ try:
+ cur = conn.cursor()
+ try:
+ # TODO: convert to upsert with postgresql 9.5 to eliminate the small window where it's possible for more than one concurrent insert to execute
+ cur.execute('select id, trace, solution content from solution where codeq_user_id = %s and problem_id = %s for update', (self.uid, problem_id))
+ row = cur.fetchone()
+ if row:
+ if row[1]:
+ new_trace = row[1]
+ if trace:
+ new_trace.extend(trace)
+ else:
+ new_trace = trace
+ new_solution = row[2] if solution is None else solution
+ cur.execute('update solution set content = %s, trace = %s where id = %s', (new_solution, psycopg2.extras.Json(new_trace), row[0]))
+ else:
+ # this is the first entry
+ cur.execute('insert into solution (done, content, problem_id, codeq_user_id, trace) values (%s, %s, %s, %s, %s)', (False, solution, problem_id, self.uid, psycopg2.extras.Json(trace)))
+ finally:
+ cur.close()
+ conn.commit()
+ except:
+ conn.rollback()
+ raise
+ finally:
+ db.return_connection(conn)
+
def __del__(self):
# no locking needed if GC is removing us, as there cannot be any concurrent access by definition
if hasattr(self, 'prolog_session') and (self.prolog_session is not None):