From 4bace6f68165ca031ddad75d01122a25a2bafec2 Mon Sep 17 00:00:00 2001 From: ImBenji Date: Thu, 4 Dec 2025 20:33:06 +0000 Subject: [PATCH] Add thread-local caches for file locks and handles in fd_pool --- cpp/CMakeLists.txt | 1 - .../Private/sweepstore/utils/file_lock.cpp | 7 ++ cpp/src/Public/sweepstore/sweepstore.h | 2 +- cpp/src/Public/sweepstore/utils/file_lock.h | 66 +++++++++++++++++++ 4 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 cpp/src/Private/sweepstore/utils/file_lock.cpp diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index cbc396f..b660dab 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -20,7 +20,6 @@ add_executable(main src/Public/sweepstore/concurrency.h src/Private/sweepstore/concurrency.cpp src/Public/sweepstore/utils/file_lock.h - src/Private/sweepstore/utils/fd_pool.h src/Private/sweepstore/utils/fd_pool.cpp src/Public/sweepstore/utils/file_handle.h src/Private/sweepstore/utils/file_handle.cpp diff --git a/cpp/src/Private/sweepstore/utils/file_lock.cpp b/cpp/src/Private/sweepstore/utils/file_lock.cpp new file mode 100644 index 0000000..9096650 --- /dev/null +++ b/cpp/src/Private/sweepstore/utils/file_lock.cpp @@ -0,0 +1,7 @@ +#include "sweepstore/utils/file_lock.h" + +#ifdef _WIN32 +thread_local std::unordered_map SweepstoreFileLock::handleCache; +#else +thread_local std::unordered_map SweepstoreFileLock::fdCache; +#endif diff --git a/cpp/src/Public/sweepstore/sweepstore.h b/cpp/src/Public/sweepstore/sweepstore.h index 7fc2253..1febfc9 100644 --- a/cpp/src/Public/sweepstore/sweepstore.h +++ b/cpp/src/Public/sweepstore/sweepstore.h @@ -57,7 +57,7 @@ public: } ); - }; + } }; Proxy operator[](const std::string& key) { diff --git a/cpp/src/Public/sweepstore/utils/file_lock.h b/cpp/src/Public/sweepstore/utils/file_lock.h index 2b49037..3e1a52e 100644 --- a/cpp/src/Public/sweepstore/utils/file_lock.h +++ b/cpp/src/Public/sweepstore/utils/file_lock.h @@ -25,6 +25,55 @@ private: Mode mode; bool locked = false; +#ifdef _WIN32 + // Thread-local HANDLE cache for Windows + static thread_local std::unordered_map handleCache; + + static HANDLE getOrOpenHandle(const std::string& path) { + auto it = handleCache.find(path); + if (it != handleCache.end()) { + return it->second; + } + + HANDLE handle = CreateFileA( + path.c_str(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (handle == INVALID_HANDLE_VALUE) { + throw std::runtime_error("Failed to open file for locking: " + path); + } + + handleCache[path] = handle; + return handle; + } + + void acquire() { + HANDLE handle = getOrOpenHandle(filePath); + OVERLAPPED overlapped = {0}; + DWORD flags = (mode == Mode::Exclusive) ? LOCKFILE_EXCLUSIVE_LOCK : 0; + flags |= LOCKFILE_FAIL_IMMEDIATELY; + + if (!LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped)) { + throw std::runtime_error("Failed to acquire file lock"); + } + locked = true; + } + + void release() { + if (locked) { + HANDLE handle = getOrOpenHandle(filePath); + OVERLAPPED overlapped = {0}; + UnlockFileEx(handle, 0, MAXDWORD, MAXDWORD, &overlapped); + locked = false; + } + } +#else // Thread-local FD cache - each thread has its own FD per file static thread_local std::unordered_map fdCache; @@ -60,6 +109,7 @@ private: locked = false; } } +#endif public: // Constructor accepts offset/length for API compatibility (unused with flock) @@ -82,6 +132,21 @@ public: // Check if file is currently locked (non-blocking test) bool isLocked() const { +#ifdef _WIN32 + HANDLE handle = getOrOpenHandle(filePath); + OVERLAPPED overlapped = {0}; + DWORD flags = (mode == Mode::Exclusive) ? LOCKFILE_EXCLUSIVE_LOCK : 0; + flags |= LOCKFILE_FAIL_IMMEDIATELY; + + // Try non-blocking lock + if (!LockFileEx(handle, flags, 0, MAXDWORD, MAXDWORD, &overlapped)) { + return true; // Already locked + } + + // Got the lock, release immediately + UnlockFileEx(handle, 0, MAXDWORD, MAXDWORD, &overlapped); + return false; +#else int fd = getOrOpenFD(filePath); int operation = (mode == Mode::Exclusive) ? LOCK_EX : LOCK_SH; @@ -93,6 +158,7 @@ public: // Got the lock, release immediately flock(fd, LOCK_UN); return false; +#endif } // RAII helper for scoped locking