diff --git a/support/include/utils/config.hpp b/support/include/utils/config.hpp index e995f7f0..719a6ca0 100644 --- a/support/include/utils/config.hpp +++ b/support/include/utils/config.hpp @@ -468,7 +468,7 @@ struct http_range final { std::uint64_t end{}; }; -using http_headers = std::map; +using http_headers = std::unordered_map; using http_query_parameters = std::map; using http_ranges = std::vector; #endif // defined(PROJECT_ENABLE_CURL) diff --git a/support/include/utils/file_thread_file.hpp b/support/include/utils/file_thread_file.hpp index 74cf110e..15234d80 100644 --- a/support/include/utils/file_thread_file.hpp +++ b/support/include/utils/file_thread_file.hpp @@ -23,6 +23,7 @@ #define REPERTORY_INCLUDE_UTILS_FILE_THREAD_FILE_HPP_ #include "utils/file.hpp" +#include namespace repertory::utils::file { class thread_file final : public i_file { @@ -67,11 +68,44 @@ public: thread_file(thread_file &&move_file) noexcept : file_(std::move(move_file.file_)) {} - ~thread_file() override { close(); } + ~thread_file() override; + +private: + using action_t = std::function; + + struct io_item final { + action_t action; + bool complete{false}; + std::unique_ptr mtx{ + std::make_unique(), + }; + mutable std::unique_ptr notify{ + std::make_unique(), + }; + bool success{false}; + + void done(bool result); + + void wait() const; + }; private: fs_file_t file_; +private: + mutable std::vector actions_; + mutable std::unique_ptr io_thread_; + mutable std::unique_ptr mtx_{std::make_unique()}; + mutable std::unique_ptr notify_{ + std::make_unique(), + }; + stop_type stop_requested_{false}; + +private: + auto do_io(action_t action) const -> bool; + + void thread_func() const; + public: void close() override; diff --git a/support/src/utils/file_smb_directory.cpp b/support/src/utils/file_smb_directory.cpp index bef0d576..190366f5 100644 --- a/support/src/utils/file_smb_directory.cpp +++ b/support/src/utils/file_smb_directory.cpp @@ -127,7 +127,7 @@ auto smb_directory::open(std::wstring_view host, std::wstring_view user, } auto smb_directory::copy_to(std::string_view new_path, - bool overwrite) const -> bool { + bool /* overwrite */) const -> bool { REPERTORY_USES_FUNCTION_NAME(); try { diff --git a/support/src/utils/file_thread_file.cpp b/support/src/utils/file_thread_file.cpp index 4ffc6aff..20576091 100644 --- a/support/src/utils/file_thread_file.cpp +++ b/support/src/utils/file_thread_file.cpp @@ -25,41 +25,174 @@ namespace repertory::utils::file { // auto thread_file::attach_file(native_handle handle, // bool read_only) -> fs_file_t {} -thread_file::thread_file(std::string_view path) - : file_(new repertory::utils::file::file(path)) {} - -thread_file::thread_file(std::wstring_view path) - : file_(new repertory::utils::file::file(utils::string::to_utf8(path))) {} - -auto thread_file::attach_file(fs_file_t file) -> fs_file_t {} +auto thread_file::attach_file(fs_file_t file) -> fs_file_t { + return fs_file_t{ + new thread_file(std::move(file)), + }; +} auto thread_file::open_file(std::string_view path, - bool read_only) -> fs_file_t {} + bool read_only) -> fs_file_t { + return fs_file_t{ + new thread_file(file::open_file(path, read_only)), + }; +} auto thread_file::open_or_create_file(std::string_view path, - bool read_only) -> fs_file_t {} + bool read_only) -> fs_file_t { + return fs_file_t{ + new thread_file(file::open_or_create_file(path, read_only)), + }; +} + +void thread_file::io_item::done(bool result) { + unique_mutex_lock lock(*mtx); + complete = true; + success = result; + notify->notify_all(); +} + +void thread_file::io_item::wait() const { + if (complete) { + return; + } + + unique_mutex_lock lock(*mtx); + while (not complete) { + notify->wait(lock); + } + notify->notify_all(); +} + +thread_file::thread_file(std::string_view path) : file_(new file(path)) {} + +thread_file::thread_file(std::wstring_view path) + : file_(new file(utils::string::to_utf8(path))) {} thread_file::thread_file(fs_file_t file) : file_(std::move(file)) {} -void thread_file::close() {} +thread_file::~thread_file() { + close(); + + if (io_thread_) { + io_thread_->join(); + } +} + +void thread_file::close() { + do_io([this]() -> bool { + file_->close(); + stop_requested_ = true; + return true; + }); +} auto thread_file::copy_to(std::string_view new_path, - bool overwrite) const -> bool {} + bool overwrite) const -> bool { + return do_io([this, &new_path, &overwrite]() -> bool { + return file_->copy_to(new_path, overwrite); + }); +} -void thread_file::flush() const {} +auto thread_file::do_io(action_t action) const -> bool { + unique_mutex_lock lock(*mtx_); + if (stop_requested_) { + return false; + } -auto thread_file::move_to(std::string_view path) -> bool {} + if (not io_thread_) { + io_thread_ = std::make_unique([this]() { thread_func(); }); + } + + io_item item{action}; + actions_.emplace_back(&item); + notify_->notify_all(); + lock.unlock(); + + item.wait(); + + return item.success; +} + +void thread_file::flush() const { + do_io([this]() -> bool { + file_->flush(); + return true; + }); +} + +auto thread_file::move_to(std::string_view path) -> bool { + return do_io([this, &path]() -> bool { return file_->move_to(path); }); +} auto thread_file::read(unsigned char *data, std::size_t to_read, - std::uint64_t offset, std::size_t *total_read) -> bool {} + std::uint64_t offset, std::size_t *total_read) -> bool { + return do_io([this, &data, &to_read, &offset, &total_read]() -> bool { + return file_->read(data, to_read, offset, total_read); + }); +} -auto thread_file::remove() -> bool {} +auto thread_file::remove() -> bool { + return do_io([this]() -> bool { return file_->remove(); }); +} -auto thread_file::truncate(std::size_t size) -> bool {} +void thread_file::thread_func() const { + unique_mutex_lock lock(*mtx_); + notify_->notify_all(); + lock.unlock(); + + const auto run_actions = [this, &lock]() { + auto actions = actions_; + actions_.clear(); + notify_->notify_all(); + lock.unlock(); + + for (auto &&action : actions) { + action->done(action->action()); + } + }; + + while (not stop_requested_) { + lock.lock(); + if (stop_requested_) { + lock.unlock(); + break; + } + + while (not stop_requested_ && actions_.empty()) { + notify_->wait(lock); + } + + if (stop_requested_) { + lock.unlock(); + break; + } + + run_actions(); + } + + lock.lock(); + run_actions(); +} + +auto thread_file::truncate(std::size_t size) -> bool { + return do_io([this, &size]() -> bool { return file_->truncate(size); }); +} auto thread_file::write(const unsigned char *data, std::size_t to_write, std::size_t offset, - std::size_t *total_written) -> bool {} + std::size_t *total_written) -> bool { + return do_io([this, &data, &to_write, &offset, &total_written]() -> bool { + return file_->write(data, to_write, offset, total_written); + }); +} -auto thread_file::size() const -> std::optional {} +auto thread_file::size() const -> std::optional { + std::optional size; + do_io([this, &size]() -> bool { + size = file_->size(); + return size.has_value(); + }); + return size; +} } // namespace repertory::utils::file diff --git a/support/test/src/test.cpp b/support/test/src/test.cpp index e094247a..f9d78280 100644 --- a/support/test/src/test.cpp +++ b/support/test/src/test.cpp @@ -57,8 +57,10 @@ auto create_random_file(std::size_t size) -> utils::file::i_file & { #if defined(PROJECT_ENABLE_LIBSODIUM) randombytes_buf(buf.data(), buf.size()); #else // !defined(PROJECT_ENABLE_LIBSODIUM) - thread_local std::mt19937 gen(static_cast( - std::time(nullptr) ^ std::random_device{}())); + thread_local std::mt19937 gen{ + static_cast(std::time(nullptr)) ^ + static_cast(std::random_device{}()), + }; std::uniform_int_distribution dis(0U, 255U); std::generate(buf.begin(), buf.end(), [&]() -> auto { return dis(gen); }); #endif // defined(PROJECT_ENABLE_LIBSODIUM) diff --git a/support/test/src/utils/file_test.cpp b/support/test/src/utils/file_test.cpp index 04788070..6997407f 100644 --- a/support/test/src/utils/file_test.cpp +++ b/support/test/src/utils/file_test.cpp @@ -22,7 +22,7 @@ #include "test.hpp" namespace { -static constexpr const auto file_type_count{1U}; +static constexpr const auto file_type_count{2U}; } namespace repertory {