* SPDX-License-Identifier: MulanPSL-2.0
*/
#include "util/file_lock.h"
#include "log/logging.h"
void FileLock::ReleaseFileLock(uint64_t inodeId, LockMode m)
{
std::unique_lock<std::shared_mutex> lock(mutex);
if (inodeIdTofileLockStateMap.find(inodeId) == inodeIdTofileLockStateMap.end()) {
return;
}
std::shared_ptr<std::condition_variable_any> cv = inodeIdTofileLockStateMap[inodeId].cv;
bool toNotify = false;
if (m == LockMode::S) {
if (--inodeIdTofileLockStateMap[inodeId].lockCount == 0) {
toNotify = true;
}
} else {
if (++inodeIdTofileLockStateMap[inodeId].lockCount == 0) {
toNotify = true;
}
}
if (toNotify) {
if (inodeIdTofileLockStateMap[inodeId].waitingThreads == 0) {
inodeIdTofileLockStateMap.erase(inodeId);
} else {
cv->notify_all();
}
}
}
bool FileLock::GetFileLock(uint64_t inodeId, LockMode m, bool wait) { return innerGetFileLock(inodeId, m, wait); }
bool FileLock::TryGetFileLock(uint64_t inodeId, LockMode m) { return innerGetFileLock(inodeId, m, false); }
void FileLock::WaitGetFileLock(uint64_t inodeId, LockMode m) { innerGetFileLock(inodeId, m, true); }
bool FileLock::innerGetFileLock(uint64_t inodeId, LockMode m, bool wait)
{
std::unique_lock<std::shared_mutex> lock(mutex);
int lockCnt = 0;
if (inodeIdTofileLockStateMap.count(inodeId) != 0) {
lockCnt = inodeIdTofileLockStateMap[inodeId].lockCount;
}
if (lockCnt == 0) {
if (inodeIdTofileLockStateMap[inodeId].waitingThreads == 0) {
inodeIdTofileLockStateMap[inodeId].cv = std::make_shared<std::condition_variable_any>();
}
inodeIdTofileLockStateMap[inodeId].lockCount = static_cast<int>(m);
} else if (lockCnt > 0 && m == LockMode::S) {
inodeIdTofileLockStateMap[inodeId].lockCount++;
} else if (wait) {
std::shared_ptr<std::condition_variable_any> cv = inodeIdTofileLockStateMap[inodeId].cv;
if (cv == nullptr) {
FALCON_LOG(LOG_ERROR) << "innerGetFileLock(): cv == nullptr for inode Id " << inodeId;
return false;
}
++inodeIdTofileLockStateMap[inodeId].waitingThreads;
if (m == LockMode::X) {
cv->wait(lock, [this, inodeId]() { return inodeIdTofileLockStateMap[inodeId].lockCount == 0; });
} else {
cv->wait(lock, [this, inodeId]() { return inodeIdTofileLockStateMap[inodeId].lockCount >= 0; });
}
--inodeIdTofileLockStateMap[inodeId].waitingThreads;
inodeIdTofileLockStateMap[inodeId].lockCount += static_cast<int>(m);
} else {
return false;
}
return true;
}
bool FileLock::TestLocked(uint64_t inodeId, LockMode m)
{
std::shared_lock<std::shared_mutex> lock(mutex);
if (m == LockMode::X) {
return inodeIdTofileLockStateMap.count(inodeId) != 0;
}
return inodeIdTofileLockStateMap.count(inodeId) != 0 && inodeIdTofileLockStateMap[inodeId].lockCount < 0;
}
FileLocker::FileLocker(FileLock *initFileLock, uint64_t initInodeId, LockMode initLockMode, bool wait)
{
fileLock = initFileLock;
inodeId = initInodeId;
lockMode = initLockMode;
locked = fileLock->GetFileLock(initInodeId, initLockMode, wait);
}
FileLocker::~FileLocker()
{
if (locked) {
fileLock->ReleaseFileLock(inodeId, lockMode);
}
}
bool FileLocker::isLocked() { return locked; }