diff --git a/src/engine.cpp b/src/engine.cpp index 52e83a1..b697120 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -1,9 +1,11 @@ #include "engine.h" #include +#include #include #include #include #include "basic_defs.h" +#include "data.h" #include "utils.h" const hash_t add_user_hash = 1294763820278197867ull; // SplitMix64Hash(std::string_view("add_user")); const hash_t login_hash = 2711532776857333909ull; // SplitMix64Hash(std::string_view("login")); @@ -39,7 +41,7 @@ std::string TicketSystemEngine::Execute(const std::string &command) { // LOG->debug("clean_hash: {}", clean_hash); // LOG->debug("exit_hash: {}", exit_hash); char command_name[20]; - sscanf(command.c_str(), "%s", command_name); + sscanf(command.c_str(), "%*s %s", command_name); hash_t command_name_hash = SplitMix64Hash(std::string_view(command_name)); switch (command_name_hash) { case add_user_hash: @@ -90,20 +92,303 @@ std::string TicketSystemEngine::Execute(const std::string &command) { case exit_hash: LOG->debug("match exit"); PrepareExit(); - return std::move(Exit()); + return std::move(Exit(command)); } throw std::invalid_argument("Invalid command."); } -std::string TicketSystemEngine::AddUser(const std::string &command) { return "AddUser"; } +std::string TicketSystemEngine::AddUser(const std::string &command) { + command_id_t command_id; + sscanf(command.c_str(), "[%llu]", &command_id); + LOG->debug("command id: {}", command_id); + LOG->debug("command: {}", command); + std::stringstream command_stream(command), response_stream; + std::string token, cur_username, username, password, name, mailAddr; + uint8_t privilege; + command_stream >> token >> token; + while (command_stream >> token) { + switch (token[1]) { + case 'c': { + command_stream >> cur_username; + break; + } + case 'u': { + command_stream >> username; + break; + } + case 'p': { + command_stream >> password; + break; + } + case 'n': { + command_stream >> name; + break; + } + case 'm': { + command_stream >> mailAddr; + break; + } + case 'g': { + int tmp; + command_stream >> tmp; + privilege = tmp; + break; + } + default: + throw std::invalid_argument("arg parse fatal error in add_user"); + } + } + if (user_data.size() == 0) { + // special case, no need to check current user's privilege + FullUserData dat; + dat.privilege = 10; + strcpy(dat.username, username.c_str()); + dat.password_hash = SplitMix64Hash(password); + strcpy(dat.name, name.c_str()); + strcpy(dat.mailAddr, mailAddr.c_str()); + user_data.Put(SplitMix64Hash(username), dat); + LOG->debug("stored user_name hash: {}", SplitMix64Hash(username)); + LOG->debug("stored user_name: {}", dat.username); + LOG->debug("stored password hash: {}", dat.password_hash); + LOG->debug("stored name: {}", dat.name); + LOG->debug("stored mailAddr: {}", dat.mailAddr); + LOG->debug("stored privilege: {}", dat.privilege); + response_stream << '[' << command_id << "] 0"; + return response_stream.str(); + } + hash_t current_user_username_hash = SplitMix64Hash(cur_username); + if (online_users.find(current_user_username_hash) == online_users.end()) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + if (privilege >= online_users[current_user_username_hash]) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + hash_t new_user_username_hash = SplitMix64Hash(username); + if (user_data.HasKey(new_user_username_hash)) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + FullUserData dat; + dat.privilege = privilege; + strcpy(dat.username, username.c_str()); + dat.password_hash = SplitMix64Hash(password); + strcpy(dat.name, name.c_str()); + strcpy(dat.mailAddr, mailAddr.c_str()); + user_data.Put(new_user_username_hash, dat); + LOG->debug("stored user_name hash: {}", new_user_username_hash); + LOG->debug("stored user_name: {}", dat.username); + LOG->debug("stored password hash: {}", dat.password_hash); + LOG->debug("stored name: {}", dat.name); + LOG->debug("stored mailAddr: {}", dat.mailAddr); + LOG->debug("stored privilege: {}", dat.privilege); + response_stream << '[' << command_id << "] 0"; + return response_stream.str(); +} -std::string TicketSystemEngine::LoginUser(const std::string &command) { return "LoginUser"; } +std::string TicketSystemEngine::LoginUser(const std::string &command) { + command_id_t command_id; + sscanf(command.c_str(), "[%llu]", &command_id); + LOG->debug("command id: {}", command_id); + std::stringstream command_stream(command), response_stream; + std::string token, user_name, password; + command_stream >> token >> token; + while (command_stream >> token) { + switch (token[1]) { + case 'u': { + command_stream >> user_name; + break; + } + case 'p': { + command_stream >> password; + break; + } + default: + throw std::invalid_argument("arg parse fatal error in login"); + } + } + hash_t user_name_hash = SplitMix64Hash(user_name); + hash_t password_hash = SplitMix64Hash(password); + if (online_users.find(user_name_hash) != online_users.end()) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + FullUserData dat; + try { + user_data.Get(user_name_hash, dat); + if (dat.password_hash != password_hash) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + } catch (std::runtime_error &e) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + online_users[user_name_hash] = dat.privilege; + response_stream << '[' << command_id << "] 0"; + return response_stream.str(); +} -std::string TicketSystemEngine::LogoutUser(const std::string &command) { return "LogoutUser"; } +std::string TicketSystemEngine::LogoutUser(const std::string &command) { + command_id_t command_id; + sscanf(command.c_str(), "[%llu]", &command_id); + LOG->debug("command id: {}", command_id); + std::stringstream command_stream(command), response_stream; + std::string token, user_name; + command_stream >> token >> token; + while (command_stream >> token) { + switch (token[1]) { + case 'u': { + command_stream >> user_name; + break; + } + default: + throw std::invalid_argument("arg parse fatal error in logout"); + } + } + hash_t user_name_hash = SplitMix64Hash(user_name); + if (online_users.find(user_name_hash) == online_users.end()) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + online_users.erase(user_name_hash); + response_stream << '[' << command_id << "] 0"; + return response_stream.str(); +} -std::string TicketSystemEngine::QueryProfile(const std::string &command) { return "QueryProfile"; } +std::string TicketSystemEngine::QueryProfile(const std::string &command) { + command_id_t command_id; + sscanf(command.c_str(), "[%llu]", &command_id); + LOG->debug("command id: {}", command_id); + std::stringstream command_stream(command), response_stream; + std::string token, current_user_name, user_name; + command_stream >> token >> token; + while (command_stream >> token) { + switch (token[1]) { + case 'c': { + command_stream >> current_user_name; + break; + } + case 'u': { + command_stream >> user_name; + break; + } + default: + throw std::invalid_argument("arg parse fatal error in query_profile"); + } + } + hash_t current_user_name_hash = SplitMix64Hash(current_user_name); + hash_t user_name_hash = SplitMix64Hash(user_name); + if (online_users.find(current_user_name_hash) == online_users.end()) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + FullUserData dat; + LOG->debug("user_name_hash: {}", user_name_hash); + LOG->debug("mailAddr: {}", dat.mailAddr); + if (current_user_name_hash != user_name_hash) { + try { + user_data.Get(user_name_hash, dat); + if (online_users[current_user_name_hash] <= dat.privilege) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + } catch (std::runtime_error &e) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + } else { + user_data.Get(user_name_hash, dat); + } + LOG->debug("mailAddr: {}", dat.mailAddr); + response_stream << '[' << command_id << "] " << dat.username << ' ' << dat.name << ' ' << dat.mailAddr << ' ' + << static_cast(dat.privilege); + return response_stream.str(); +} -std::string TicketSystemEngine::ModifyProfile(const std::string &command) { return "ModifyProfile"; } +std::string TicketSystemEngine::ModifyProfile(const std::string &command) { + command_id_t command_id; + sscanf(command.c_str(), "[%llu]", &command_id); + LOG->debug("command id: {}", command_id); + std::stringstream command_stream(command), response_stream; + std::string token, current_user_name, user_name, password, name, mailAddr; + uint8_t privilege = 11; + command_stream >> token >> token; + while (command_stream >> token) { + switch (token[1]) { + case 'c': { + command_stream >> current_user_name; + break; + } + case 'u': { + command_stream >> user_name; + break; + } + case 'p': { + command_stream >> password; + break; + } + case 'n': { + command_stream >> name; + break; + } + case 'm': { + command_stream >> mailAddr; + break; + } + case 'g': { + int tmp; + command_stream >> tmp; + privilege = tmp; + break; + } + default: + throw std::invalid_argument("arg parse fatal error in add_user"); + } + } + hash_t current_user_name_hash = SplitMix64Hash(current_user_name); + hash_t user_name_hash = SplitMix64Hash(user_name); + if (online_users.find(current_user_name_hash) == online_users.end()) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + FullUserData dat; + if (current_user_name_hash != user_name_hash) { + try { + user_data.Get(user_name_hash, dat); + if (online_users[current_user_name_hash] <= dat.privilege) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + } catch (std::runtime_error &e) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + } else { + user_data.Get(user_name_hash, dat); + } + if (privilege != 11 && privilege >= online_users[current_user_name_hash]) { + response_stream << '[' << command_id << "] -1"; + return response_stream.str(); + } + if (privilege != 11) { + dat.privilege = privilege; + } + if (password != "") { + dat.password_hash = SplitMix64Hash(password); + } + if (name != "") { + strcpy(dat.name, name.c_str()); + } + if (mailAddr != "") { + strcpy(dat.mailAddr, mailAddr.c_str()); + } + user_data.Put(user_name_hash, dat); + response_stream << '[' << command_id << "] " << dat.username << ' ' << dat.name << ' ' << dat.mailAddr << ' ' + << static_cast(dat.privilege); + return response_stream.str(); +} std::string TicketSystemEngine::AddTrain(const std::string &command) { return "AddTrain"; } @@ -125,6 +410,13 @@ std::string TicketSystemEngine::QueryTicket(const std::string &command) { return std::string TicketSystemEngine::Clean() { return "Clean"; } -std::string TicketSystemEngine::Exit() { return "bye"; } +std::string TicketSystemEngine::Exit(const std::string &command) { + command_id_t command_id; + sscanf(command.c_str(), "[%llu]", &command_id); + LOG->debug("command id: {}", command_id); + std::stringstream response_stream; + response_stream << '[' << command_id << "] bye"; + return response_stream.str(); +} void TicketSystemEngine::PrepareExit() { LOG->info("Preparing exit"); } \ No newline at end of file diff --git a/src/include/basic_defs.h b/src/include/basic_defs.h index 977c360..7425bc3 100644 --- a/src/include/basic_defs.h +++ b/src/include/basic_defs.h @@ -16,5 +16,8 @@ constexpr bool global_log_enabled = false; constexpr bool global_log_enabled = true; #endif extern const bool optimize_enabled; -#define LOG if constexpr (global_log_enabled) if (logger_ptr) logger_ptr +#define LOG \ + if constexpr (global_log_enabled) \ + if (logger_ptr) logger_ptr +typedef unsigned long long command_id_t; #endif \ No newline at end of file diff --git a/src/include/data.h b/src/include/data.h index 9f55c6e..f38438f 100644 --- a/src/include/data.h +++ b/src/include/data.h @@ -1,4 +1,12 @@ #ifndef DATA_H #define DATA_H - +#include +#include "utils.h" +struct FullUserData { + char username[21]; + hash_t password_hash; + char name[21]; + char mailAddr[31]; + uint8_t privilege; +}; #endif \ No newline at end of file diff --git a/src/include/engine.h b/src/include/engine.h index d311c0b..3f1be69 100644 --- a/src/include/engine.h +++ b/src/include/engine.h @@ -7,17 +7,23 @@ #include "dataguard/snapshot.h" #endif #include +#include "data.h" +#include "storage/disk_map.hpp" #include "utils.h" class TicketSystemEngine { #ifdef ENABLE_ADVANCED_FEATURE SnapShotManager snapshot_manager; #endif std::string data_directory; - std::map online_users; + std::map online_users; + DiskMap user_data; void PrepareExit(); public: - inline TicketSystemEngine(std::string data_directory) : data_directory(data_directory) {} + inline TicketSystemEngine(std::string data_directory) + : data_directory(data_directory), + user_data("user_data.idx", data_directory + "/user_data.idx", "user_data.val", + data_directory + "/user_data.val") {} std::string Execute(const std::string &command); // 用户相关函数 @@ -42,6 +48,6 @@ class TicketSystemEngine { std::string QueryTransfer(const std::string &command); std::string QueryTicket(const std::string &command); std::string Clean(); - std::string Exit(); + std::string Exit(const std::string &command); }; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 677ceef..1c67f67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include "basic_defs.h" #include "dataguard/dataguard.h" #include "engine.h" @@ -17,7 +18,7 @@ const bool optimize_enabled = false; // const bool global_log_enabled = true; // #endif int main(int argc, char *argv[]) { - argparse::ArgumentParser program("core-cli", main_version + "-" + build_version); + argparse::ArgumentParser program("zts-core", main_version + "-" + build_version); argparse::ArgumentParser fsck_command("fsck"); fsck_command.add_description("Check and fix data"); program.add_subparser(fsck_command); @@ -29,6 +30,9 @@ int main(int argc, char *argv[]) { .default_value(std::string("127.0.0.1")) .nargs(1, 1); program.add_subparser(server_command); + argparse::ArgumentParser snapshot_command("snapshot"); + snapshot_command.add_description("Manage snapshots"); + program.add_subparser(snapshot_command); program.add_argument("-d", "--directory").help("Directory to serve").default_value(std::string(".")).nargs(1, 1); auto &group = program.add_mutually_exclusive_group(); group.add_argument("-c", "--consolelog").help("Enable console log").default_value(false).implicit_value(true); @@ -81,29 +85,37 @@ int main(int argc, char *argv[]) { LOG->info("Data directory: {}", data_directory); bool is_server = program.is_subcommand_used("server"); LOG->info("Server mode: {}", is_server); - if (is_server) { - auto port = server_command.get("--port"); - auto address = server_command.get("--address"); - LOG->info("Server port: {}", port); - LOG->info("Server address: {}", address); - LOG->info("Starting server"); - sockpp::tcp_acceptor acceptor(sockpp::inet_address(address, port)); - if (!acceptor) { - LOG->error("Error creating acceptor: {}", acceptor.last_error_str()); - return 1; - } else - LOG->info("successfully bind to address {} port {}", address, port); - throw std::runtime_error("Server mode not implemented"); - } else { - std::ios::sync_with_stdio(false); - std::cin.tie(nullptr); - std::cout.tie(nullptr); - TicketSystemEngine engine(data_directory); - std::string cmd; - while (std::getline(std::cin, cmd)) { - std::cout << engine.Execute(cmd) << '\n'; - std::cout.flush(); + try { + if (is_server) { + auto port = server_command.get("--port"); + auto address = server_command.get("--address"); + LOG->info("Server port: {}", port); + LOG->info("Server address: {}", address); + LOG->info("Starting server"); + sockpp::tcp_acceptor acceptor(sockpp::inet_address(address, port)); + if (!acceptor) { + LOG->error("Error creating acceptor: {}", acceptor.last_error_str()); + return 1; + } else + LOG->info("successfully bind to address {} port {}", address, port); + throw std::runtime_error("Server mode not implemented"); + } else { + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + TicketSystemEngine engine(data_directory); + std::string cmd; + while (std::getline(std::cin, cmd)) { + std::cout << engine.Execute(cmd) << '\n'; + std::cout.flush(); + } } + } catch (std::exception &e) { + LOG->error("Exception: {}", e.what()); + return 1; + } catch (...) { + LOG->error("Unknown exception"); + return 2; } return 0; } \ No newline at end of file diff --git a/storage/include/storage/disk_map.hpp b/storage/include/storage/disk_map.hpp index 69af901..2d070c4 100644 --- a/storage/include/storage/disk_map.hpp +++ b/storage/include/storage/disk_map.hpp @@ -53,7 +53,7 @@ class DiskMap : public DataDriverBase { res.push_back({data_file_identifier, data_file_path, data_disk_manager}); return res; } - void LockDownForCheckOut() override { + virtual void LockDownForCheckOut() override { delete indexer; delete index_bpm; delete index_disk_manager; @@ -67,6 +67,7 @@ class DiskMap : public DataDriverBase { data_bpm = nullptr; data_disk_manager = nullptr; } + bool HasKey(const Key &key) { return indexer->Get(key) != kInvalidValueIndex; } Value Get(const Key &key) { size_t data_id; if ((data_id = indexer->Get(key)) == kInvalidValueIndex) throw std::runtime_error("Key not found"); @@ -74,6 +75,12 @@ class DiskMap : public DataDriverBase { data_storage->read(res, data_id); return res; } + void Get(const Key &key, Value &res) { + size_t data_id; + if ((data_id = indexer->Get(key)) == kInvalidValueIndex) throw std::runtime_error("Key not found"); + data_storage->read(res, data_id); + } + size_t size() { return indexer->Size(); } bool Remove(const Key &key) { b_plus_tree_value_index_t data_id; bool remove_success = indexer->Remove(key, &data_id); @@ -92,7 +99,7 @@ class DiskMap : public DataDriverBase { indexer->Put(key, data_id); return true; } - void Flush() { + virtual void Flush() override { if (indexer == nullptr) return; indexer->Flush(); data_storage->Flush(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 072b113..dd20e7d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,4 +20,5 @@ set_target_properties(t1_mk PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_D add_executable(bpt_advanced_test bpt_advanced_test.cpp) target_link_libraries(bpt_advanced_test storage GTest::gtest_main spdlog::spdlog) add_executable(snapshot_test snapshot_test.cpp) -target_link_libraries(snapshot_test storage dataguard GTest::gtest_main spdlog::spdlog) \ No newline at end of file +target_link_libraries(snapshot_test storage dataguard GTest::gtest_main spdlog::spdlog) +add_executable(hash_collision_test hash_collision_test.cpp) \ No newline at end of file diff --git a/test/ctest_config b/test/ctest_config index 2606787..a347c7e 100644 --- a/test/ctest_config +++ b/test/ctest_config @@ -1,13 +1,13 @@ -add_test(NAME basic_1 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_1 --skip-check --ignore-first-dependency) -add_test(NAME basic_2 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_2 --skip-check --ignore-first-dependency) -add_test(NAME basic_3 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_3 --skip-check --ignore-first-dependency) -add_test(NAME basic_4 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_4 --skip-check --ignore-first-dependency) -add_test(NAME basic_5 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_5 --skip-check --ignore-first-dependency) -add_test(NAME basic_6 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_6 --skip-check --ignore-first-dependency) -add_test(NAME basic_extra COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_extra --skip-check --ignore-first-dependency) -add_test(NAME pressure_1_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_easy --skip-check --ignore-first-dependency) -add_test(NAME pressure_2_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_easy --skip-check --ignore-first-dependency) -add_test(NAME pressure_3_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_easy --skip-check --ignore-first-dependency) -add_test(NAME pressure_1_hard COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_hard --skip-check --ignore-first-dependency) -add_test(NAME pressure_2_hard COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_hard --skip-check --ignore-first-dependency) -add_test(NAME pressure_3_hard COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_hard --skip-check --ignore-first-dependency) \ No newline at end of file +add_test(NAME basic_1 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_1 --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_2 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_2 --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_3 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_3 --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_4 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_4 --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_5 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_5 --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_6 COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_6 --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME basic_extra COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py basic_extra --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME pressure_1_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_easy --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME pressure_2_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_easy --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME pressure_3_easy COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_easy --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME pressure_1_hard COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_1_hard --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME pressure_2_hard COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_2_hard --skip-check --ignore-first-dependency --enable-tested-program-logging) +add_test(NAME pressure_3_hard COMMAND ${PROJECT_SOURCE_DIR}/test/ojtest.py pressure_3_hard --skip-check --ignore-first-dependency --enable-tested-program-logging) \ No newline at end of file diff --git a/test/hash_collision_test.cpp b/test/hash_collision_test.cpp new file mode 100644 index 0000000..c246776 --- /dev/null +++ b/test/hash_collision_test.cpp @@ -0,0 +1,17 @@ +#include +#include +#include +#include "../src/include/utils.h" +std::unordered_map storage; +int main() { + std::string token; + while (std::cin >> token) { + hash_t hsh = SplitMix64Hash(token); + if (storage.find(hsh) == storage.end()) { + storage[hsh] = token; + } else if (storage[hsh] != token) { + std::cerr << "Collision detected: " << storage[hsh] << " " << token << std::endl; + } + } + return 0; +} \ No newline at end of file diff --git a/test/ojtest.py b/test/ojtest.py index 61dd407..4cf2efa 100755 --- a/test/ojtest.py +++ b/test/ojtest.py @@ -115,7 +115,7 @@ def RunTestGroup(name): if not enable_tested_program_logging: command = f'ulimit -t {time_limit} && ulimit -m {memory_limit} && ulimit -f {disk_limit} && ulimit -n {file_number_limit} && {path_to_exec_file} < {input_file} > {output_file} 2> {stderr_file}' else: - command = f'ulimit -t {time_limit} && ulimit -m {memory_limit} && ulimit -f {disk_limit} && ulimit -n {file_number_limit} && {path_to_exec_file} -l {log_file} < {input_file} > {output_file} 2> {stderr_file}' + command = f'ulimit -t {time_limit} && ulimit -m {memory_limit} && ulimit -f {disk_limit} && ulimit -n {file_number_limit} && {path_to_exec_file} -l {log_file} --level debug < {input_file} > {output_file} 2> {stderr_file}' print("the test command is: ", command) process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=playground_dir) # Check the exit status of the command