diff --git a/src/limestone/datastore.cpp b/src/limestone/datastore.cpp index 244edcc7..51121060 100644 --- a/src/limestone/datastore.cpp +++ b/src/limestone/datastore.cpp @@ -24,6 +24,7 @@ #include #include #include "logging_helper.h" +#include "limestone_exception_helper.h" #include #include "internal.h" @@ -47,8 +48,7 @@ datastore::datastore(configuration const& conf) : location_(conf.data_locations_ if (!result_check || error) { const bool result_mkdir = boost::filesystem::create_directory(location_, error); if (!result_mkdir || error) { - LOG_LP(ERROR) << "fail to create directory: result_mkdir: " << result_mkdir << ", error_code: " << error << ", path: " << location_; - throw std::runtime_error("fail to create the log_location directory"); + LOG_AND_THROW_IO_EXCEPTION("fail to create directory: result_mkdir: " + location_.string(), error); } internal::setup_initial_logdir(location_); add_file(manifest_path); @@ -77,12 +77,10 @@ datastore::datastore(configuration const& conf) : location_(conf.data_locations_ if (!result || error) { FILE* strm = fopen(epoch_file_path_.c_str(), "a"); // NOLINT(*-owning-memory) if (!strm) { - LOG_LP(ERROR) << "does not have write permission for the log_location directory, path: " << location_; - throw std::runtime_error("does not have write permission for the log_location directory"); + LOG_AND_THROW_IO_EXCEPTION("does not have write permission for the log_location directory, path: " + location_.string(), errno); } if (fclose(strm) != 0) { // NOLINT(*-owning-memory) - LOG_LP(ERROR) << "fclose failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fclose failed", errno); } add_file(epoch_file_path_); } @@ -114,13 +112,11 @@ void datastore::ready() { boost::filesystem::directory_iterator it(location_, error); boost::filesystem::directory_iterator end; if (error) { - LOG_LP(ERROR) << "Failed to initialize directory iterator: error_code: " << error.message() << ", path: " << location_; - throw std::runtime_error("Failed to initialize directory iterator"); + LOG_AND_THROW_IO_EXCEPTION("Failed to initialize directory iterator, path: " + location_.string(), error); } for (; it != end; it.increment(error)) { if (error) { - LOG_LP(ERROR) << "Failed to access directory entry: error_code: " << error.message() << ", path: " << location_; - throw std::runtime_error("Failed to iterate over the directory entries"); + LOG_AND_THROW_IO_EXCEPTION("Failed to access directory entry: , path: " + location_.string(), error); } if (boost::filesystem::is_regular_file(it->path())) { std::string filename = it->path().filename().string(); @@ -200,21 +196,17 @@ void datastore::update_min_epoch_id(bool from_switch_epoch) { // NOLINT(readabi FILE* strm = fopen(epoch_file_path_.c_str(), "a"); // NOLINT(*-owning-memory) if (!strm) { - LOG_LP(ERROR) << "fopen failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fopen failed", errno); } log_entry::durable_epoch(strm, static_cast(epoch_id_recorded_.load())); if (fflush(strm) != 0) { - LOG_LP(ERROR) << "fflush failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fflush failed", errno); } if (fsync(fileno(strm)) != 0) { - LOG_LP(ERROR) << "fsync failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fsync failed", errno); } if (fclose(strm) != 0) { // NOLINT(*-owning-memory) - LOG_LP(ERROR) << "fclose failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fclose failed", errno); } break; } @@ -400,8 +392,7 @@ void datastore::rotate_epoch_file() { boost::filesystem::ofstream strm{}; strm.open(epoch_file_path_, std::ios_base::out | std::ios_base::app | std::ios_base::binary); if(!strm || !strm.is_open() || strm.bad() || strm.fail()){ - LOG_LP(ERROR) << "does not have write permission for the log_location directory, path: " << location_; - throw std::runtime_error("does not have write permission for the log_location directory"); + THROW_LIMESTONE_IO_EXCEPTION("does not have write permission for the log_location directory, path: " + location_.string(), errno); } strm.close(); } diff --git a/src/limestone/datastore_format.cpp b/src/limestone/datastore_format.cpp index 7b6e36fd..f1d03944 100644 --- a/src/limestone/datastore_format.cpp +++ b/src/limestone/datastore_format.cpp @@ -23,6 +23,7 @@ #include +#include "limestone_exception_helper.h" #include "compaction_catalog.h" #include "internal.h" #include "log_entry.h" @@ -43,31 +44,26 @@ void setup_initial_logdir(const boost::filesystem::path& logdir) { boost::filesystem::path config = logdir / std::string(manifest_file_name); FILE* strm = fopen(config.c_str(), "w"); // NOLINT(*-owning-memory) if (!strm) { - std::string err_msg = "Failed to open file for writing: " + config.string() + ". errno = " + std::to_string(errno); - LOG_LP(ERROR) << err_msg; - throw std::runtime_error(err_msg); + std::string err_msg = "Failed to open file for writing: " + config.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, errno); } std::string manifest_str = manifest_v2.dump(4); auto ret = fwrite(manifest_str.c_str(), manifest_str.length(), 1, strm); if (ret != 1) { - std::string err_msg = "Failed to write to file: " + config.string() + ". errno = " + std::to_string(errno); - LOG_LP(ERROR) << err_msg; - throw std::runtime_error(err_msg); + std::string err_msg = "Failed to write to file: " + config.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, errno); } if (fflush(strm) != 0) { - std::string err_msg = "Failed to flush file buffer: " + config.string() + ". errno = " + std::to_string(errno); - LOG_LP(ERROR) << err_msg; - throw std::runtime_error(err_msg); + std::string err_msg = "Failed to flush file buffer: " + config.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, errno); } if (fsync(fileno(strm)) != 0) { - std::string err_msg = "Failed to sync file to disk: " + config.string() + ". errno = " + std::to_string(errno); - LOG_LP(ERROR) << err_msg; - throw std::runtime_error(err_msg); + std::string err_msg = "Failed to sync file to disk: " + config.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, errno); } if (fclose(strm) != 0) { // NOLINT(*-owning-memory) - std::string err_msg = "Failed to close file: " + config.string() + ". errno = " + std::to_string(errno); - LOG_LP(ERROR) << err_msg; - throw std::runtime_error(err_msg); + std::string err_msg = "Failed to close file: " + config.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, errno); } // Create compaction catalog file compaction_catalog catalog(logdir); @@ -105,48 +101,56 @@ int is_supported_version(const boost::filesystem::path& manifest_path, std::stri } } +bool exists_path(const boost::filesystem::path& path) { + boost::system::error_code ec; + bool ret = boost::filesystem::exists(path, ec); + if (!ret && ec != boost::system::errc::no_such_file_or_directory) { + std::string err_msg = "Failed to check if file exists: " + path.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, ec); + } + return ret; +} + + void check_and_migrate_logdir_format(const boost::filesystem::path& logdir) { boost::filesystem::path manifest_path = logdir / std::string(manifest_file_name); boost::filesystem::path manifest_backup_path = logdir / std::string(manifest_file_backup_name); boost::system::error_code ec; - if (!boost::filesystem::exists(manifest_path) && boost::filesystem::exists(manifest_backup_path)) { + if (!exists_path(manifest_path) && exists_path(manifest_backup_path)) { VLOG_LP(log_info) << "Manifest file is missing, but a backup file exists at " << manifest_backup_path.string() << ". Using the backup file as the manifest by renaming it to " << manifest_path.string(); boost::filesystem::rename(manifest_backup_path, manifest_path, ec); if (ec) { std::string err_msg = - "Failed to rename manifest backup from " + manifest_backup_path.string() + " to " + manifest_path.string() + ". Error: " + ec.message(); - LOG(ERROR) << err_msg; - throw std::runtime_error(err_msg); + "Failed to rename manifest backup from " + manifest_backup_path.string() + " to " + manifest_path.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, ec); } } - if (boost::filesystem::exists(manifest_path) && boost::filesystem::exists(manifest_backup_path)) { + if (exists_path(manifest_path) && exists_path(manifest_backup_path)) { VLOG_LP(log_info) << "both manifest and backup manifest file exists, removing backup manifest file"; boost::filesystem::remove(manifest_backup_path, ec); if (ec) { - std::string err_msg = "Failed to remove backup manifest file: " + manifest_backup_path.string() + ". Error: " + ec.message(); - LOG(ERROR) << err_msg; - throw std::runtime_error(err_msg); + std::string err_msg = "Failed to remove backup manifest file: " + manifest_backup_path.string(); + LOG_AND_THROW_IO_EXCEPTION(err_msg, ec); } } - if (!boost::filesystem::exists(manifest_path)) { + if (!exists_path(manifest_path)) { VLOG_LP(log_info) << "no manifest file in logdir, maybe v0"; - LOG(ERROR) << version_error_prefix << " (version mismatch: version 0, server supports version 1)"; - throw std::runtime_error("logdir version mismatch"); + THROW_LIMESTONE_EXCEPTION(std::string(version_error_prefix) + " (version mismatch: version 0, server supports version 1)"); } std::string errmsg; int vc = is_supported_version(manifest_path, errmsg); if (vc == 0) { LOG(ERROR) << version_error_prefix << " (" << errmsg << ")"; - throw std::runtime_error("logdir version mismatch"); + THROW_LIMESTONE_EXCEPTION("logdir version mismatch"); } if (vc < 0) { VLOG_LP(log_info) << errmsg; LOG(ERROR) << "/:limestone dbdir is corrupted, can not use."; - throw std::runtime_error("logdir corrupted"); + THROW_LIMESTONE_EXCEPTION("logdir corrupted"); } if (vc == 1) { // migrate to version 2 @@ -154,16 +158,14 @@ void check_and_migrate_logdir_format(const boost::filesystem::path& logdir) { boost::filesystem::rename(manifest_path, manifest_backup_path, ec); if (ec) { std::string err_msg = "Failed to rename manifest file: " + manifest_path.string() + " to " + manifest_backup_path.string() + ". Error: " + ec.message(); - LOG(ERROR) << err_msg; - throw std::runtime_error(err_msg); + LOG_AND_THROW_IO_EXCEPTION(err_msg, ec); } setup_initial_logdir(logdir); VLOG_LP(log_info) << "migration done"; boost::filesystem::remove(manifest_backup_path, ec); if (ec) { std::string err_msg = "Failed to remove backup manifest file: " + manifest_backup_path.string() + ". Error: " + ec.message(); - LOG(ERROR) << err_msg; - throw std::runtime_error(err_msg); + LOG_AND_THROW_IO_EXCEPTION(err_msg, ec); } } } diff --git a/src/limestone/datastore_snapshot.cpp b/src/limestone/datastore_snapshot.cpp index bca9cbe1..273c5536 100644 --- a/src/limestone/datastore_snapshot.cpp +++ b/src/limestone/datastore_snapshot.cpp @@ -26,6 +26,7 @@ #include "logging_helper.h" #include +#include "limestone_exception_helper.h" #include "dblog_scan.h" #include "internal.h" #include "log_entry.h" @@ -175,12 +176,12 @@ static std::pair create_sorted_from_wals( try { epoch_id_type max_appeared_epoch = logscan.scan_pwal_files_throws(ld_epoch, add_entry); return {max_appeared_epoch, std::move(sctx)}; - } catch (std::runtime_error& e) { + } catch (limestone_exception& e) { VLOG_LP(log_info) << "failed to scan pwal files: " << e.what(); LOG(ERROR) << "/:limestone recover process failed. (cause: corruption detected in transaction log data directory), " << "see https://github.com/project-tsurugi/tsurugidb/blob/master/docs/troubleshooting-guide.md"; LOG(ERROR) << "/:limestone dblogdir (transaction log directory): " << from_dir; - throw std::runtime_error("dblogdir is corrupted"); + throw limestone_exception("dblogdir is corrupted"); } } @@ -267,8 +268,7 @@ void create_compact_pwal( if (!result_check || error) { const bool result_mkdir = boost::filesystem::create_directory(to_dir, error); if (!result_mkdir || error) { - LOG_LP(ERROR) << "fail to create directory " << to_dir; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fail to create directory " + to_dir.string(), error); } } @@ -276,8 +276,7 @@ void create_compact_pwal( VLOG_LP(log_info) << "generating compacted pwal file: " << snapshot_file; FILE* ostrm = fopen(snapshot_file.c_str(), "w"); // NOLINT(*-owning-memory) if (!ostrm) { - LOG_LP(ERROR) << "cannot create snapshot file (" << snapshot_file << ")"; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("cannot create snapshot file (" + snapshot_file.string() + ")", errno); } setvbuf(ostrm, nullptr, _IOFBF, 128L * 1024L); // NOLINT, NB. glibc may ignore size when _IOFBF and buffer=NULL bool rewind = true; // TODO: change by flag @@ -296,8 +295,7 @@ void create_compact_pwal( sortdb_foreach(sctx, write_snapshot_entry); //log_entry::end_session(ostrm, epoch); if (fclose(ostrm) != 0) { // NOLINT(*-owning-memory) - LOG_LP(ERROR) << "cannot close snapshot file (" << snapshot_file << "), errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("cannot close snapshot file (" + snapshot_file.string() + ")", errno); } } @@ -318,8 +316,7 @@ void datastore::create_snapshot(const std::set& file_names) { if (!result_check || error) { const bool result_mkdir = boost::filesystem::create_directory(sub_dir, error); if (!result_mkdir || error) { - LOG_LP(ERROR) << "fail to create directory"; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fail to create directory", error); } } @@ -327,15 +324,13 @@ void datastore::create_snapshot(const std::set& file_names) { VLOG_LP(log_info) << "generating snapshot file: " << snapshot_file; FILE* ostrm = fopen(snapshot_file.c_str(), "w"); // NOLINT(*-owning-memory) if (!ostrm) { - LOG_LP(ERROR) << "cannot create snapshot file (" << snapshot_file << ")"; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("cannot create snapshot file", errno); } setvbuf(ostrm, nullptr, _IOFBF, 128L * 1024L); // NOLINT, NB. glibc may ignore size when _IOFBF and buffer=NULL auto write_snapshot_entry = [&ostrm](std::string_view key, std::string_view value){log_entry::write(ostrm, key, value);}; sortdb_foreach(sctx, write_snapshot_entry); if (fclose(ostrm) != 0) { // NOLINT(*-owning-memory) - LOG_LP(ERROR) << "cannot close snapshot file (" << snapshot_file << "), errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("cannot close snapshot file (" + snapshot_file.string() + ")", errno); } } diff --git a/src/limestone/dblog_scan.cpp b/src/limestone/dblog_scan.cpp index c4865f92..3de4f8e4 100644 --- a/src/limestone/dblog_scan.cpp +++ b/src/limestone/dblog_scan.cpp @@ -20,6 +20,7 @@ #include #include #include "logging_helper.h" +#include "limestone_exception_helper.h" #include #include "internal.h" @@ -40,13 +41,11 @@ std::optional last_durable_epoch(const boost::filesystem::path& f // ASSERT: file exists istrm.open(file, std::ios_base::in | std::ios_base::binary); if (!istrm) { // permission? - LOG_LP(ERROR) << "cannot read epoch file: " << file; - throw std::runtime_error("cannot read epoch file"); + THROW_LIMESTONE_IO_EXCEPTION("cannot read epoch file: " + file.string(), errno); } while (e.read(istrm)) { if (e.type() != log_entry::entry_type::marker_durable) { - LOG_LP(ERROR) << "this epoch file is broken: unexpected log_entry type: " << static_cast(e.type()); - throw std::runtime_error("unexpected log_entry type for epoch file"); + LOG_AND_THROW_EXCEPTION("this epoch file is broken: unexpected log_entry type: " + std::to_string(static_cast(e.type()))); } if (!rv.has_value() || e.epoch_id() > rv) { rv = e.epoch_id(); @@ -63,8 +62,7 @@ epoch_id_type dblog_scan::last_durable_epoch_in_dir() { if (!boost::filesystem::exists(main_epoch_file)) { // datastore operations (ctor and rotate) ensure that the main epoch file exists. // so it may directory called from outside of datastore - LOG_LP(ERROR) << "epoch file does not exist: " << main_epoch_file; - throw std::runtime_error("epoch file does not exist"); + LOG_AND_THROW_EXCEPTION("epoch file does not exist: " + main_epoch_file.string()); } std::optional ld_epoch = last_durable_epoch(main_epoch_file); if (ld_epoch.has_value()) { @@ -90,8 +88,8 @@ epoch_id_type dblog_scan::last_durable_epoch_in_dir() { } static bool log_error_and_throw(log_entry::read_error& e) { - LOG_LP(ERROR) << "this pwal file is broken: " << e.message(); - throw std::runtime_error("pwal file read error"); + LOG_AND_THROW_EXCEPTION("this pwal file is broken: " + e.message()); + return false; } void dblog_scan::detach_wal_files(bool skip_empty_files) { @@ -144,7 +142,7 @@ epoch_id_type dblog_scan::scan_pwal_files( // NOLINT(readability-function-cogni if (!is_detached_wal(p)) { VLOG(30) << "MARKED BUT TAIL IS BROKEN (NOT DETACHED): " << p; if (fail_fast_) { - throw std::runtime_error("the end of non-detached file is broken"); + THROW_LIMESTONE_EXCEPTION("the end of non-detached file is broken"); } } else { VLOG(30) << "MARKED BUT TAIL IS BROKEN (DETACHED): " << p; @@ -155,7 +153,7 @@ epoch_id_type dblog_scan::scan_pwal_files( // NOLINT(readability-function-cogni VLOG(30) << "TAIL IS BROKEN: " << p; if (!is_detached_wal(p)) { if (fail_fast_) { - throw std::runtime_error("the end of non-detached file is broken"); + THROW_LIMESTONE_EXCEPTION("the end of non-detached file is broken"); } } break; @@ -166,7 +164,7 @@ epoch_id_type dblog_scan::scan_pwal_files( // NOLINT(readability-function-cogni case parse_error::failed: VLOG(30) << "ERROR: " << p; if (fail_fast_) { - throw std::runtime_error(ec.message()); + THROW_LIMESTONE_EXCEPTION(ec.message()); } break; case parse_error::broken_after_tobe_cut: assert(false); @@ -204,7 +202,7 @@ epoch_id_type dblog_scan::scan_pwal_files( // NOLINT(readability-function-cogni try { process_file(p); - } catch (std::runtime_error& ex) { + } catch (limestone_exception& ex) { VLOG(log_info) << "/:limestone catch runtime_error(" << ex.what() << ")"; { std::lock_guard lock(list_mtx); diff --git a/src/limestone/dblogutil/dblogutil.cpp b/src/limestone/dblogutil/dblogutil.cpp index c1b0d524..d8433ba1 100644 --- a/src/limestone/dblogutil/dblogutil.cpp +++ b/src/limestone/dblogutil/dblogutil.cpp @@ -24,6 +24,7 @@ #include "dblog_scan.h" #include "internal.h" #include "log_entry.h" +#include "limestone_exception_helper.h" using namespace limestone::api; using namespace limestone::internal; @@ -63,7 +64,7 @@ void inspect(dblog_scan &ds, std::optional epoch) { epoch_id_type ld_epoch{}; try { ld_epoch = ds.last_durable_epoch_in_dir(); - } catch (std::runtime_error& ex) { + } catch (limestone_exception& ex) { LOG(ERROR) << "reading epoch file is failed: " << ex.what(); log_and_exit(64); } @@ -120,7 +121,7 @@ void repair(dblog_scan &ds, std::optional epoch) { } else { try { ld_epoch = ds.last_durable_epoch_in_dir(); - } catch (std::runtime_error& ex) { + } catch (limestone_exception& ex) { LOG(ERROR) << "reading epoch file is failed: " << ex.what(); log_and_exit(64); } @@ -166,8 +167,7 @@ void repair(dblog_scan &ds, std::optional epoch) { static boost::filesystem::path make_tmp_dir_next_to(const boost::filesystem::path& target_dir, const char* suffix) { auto tmpdirname = boost::filesystem::canonical(target_dir).string() + suffix; if (::mkdtemp(tmpdirname.data()) == nullptr) { - LOG_LP(ERROR) << "mkdtemp failed, errno = " << errno; - throw std::runtime_error("I/O error"); + THROW_LIMESTONE_IO_EXCEPTION("mkdtemp failed", errno); } return {tmpdirname}; } @@ -188,7 +188,7 @@ void compaction(dblog_scan &ds, std::optional epoch) { } else { try { ld_epoch = ds.last_durable_epoch_in_dir(); - } catch (std::runtime_error& ex) { + } catch (limestone_exception& ex) { LOG(ERROR) << "reading epoch file is failed: " << ex.what(); log_and_exit(64); } @@ -224,22 +224,18 @@ void compaction(dblog_scan &ds, std::optional epoch) { VLOG_LP(log_info) << "making compact epoch file to " << tmp; FILE* strm = fopen((tmp / "epoch").c_str(), "a"); // NOLINT(*-owning-memory) if (!strm) { - LOG_LP(ERROR) << "fopen failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fopen failed", errno); } // TODO: if to-flat mode, set ld_epoch := 1 log_entry::durable_epoch(strm, ld_epoch); if (fflush(strm) != 0) { - LOG_LP(ERROR) << "fflush failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fflush failed", errno); } if (fsync(fileno(strm)) != 0) { - LOG_LP(ERROR) << "fsync failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fsync failed", errno); } if (fclose(strm) != 0) { // NOLINT(*-owning-memory) - LOG_LP(ERROR) << "fclose failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fclose failed", errno); } if (FLAGS_dry_run) { @@ -298,7 +294,7 @@ int main(char *dir, subcommand mode) { // NOLINT if (mode == cmd_inspect) inspect(ds, opt_epoch); if (mode == cmd_repair) repair(ds, opt_epoch); if (mode == cmd_compaction) compaction(ds, opt_epoch); - } catch (std::runtime_error& e) { + } catch (limestone_exception& e) { LOG(ERROR) << e.what(); log_and_exit(64); } diff --git a/src/limestone/limestone_exception_helper.h b/src/limestone/limestone_exception_helper.h index de7d896e..05933c17 100644 --- a/src/limestone/limestone_exception_helper.h +++ b/src/limestone/limestone_exception_helper.h @@ -16,8 +16,9 @@ #include #include -#include "logging_helper.h" +#include +#include "logging_helper.h" #include #pragma once @@ -35,6 +36,10 @@ inline void throw_limestone_io_exception(const std::string& message, int error_c throw limestone_io_exception(message + " (at " + std::filesystem::path(file).filename().string() + ":" + std::to_string(line) + ")", error_code); } +inline void throw_limestone_io_exception(const std::string& message, const boost::system::error_code& error_code, const char* file, int line) { + throw limestone_io_exception(message + " (at " + std::filesystem::path(file).filename().string() + ":" + std::to_string(line) + ")", error_code.value()); +} + inline void log_and_throw_exception(const std::string& message, const char* file, int line) { LOG_LP(ERROR) << message; throw_limestone_exception(message, file, line); @@ -46,6 +51,12 @@ inline void log_and_throw_io_exception(const std::string& message, int error_cod throw_limestone_io_exception(message, error_code, file, line); } +inline void log_and_throw_io_exception(const std::string& message, const boost::system::error_code& error_code, const char* file, int line) { + std::string full_message = limestone_io_exception::format_message(message, error_code.value()); + LOG_LP(ERROR) << full_message; + throw_limestone_io_exception(message, error_code, file, line); +} + // NOLINTNEXTLINE #define THROW_LIMESTONE_EXCEPTION(message) throw_limestone_exception(message, __FILE__, __LINE__) diff --git a/src/limestone/log_channel.cpp b/src/limestone/log_channel.cpp index 6ae8a823..fd472126 100644 --- a/src/limestone/log_channel.cpp +++ b/src/limestone/log_channel.cpp @@ -21,6 +21,7 @@ #include #include #include "logging_helper.h" +#include "limestone_exception_helper.h" #include #include @@ -48,8 +49,7 @@ void log_channel::begin_session() { auto log_file = file_path(); strm_ = fopen(log_file.c_str(), "a"); // NOLINT(*-owning-memory) if (!strm_) { - LOG_LP(ERROR) << "I/O error, cannot make file on " << location_ << ", errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("cannot make file on " + location_.string(), errno); } setvbuf(strm_, nullptr, _IOFBF, 128L * 1024L); // NOLINT, NB. glibc may ignore size when _IOFBF and buffer=NULL if (!registered_) { @@ -65,20 +65,17 @@ void log_channel::begin_session() { void log_channel::end_session() { if (fflush(strm_) != 0) { - LOG_LP(ERROR) << "fflush failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fflush failed", errno); } if (fsync(fileno(strm_)) != 0) { - LOG_LP(ERROR) << "fsync failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fsync failed", errno); } finished_epoch_id_.store(current_epoch_id_.load()); current_epoch_id_.store(UINT64_MAX); envelope_.update_min_epoch_id(); if (fclose(strm_) != 0) { // NOLINT(*-owning-memory) - LOG_LP(ERROR) << "fclose failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fclose failed", errno); } // Remove current_epoch_id_ from waiting_epoch_ids_ @@ -102,8 +99,7 @@ void log_channel::add_entry(storage_id_type storage_id, std::string_view key, st } void log_channel::add_entry([[maybe_unused]] storage_id_type storage_id, [[maybe_unused]] std::string_view key, [[maybe_unused]] std::string_view value, [[maybe_unused]] write_version_type write_version, [[maybe_unused]] const std::vector& large_objects) { - LOG_LP(ERROR) << "not implemented"; - throw std::runtime_error("not implemented"); // FIXME + LOG_AND_THROW_EXCEPTION("not implemented");// FIXME }; void log_channel::remove_entry(storage_id_type storage_id, std::string_view key, write_version_type write_version) { diff --git a/src/limestone/log_entry.h b/src/limestone/log_entry.h index a01e5416..a2b6d5e8 100644 --- a/src/limestone/log_entry.h +++ b/src/limestone/log_entry.h @@ -29,6 +29,7 @@ #include #include #include "logging_helper.h" +#include "limestone_exception_helper.h" namespace limestone::api { @@ -251,8 +252,7 @@ class log_entry { read_error ec{}; bool rc = read_entry_from(strm, ec); if (ec) { - LOG_LP(ERROR) << "this log_entry is broken: " << ec.message(); - throw std::runtime_error(ec.message()); + LOG_AND_THROW_EXCEPTION("this log_entry is broken: " + ec.message()); } return rc; } @@ -380,8 +380,7 @@ class log_entry { static void write_uint8(FILE* out, const std::uint8_t value) { int ret = fputc(value, out); if (ret == EOF) { - LOG_LP(ERROR) << "fputc failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fputc failed", errno); } } static void write_uint32le(FILE* out, const std::uint32_t value) { @@ -406,8 +405,7 @@ class log_entry { if (len == 0) return; // nothing to write auto ret = fwrite(buf, len, 1, out); if (ret != 1) { - LOG_LP(ERROR) << "fwrite failed, errno = " << errno; - throw std::runtime_error("I/O error"); + LOG_AND_THROW_IO_EXCEPTION("fwrite failed", errno); } } static void read_bytes(std::istream& in, void* buf, std::streamsize len, read_error& ec) { diff --git a/src/limestone/online_compaction.cpp b/src/limestone/online_compaction.cpp index 539f7198..fe83feb6 100644 --- a/src/limestone/online_compaction.cpp +++ b/src/limestone/online_compaction.cpp @@ -20,6 +20,7 @@ #include #include +#include "limestone_exception_helper.h" #include "logging_helper.h" #include "compaction_catalog.h" @@ -31,8 +32,7 @@ void safe_rename(const boost::filesystem::path& from, const boost::filesystem::p boost::system::error_code error; boost::filesystem::rename(from, to, error); if (error) { - LOG_LP(ERROR) << "fail to rename file: error_code: " << error << ", from: " << from << ", to: " << to; - throw std::runtime_error("fail to rename the file"); + LOG_AND_THROW_IO_EXCEPTION("fail to rename the file from: " + from.string() + ", to: " + to.string() , error); } } @@ -57,15 +57,13 @@ std::set select_files_for_compaction(const std::set get_files_in_directory(const boost::filesystem::path& dire boost::system::error_code error; if (!boost::filesystem::exists(directory, error)) { - LOG_LP(ERROR) << "Directory does not exist: " << directory << ", error_code: " << error.message(); - throw std::runtime_error("Directory does not exist: " + directory.string()); + LOG_AND_THROW_IO_EXCEPTION("Directory does not exist: " + directory.string(), error); } if (!boost::filesystem::is_directory(directory, error)) { - LOG_LP(ERROR) << "The path exists but is not a directory: " << directory << ", error_code: " << error.message(); - throw std::runtime_error("The path exists but is not a directory: " + directory.string()); + LOG_AND_THROW_IO_EXCEPTION("The path exists but is not a directory: " + directory.string(), error.value()); } for (boost::filesystem::directory_iterator it(directory, error), end; it != end && !error; it.increment(error)) { @@ -104,8 +99,7 @@ std::set get_files_in_directory(const boost::filesystem::path& dire } if (error) { - LOG_LP(ERROR) << "Error while iterating directory: " << directory << ", error_code: " << error.message(); - throw std::runtime_error("Error while iterating directory: " + directory.string()); + LOG_AND_THROW_IO_EXCEPTION("Error while iterating directory: " + directory.string(), error.value()); } return files; @@ -116,8 +110,7 @@ void remove_file_safely(const boost::filesystem::path& file) { boost::system::error_code error; boost::filesystem::remove(file, error); if (error) { - LOG_LP(ERROR) << "failed to remove file: error_code: " << error << ", path: " << file; - throw std::runtime_error("Failed to remove the file"); + LOG_AND_THROW_IO_EXCEPTION("Failed to remove the file", error); } } diff --git a/src/limestone/online_compaction.h b/src/limestone/online_compaction.h index d0333a3d..8124a52f 100644 --- a/src/limestone/online_compaction.h +++ b/src/limestone/online_compaction.h @@ -31,7 +31,7 @@ namespace limestone::internal { * * @param from The current path of the file or directory. * @param to The new path to rename the file or directory to. - * @throws std::runtime_error if the renaming operation fails. + * @throws limestone_exception if the renaming operation fails. */ void safe_rename(const boost::filesystem::path& from, const boost::filesystem::path& to); @@ -56,7 +56,7 @@ std::set select_files_for_compaction(const std::set get_files_in_directory(const boost::filesystem::path& dire * an error message and throws a runtime exception. * * @param file The path of the file to be removed. - * @throws std::runtime_error if the file removal operation fails. + * @throws limestone_exception if the file removal operation fails. */ void remove_file_safely(const boost::filesystem::path& file); diff --git a/src/limestone/parse_wal_file.cpp b/src/limestone/parse_wal_file.cpp index b3184326..99ee846f 100644 --- a/src/limestone/parse_wal_file.cpp +++ b/src/limestone/parse_wal_file.cpp @@ -20,6 +20,7 @@ #include #include #include "logging_helper.h" +#include "limestone_exception_helper.h" #include #include "dblog_scan.h" @@ -225,8 +226,7 @@ epoch_id_type dblog_scan::scan_one_pwal_file( // NOLINT(readability-function-co boost::filesystem::fstream strm; strm.open(p, std::ios_base::in | std::ios_base::out | std::ios_base::binary); if (!strm) { - LOG_LP(ERROR) << "cannot open pwal file: " << p; - throw std::runtime_error("cannot open pwal file"); + LOG_AND_THROW_IO_EXCEPTION("cannot open pwal file: " + p.string(), errno); } bool valid = true; // scanning in the normal (not-invalidated) epoch snippet [[maybe_unused]] @@ -287,8 +287,8 @@ epoch_id_type dblog_scan::scan_one_pwal_file( // NOLINT(readability-function-co pe = parse_error(parse_error::repaired); } break; - // case process_at_nondurable::repair_by_cut: - // throw std::runtime_error("unimplemented repair method"); + // case process_at_nondurable::repair_by_cut: + // THROW_LIMESTONE_EXCEPTION("unimplemented repair method"); case process_at_nondurable::report: invalidated_wrote = false; log_entry::read_error nondurable(log_entry::read_error::nondurable_snippet); diff --git a/src/limestone/sortdb_wrapper.h b/src/limestone/sortdb_wrapper.h index 1de46ed5..99ed3db9 100644 --- a/src/limestone/sortdb_wrapper.h +++ b/src/limestone/sortdb_wrapper.h @@ -27,6 +27,7 @@ #include #include +#include "limestone_exception_helper.h" namespace limestone::api { #ifdef SORT_METHOD_USE_ROCKSDB @@ -81,8 +82,7 @@ class sortdb_wrapper { WriteOptions write_options{}; auto status = sortdb_->Put(write_options, key, value); if (status.ok()) { return; } - LOG_LP(ERROR) << "sortdb put error, status: " << status.ToString(); - throw std::runtime_error("error in sortdb put"); + LOG_AND_THROW_EXCEPTION("sortdb put error, status: " + status.ToString()); } bool get(const std::string& key, std::string* value) { @@ -90,8 +90,8 @@ class sortdb_wrapper { auto status = sortdb_->Get(read_options, key, value); if (status.ok()) { return true; } if (status.IsNotFound()) { return false; } - LOG_LP(ERROR) << "sortdb get error, status: " << status.ToString(); - throw std::runtime_error("error in sortdb get"); + LOG_AND_THROW_EXCEPTION("sortdb get error, status: " + status.ToString()); + return false; // Added return statement to ensure function always returns a value } void each(const std::function& fun) { @@ -102,8 +102,7 @@ class sortdb_wrapper { fun(std::string_view(key.data(), key.size()), std::string_view(value.data(), value.size())); } if (!it->status().ok()) { - LOG_LP(ERROR) << "sortdb iterator invalidated, status: " << it->status().ToString(); - throw std::runtime_error("error in sortdb read iteration"); + LOG_AND_THROW_EXCEPTION("sortdb iterator invalidated, status: " + it->status().ToString()); } }