Add thread-local caches for file locks and handles in fd_pool
This commit is contained in:
@@ -20,7 +20,6 @@ add_executable(main
|
|||||||
src/Public/sweepstore/concurrency.h
|
src/Public/sweepstore/concurrency.h
|
||||||
src/Private/sweepstore/concurrency.cpp
|
src/Private/sweepstore/concurrency.cpp
|
||||||
src/Public/sweepstore/utils/file_lock.h
|
src/Public/sweepstore/utils/file_lock.h
|
||||||
src/Private/sweepstore/utils/fd_pool.h
|
|
||||||
src/Private/sweepstore/utils/fd_pool.cpp
|
src/Private/sweepstore/utils/fd_pool.cpp
|
||||||
src/Public/sweepstore/utils/file_handle.h
|
src/Public/sweepstore/utils/file_handle.h
|
||||||
src/Private/sweepstore/utils/file_handle.cpp
|
src/Private/sweepstore/utils/file_handle.cpp
|
||||||
|
|||||||
7
cpp/src/Private/sweepstore/utils/file_lock.cpp
Normal file
7
cpp/src/Private/sweepstore/utils/file_lock.cpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include "sweepstore/utils/file_lock.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
thread_local std::unordered_map<std::string, HANDLE> SweepstoreFileLock::handleCache;
|
||||||
|
#else
|
||||||
|
thread_local std::unordered_map<std::string, int> SweepstoreFileLock::fdCache;
|
||||||
|
#endif
|
||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Proxy operator[](const std::string& key) {
|
Proxy operator[](const std::string& key) {
|
||||||
|
|||||||
@@ -25,6 +25,55 @@ private:
|
|||||||
Mode mode;
|
Mode mode;
|
||||||
bool locked = false;
|
bool locked = false;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Thread-local HANDLE cache for Windows
|
||||||
|
static thread_local std::unordered_map<std::string, HANDLE> 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
|
// Thread-local FD cache - each thread has its own FD per file
|
||||||
static thread_local std::unordered_map<std::string, int> fdCache;
|
static thread_local std::unordered_map<std::string, int> fdCache;
|
||||||
|
|
||||||
@@ -60,6 +109,7 @@ private:
|
|||||||
locked = false;
|
locked = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor accepts offset/length for API compatibility (unused with flock)
|
// Constructor accepts offset/length for API compatibility (unused with flock)
|
||||||
@@ -82,6 +132,21 @@ public:
|
|||||||
|
|
||||||
// Check if file is currently locked (non-blocking test)
|
// Check if file is currently locked (non-blocking test)
|
||||||
bool isLocked() const {
|
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 fd = getOrOpenFD(filePath);
|
||||||
int operation = (mode == Mode::Exclusive) ? LOCK_EX : LOCK_SH;
|
int operation = (mode == Mode::Exclusive) ? LOCK_EX : LOCK_SH;
|
||||||
|
|
||||||
@@ -93,6 +158,7 @@ public:
|
|||||||
// Got the lock, release immediately
|
// Got the lock, release immediately
|
||||||
flock(fd, LOCK_UN);
|
flock(fd, LOCK_UN);
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// RAII helper for scoped locking
|
// RAII helper for scoped locking
|
||||||
|
|||||||
Reference in New Issue
Block a user