-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
44 changed files
with
325 additions
and
488 deletions.
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
subprojects/sim/include/sim/change_problem_statement_jobs/change_problem_statement_job.hh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
#pragma once | ||
|
||
#include <sim/internal_files/internal_file.hh> | ||
#include <sim/jobs/job.hh> | ||
#include <sim/sql/fields/varbinary.hh> | ||
|
||
namespace sim::change_problem_statement_jobs { | ||
|
||
struct ChangeProblemStatementJob { | ||
decltype(jobs::Job::id) id; | ||
decltype(internal_files::InternalFile::id) new_statement_file_id; | ||
sql::fields::Varbinary<256> path_for_new_statement; | ||
}; | ||
|
||
} // namespace sim::change_problem_statement_jobs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 87 additions & 64 deletions
151
subprojects/sim/src/job_server/job_handlers/change_problem_statement.cc
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,135 @@ | ||
#include "change_problem_statement.hh" | ||
|
||
#include <simlib/file_manip.hh> | ||
#include <sim/change_problem_statement_jobs/change_problem_statement_job.hh> | ||
#include <sim/internal_files/internal_file.hh> | ||
#include <sim/problems/problem.hh> | ||
#include <sim/sql/sql.hh> | ||
#include <simlib/concat_tostr.hh> | ||
#include <simlib/file_remover.hh> | ||
#include <simlib/libzip.hh> | ||
#include <simlib/macros/wont_throw.hh> | ||
#include <simlib/path.hh> | ||
#include <simlib/sim/problem_package.hh> | ||
#include <simlib/sim/simfile.hh> | ||
#include <simlib/time.hh> | ||
#include <zip.h> | ||
|
||
using sim::jobs::OldJob; | ||
using sim::change_problem_statement_jobs::ChangeProblemStatementJob; | ||
using sim::jobs::Job; | ||
using sim::problems::Problem; | ||
using sim::sql::InsertInto; | ||
using sim::sql::Select; | ||
using sim::sql::Update; | ||
|
||
namespace job_server::job_handlers { | ||
|
||
void ChangeProblemStatement::run(sim::mysql::Connection& mysql) { | ||
STACK_UNWINDING_MARK; | ||
|
||
auto transaction = mysql.start_repeatable_read_transaction(); | ||
auto old_mysql = old_mysql::ConnectionView{mysql}; | ||
decltype(Job::aux_id)::value_type problem_id; | ||
decltype(ChangeProblemStatementJob::new_statement_file_id) new_statement_file_id; | ||
decltype(ChangeProblemStatementJob::path_for_new_statement) path_for_new_statement; | ||
{ | ||
auto stmt = | ||
mysql.execute(Select("j.aux_id, cpsj.new_statement_file_id, cpsj.path_for_new_statement" | ||
) | ||
.from("jobs j") | ||
.inner_join("change_problem_statement_jobs cpsj") | ||
.on("cpsj.id=j.id") | ||
.where("j.id=?", job_id_)); | ||
stmt.res_bind(problem_id, new_statement_file_id, path_for_new_statement); | ||
throw_assert(stmt.next()); | ||
} | ||
|
||
uint64_t problem_file_id = 0; | ||
std::string problem_package_path; | ||
sim::Simfile simfile; | ||
{ | ||
auto stmt = old_mysql.prepare("SELECT file_id, simfile FROM problems" | ||
" WHERE id=?"); | ||
stmt.bind_and_execute(problem_id_); | ||
InplaceBuff<0> simfile_str; | ||
stmt.res_bind_all(problem_file_id, simfile_str); | ||
if (not stmt.next()) { | ||
return set_failure("Problem with ID = ", problem_id_, " does not exist"); | ||
decltype(Problem::file_id) problem_file_id; | ||
decltype(Problem::simfile) simfile_as_str; | ||
auto stmt = | ||
mysql.execute(Select("file_id, simfile").from("problems").where("id=?", problem_id)); | ||
stmt.res_bind(problem_file_id, simfile_as_str); | ||
if (!stmt.next()) { | ||
return set_failure("Problem with ID = ", problem_id, " does not exist"); | ||
} | ||
|
||
simfile = sim::Simfile(simfile_str.to_string()); | ||
problem_package_path = sim::internal_files::path_of(problem_file_id); | ||
simfile = sim::Simfile{simfile_as_str}; | ||
simfile.load_all(); | ||
} | ||
|
||
auto pkg_path = sim::internal_files::old_path_of(problem_file_id); | ||
|
||
old_mysql.prepare("INSERT INTO internal_files (created_at) VALUES(?)") | ||
.bind_and_execute(utc_mysql_datetime()); | ||
uint64_t new_file_id = old_mysql.insert_id(); | ||
auto new_pkg_path = sim::internal_files::old_path_of(new_file_id); | ||
auto new_problem_file_id = sim::internal_files::new_internal_file_id(mysql); | ||
auto new_problem_package_path = sim::internal_files::path_of(new_problem_file_id); | ||
|
||
// Replace old statement with new statement | ||
|
||
// Escape info.new_statement_path | ||
if (info_.new_statement_path.empty()) { | ||
info_.new_statement_path = WONT_THROW(simfile.statement.value()); | ||
// Escape path_for_new_statement | ||
if (path_for_new_statement.empty()) { | ||
path_for_new_statement = WONT_THROW(simfile.statement.value()); | ||
} else { | ||
info_.new_statement_path = path_absolute(info_.new_statement_path).erase(0, 1); | ||
path_for_new_statement = path_absolute(path_for_new_statement).erase(0, 1); | ||
} | ||
|
||
ZipFile src_zip(pkg_path, ZIP_RDONLY); | ||
// Replace old statement with the new statement | ||
auto src_zip = ZipFile{problem_package_path, ZIP_RDONLY}; | ||
auto main_dir = sim::zip_package_main_dir(src_zip); | ||
auto old_statement_path = concat(main_dir, WONT_THROW(simfile.statement.value())); | ||
auto new_statement_path = concat(main_dir, info_.new_statement_path); | ||
auto simfile_path = concat(main_dir, "Simfile"); | ||
|
||
auto old_statement_path = concat_tostr(main_dir, WONT_THROW(simfile.statement.value())); | ||
auto new_statement_path = concat_tostr(main_dir, path_for_new_statement); | ||
auto simfile_path = concat_tostr(main_dir, "Simfile"); | ||
if (new_statement_path == simfile_path) { | ||
return set_failure("Invalid new statement path - it would overwrite Simfile"); | ||
} | ||
simfile.statement = path_for_new_statement; | ||
|
||
simfile.statement = info_.new_statement_path; | ||
auto simfile_str = simfile.dump(); | ||
|
||
FileRemover new_pkg_remover(new_pkg_path.to_string()); | ||
ZipFile dest_zip(new_pkg_path, ZIP_CREATE | ZIP_TRUNCATE); | ||
|
||
// Copy old package contests and update the Simfile | ||
auto simfile_as_str = simfile.dump(); | ||
auto new_problem_package_remover = FileRemover{new_problem_package_path}; | ||
auto dest_zip = ZipFile{new_problem_package_path, ZIP_CREATE | ZIP_TRUNCATE}; | ||
auto eno = src_zip.entries_no(); | ||
for (decltype(eno) i = 0; i < eno; ++i) { | ||
auto entry_name = src_zip.get_name(i); | ||
if (entry_name == simfile_path) { | ||
dest_zip.file_add(simfile_path, dest_zip.source_buffer(simfile_str)); | ||
} else if (entry_name != old_statement_path) { | ||
dest_zip.file_add(simfile_path, dest_zip.source_buffer(simfile_as_str)); | ||
} else if (entry_name != old_statement_path && entry_name != new_statement_path) { | ||
dest_zip.file_add(entry_name, dest_zip.source_zip(src_zip, i)); | ||
} | ||
} | ||
|
||
// Add new statement file entry | ||
dest_zip.file_add( | ||
new_statement_path, dest_zip.source_file(sim::internal_files::old_path_of(job_file_id_)) | ||
new_statement_path, | ||
dest_zip.source_file(sim::internal_files::path_of(new_statement_file_id)) | ||
); | ||
// Save all data and close the new problem package | ||
dest_zip.close(); | ||
|
||
// Add job to delete the old problem file | ||
const auto current_datetime = utc_mysql_datetime(); | ||
mysql.execute( | ||
InsertInto("jobs (file_id, creator, type, priority, status, created_at, aux_id, data)") | ||
.select( | ||
"file_id, NULL, ?, ?, ?, ?, NULL, ''", | ||
Job::Type::DELETE_FILE, | ||
default_priority(Job::Type::DELETE_FILE), | ||
Job::Status::PENDING, | ||
current_datetime | ||
) | ||
.from("problems") | ||
.where("id=?", problem_id) | ||
); | ||
|
||
dest_zip.close(); // Write all data to the dest_zip | ||
|
||
const auto current_date = utc_mysql_datetime(); | ||
// Add job to delete old problem file | ||
old_mysql | ||
.prepare("INSERT INTO jobs(file_id, creator, type, priority, status," | ||
" created_at, aux_id, info, data)" | ||
" SELECT file_id, NULL, ?, ?, ?, ?, NULL, '', '' FROM problems" | ||
" WHERE id=?") | ||
.bind_and_execute( | ||
EnumVal(OldJob::Type::DELETE_FILE), | ||
default_priority(OldJob::Type::DELETE_FILE), | ||
EnumVal(OldJob::Status::PENDING), | ||
current_date, | ||
problem_id_ | ||
); | ||
|
||
// Use new package as problem file | ||
old_mysql | ||
.prepare("UPDATE problems SET file_id=?, simfile=?, updated_at=?" | ||
" WHERE id=?") | ||
.bind_and_execute(new_file_id, simfile_str, current_date, problem_id_); | ||
|
||
job_done(mysql, from_unsafe{info_.dump()}); | ||
|
||
// Update the problem with new file and simfile | ||
mysql.execute(Update("problems") | ||
.set( | ||
"file_id=?, simfile=?, updated_at=?", | ||
new_problem_file_id, | ||
simfile_as_str, | ||
current_datetime | ||
) | ||
.where("id=?", problem_id)); | ||
|
||
job_done(mysql); | ||
transaction.commit(); | ||
new_pkg_remover.cancel(); | ||
new_problem_package_remover.cancel(); | ||
} | ||
|
||
} // namespace job_server::job_handlers |
Oops, something went wrong.