class User(db.Model, UserMixin): '''Model for the users table.''' __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) school_id = db.Column(db.String(128), nullable=False, unique=True) name = db.Column(db.String(128), nullable=False) password = db.Column(db.String(128), nullable=False) is_teacher = db.Column(db.Boolean, nullable=False) teacher_id = db.Column(db.Integer, db.ForeignKey('teachers.id'), nullable=True) teacher = db.relationship(Teacher, backref='users') def __repr__(self): return '<User {}>'.format(self.name) def authenticate(self, password): '''Checks if provided password matches stored password.''' return check_password_hash(self.password, password) @staticmethod @login_manager.user_loader def load_user(user_id): return User.query.get(user_id)
class RuntimeParam(db.Model): id = db.Column(db.Integer, primary_key=True) env_id = db.Column(db.Integer, db.ForeignKey("runtime_env.id"), nullable=False) env = db.relationship("RuntimeEnv", back_populates="params", uselist=False) key = db.Column(db.String(100)) value = db.Column(db.Text)
class Teacher(db.Model): '''Model for the teachers table.''' __tablename__ = 'teachers' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), nullable=False) def __repr__(self): return '<Teacher {}>'.format(self.name)
class Class(db.Model): '''Model for the classes table.''' __tablename__ = 'classes' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(128), nullable=False) teacher_id = db.Column(db.Integer, db.ForeignKey('teachers.id'), nullable=True) teacher = db.relationship(Teacher, backref='classes') def __repr__(self): return '<Class {}>'.format(self.name)
class BenchmarkSuite(db.Model): id = db.Column(db.Integer, primary_key=True) created = db.Column(db.DateTime, default=datetime.utcnow) author = db.Column(db.String(50)) env = db.relationship("RuntimeEnv", back_populates="suite", uselist=False) tasks = db.relationship("BenchmarkTask", back_populates="suite", lazy=False, order_by="asc(BenchmarkTask.id)") description = db.Column(db.Text) def completedTaskCount(self): return sum(x.state in [TaskState.evaluated, TaskState.cancelled] for x in self.tasks) def assignedTaskCount(self): return sum(x.state == TaskState.assigned for x in self.tasks)
class BenchmarkTask(db.Model): id = db.Column(db.Integer, primary_key=True) suite_id = db.Column(db.Integer, db.ForeignKey("benchmark_suite.id"), nullable=False) suite = db.relationship("BenchmarkSuite", back_populates="tasks", uselist=False) command = db.Column(db.Text) state = db.Column(db.Enum(TaskState), default=TaskState.created) assignedAt = db.Column(db.DateTime, default=None) updatedAt = db.Column(db.DateTime, default=None) assignee = db.Column(db.String(100), default=None) # Exit code of the benchmarking command exitcode = db.Column(db.Integer, default=None) # Combination of stdout & stderr from the build phase buildOutput = db.deferred(db.Column(db.Text, default=None)) # Combination of stdout & stderr output = db.deferred(db.Column(db.Text, default=None)) # Statistics collected by the runner stats = db.Column(db.JSON, default=None) # The JSON object produced by the evaluation task result = db.Column(db.JSON, default=None) @staticmethod def fetchNew(availableCores, availableMemory): """ Fetch and reserve an unfinished task that fits inside the given limits. """ # TBA extend the query by tasks that are assigned, but haven't been # updated in a long time baseQuery = (BenchmarkTask.query.join(BenchmarkTask.suite).join( BenchmarkSuite.env).filter( RuntimeEnv.cpuLimit <= availableCores, RuntimeEnv.memoryLimit <= availableMemory)) task = (baseQuery.filter( BenchmarkTask.state == TaskState.pending).order_by( BenchmarkTask.id).limit(1).first()) if task: return task # Fetch tasks that are assigned, but haven't been updated for more than # 5 minutes t = datetime.utcnow() - timedelta(minutes=5) task = (baseQuery.filter( BenchmarkTask.state == TaskState.assigned).filter( BenchmarkTask.updatedAt <= t).order_by( BenchmarkTask.id).limit(1).first()) return task def acquire(self, assignee): """ Acquire the task to the assignee """ self.state = TaskState.assigned self.assignee = assignee t = datetime.utcnow() self.assignedAt = t self.updatedAt = t def abandon(self): """ Abandon the task without successfully evaluating it. """ self.state = TaskState.pending self.assignedAt = None self.updatedAt = None self.assignee = None def buildPoke(self, output): """ Poke the task - notify the database that the task's runtime environment is still being build, update its output. """ self.updatedAt = datetime.utcnow() self.buildOutput = output def poke(self, output): """ Poke the task - notify the database that the task is still being evaluated, update its output. """ self.updatedAt = datetime.utcnow() self.output = output def finish(self, exitcode, output, stats, result): """ Sucessfully finish evaluation of the task """ self.state = TaskState.evaluated self.exitcode = exitcode self.output = output self.stats = stats self.result = result