diff --git a/CMakeLists.txt b/CMakeLists.txt index e2d7af8..4a8b0bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,6 +54,7 @@ add_executable(seadisk src/main.cpp src/seafile/fs/winfsp_adapter.cpp include/seafile/fs/winfsp_adapter.hpp src/util/string_util.cpp + include/seafile/cache/cache.hpp ) target_compile_definitions(seadisk PRIVATE diff --git a/include/seafile/cache/cache.hpp b/include/seafile/cache/cache.hpp new file mode 100644 index 0000000..59a786a --- /dev/null +++ b/include/seafile/cache/cache.hpp @@ -0,0 +1,112 @@ +// +// Created by Shell on 2026/7/13. +// + +#ifndef SEADISK_CACHE_HPP +#define SEADISK_CACHE_HPP +#include +#include +#include + +namespace seafile::cache { + template + class Cache final{ + public: + using Clock = std::chrono::steady_clock; + using Duration = Clock::duration; + + /// 设置缓存 + /// @param key 键 + /// @param value 值 + /// @param ttl 超时时间 + void put(const K &key, V value, const Duration ttl) { + std::unique_lock lock(mutex_); + + cache_[key] = Entry{ + std::move(value), + Clock::now() + ttl + }; + } + + /// 获取缓存值 + /// @param key 键 + /// @return 缓存值 + std::optional get(const K &key) { + // 第一阶段:读锁 + { + std::shared_lock lock(mutex_); + + auto it = cache_.find(key); + if (it == cache_.end()) + return std::nullopt; + + if (Clock::now() < it->second.expire_time) + return it->second.value; + } + + // 第二阶段:删除过期数据 + { + std::unique_lock lock(mutex_); + + auto it = cache_.find(key); + if (it != cache_.end() && + Clock::now() >= it->second.expire_time) + { + cache_.erase(it); + } + } + + return std::nullopt; + } + + /// 移除缓存 + /// @param key 键 + void remove(const K &key) { + std::unique_lock lock(mutex_); + cache_.erase(key); + } + + ///清空缓存 + void clear() { + std::unique_lock lock(mutex_); + cache_.clear(); + } + + ///清理过时的缓存 + void cleanup() { + auto now = Clock::now(); + + std::unique_lock lock(mutex_); + + for (auto it = cache_.begin(); it != cache_.end();) + { + if (it->second.expireTime <= now) + { + it = cache_.erase(it); + } + else + { + ++it; + } + } + } + + ///缓存大小 + size_t size() const { + std::unique_lock lock(mutex_); + return cache_.size(); + } + + private: + struct Entry final { + V value; + Clock::time_point expire_time; + }; + + mutable std::shared_mutex mutex_; + + std::unordered_map cache_; + }; +} + +#endif //SEADISK_CACHE_HPP diff --git a/include/seafile/fs/seafile_file_system.hpp b/include/seafile/fs/seafile_file_system.hpp index 7bfdea5..6912eba 100644 --- a/include/seafile/fs/seafile_file_system.hpp +++ b/include/seafile/fs/seafile_file_system.hpp @@ -9,6 +9,7 @@ #include "../api/seafile_api.hpp" #include "../api/token_type.hpp" +#include "seafile/cache/cache.hpp" namespace seafile::fs { @@ -19,6 +20,8 @@ namespace seafile::fs TokenType token_type = TokenType::TOKEN; SeaFileApi api; std::wstring volume_label; + cache::Cache> repo_dir_cache{}; + public: explicit SeafileFileSystem(const std::string& server, diff --git a/src/seafile/fs/seafile_file_system.cpp b/src/seafile/fs/seafile_file_system.cpp index 10fd80e..824d7d3 100644 --- a/src/seafile/fs/seafile_file_system.cpp +++ b/src/seafile/fs/seafile_file_system.cpp @@ -3,6 +3,7 @@ #include "seafile/fs/file_context.hpp" #include "util/string_util.hpp" #include +#include namespace seafile::fs { namespace { @@ -26,7 +27,8 @@ namespace seafile::fs { return (static_cast(ft.dwHighDateTime) << 32) | ft.dwLowDateTime; } - void SetFileInfo(FSP_FSCTL_FILE_INFO *FileInfo, const uint32_t attributes, const uint64_t size,const int64_t mtime) { + void SetFileInfo(FSP_FSCTL_FILE_INFO *FileInfo, const uint32_t attributes, const uint64_t size, + const int64_t mtime) { FileInfo->FileAttributes = attributes; FileInfo->AllocationSize = size; FileInfo->FileSize = size; @@ -156,7 +158,7 @@ namespace seafile::fs { const auto copy_len = (std::min)(data.size(), static_cast(Length)); memcpy(Buffer, data.data(), copy_len); *PBytesTransferred = static_cast(copy_len); - spdlog::info(std::format("read file {} bytes offset {} length {} success", fc->path,Offset, Length)); + spdlog::info(std::format("read file {} bytes offset {} length {} success", fc->path, Offset, Length)); return STATUS_SUCCESS; } return STATUS_UNSUCCESSFUL; @@ -166,11 +168,19 @@ namespace seafile::fs { PVOID Buffer, ULONG BufferLength, PULONG PBytesTransferred) { const auto fc = static_cast(FileContext); *PBytesTransferred = 0; - const auto path = std::ranges::replace(fc->path, '\\', '/'); - const auto entries_result = api.repoDir(fc->repo_id, fc->path, token, token_type); + const auto cache_key = std::format("{}_{}", fc->repo_id, fc->path); + auto repo_entries = repo_dir_cache.get(cache_key); + if (!repo_entries.has_value()) { + if (auto entries_result = api.repoDir(fc->repo_id, fc->path, token, token_type); entries_result.has_value()) { + repo_entries = entries_result.value(); + repo_dir_cache.put(cache_key, repo_entries.value(),std::chrono::seconds(60)); + }else { + spdlog::error(std::format("can't read directory {},due to {}", fc->path,entries_result.error().what())); + } + } - if (entries_result.has_value()) { - const auto &entries = entries_result.value(); + if (repo_entries.has_value()) { + const auto &entries = repo_entries.value(); size_t start = 0; if (Marker) { const auto marker = shell::util::StringUtil::utf16le_to_utf8(Marker); @@ -208,7 +218,6 @@ namespace seafile::fs { return STATUS_SUCCESS; } - std::cout << entries_result.error().what() << std::endl; return STATUS_UNSUCCESSFUL; }