beegfs/meta/tests/TestBuddyMirroring.cpp
2025-08-10 01:34:16 +02:00

236 lines
6.7 KiB
C++

#include <common/threading/PThread.h>
#include <common/toolkit/Random.h>
#include <session/EntryLockStore.h>
#include <gtest/gtest.h>
class ParentNameLockTestThread : public PThread
{
public:
ParentNameLockTestThread(const unsigned id, EntryLockStore& entryLockStore,
const std::string& parentID, const std::string& name):
PThread("ParentNameLockTestThread" + StringTk::uintToStr(id)),
entryLockStore(entryLockStore), parentID(parentID), name(name)
{
}
void run() override
{
const unsigned maxSleepSeconds = 1;
const std::string threadName = getCurrentThreadName();
const char* logContext(threadName.c_str());
Random r;
const int sleepSec = r.getNextInRange(0, maxSleepSeconds);
LogContext(logContext).log(Log_DEBUG, "Trying to lock '" + parentID + "/" + name + "'");
ParentNameLockData* lock = entryLockStore.lock(parentID, name);
LogContext(logContext).log(Log_DEBUG, "Locked '" + parentID + "/" + name + "'");
LogContext(logContext).log(Log_DEBUG, "Sleeping for " + StringTk::intToStr(sleepSec) +
" seconds");
sleep(sleepSec);
LogContext(logContext).log(Log_DEBUG, "Trying to unlock '" + parentID + "/" + name + "'");
entryLockStore.unlock(lock);
LogContext(logContext).log(Log_DEBUG, "Unlocked '" + parentID + "/" + name + "'");
}
private:
EntryLockStore& entryLockStore;
const std::string parentID;
const std::string name;
};
class FileIDLockTestThread : public PThread
{
public:
FileIDLockTestThread(const unsigned id, EntryLockStore& entryLockStore,
const std::string& fileID) :
PThread("FileIDLockTestThread" + StringTk::uintToStr(id)), entryLockStore(entryLockStore),
fileID(fileID)
{
}
void run() override
{
const unsigned maxSleepSeconds = 1;
const std::string threadName = getCurrentThreadName();
const char* logContext(threadName.c_str());
Random r;
const int sleepSec = r.getNextInRange(0, maxSleepSeconds);
LogContext(logContext).log(Log_DEBUG, "Trying to lock '" + fileID + "'");
FileIDLockData* lock = entryLockStore.lock(fileID, true);
LogContext(logContext).log(Log_DEBUG, "Locked '" + fileID + "'");
LogContext(logContext).log(Log_DEBUG, "Sleeping for " + StringTk::intToStr(sleepSec) +
" seconds");
sleep(sleepSec);
LogContext(logContext).log(Log_DEBUG, "Trying to unlock '" + fileID + "'");
entryLockStore.unlock(lock);
LogContext(logContext).log(Log_DEBUG, "Unlocked '" + fileID + "'");
}
private:
EntryLockStore& entryLockStore;
const std::string fileID;
};
class DirIDLockTestThread : public PThread
{
public:
DirIDLockTestThread(const unsigned id, EntryLockStore& entryLockStore,
const std::string& dirID, const bool writeLock) :
PThread("DirIDLockTestThread" + StringTk::uintToStr(id)), entryLockStore(entryLockStore),
dirID(dirID), writeLock(writeLock)
{
}
void run() override
{
const unsigned maxSleepSeconds = 1;
const std::string logInfo(writeLock ? dirID + "/write" : dirID + "/read");
const std::string threadName = getCurrentThreadName();
const char* logContext(threadName.c_str());
Random r;
const int sleepSec = r.getNextInRange(0, maxSleepSeconds);
LogContext(logContext).log(Log_DEBUG, "Trying to lock '" + logInfo + "'");
FileIDLockData* lock = entryLockStore.lock(dirID, writeLock);
LogContext(logContext).log(Log_DEBUG, "Locked '" + logInfo + "'");
LogContext(logContext).log(Log_DEBUG, "Sleeping for " + StringTk::intToStr(sleepSec) +
" seconds");
sleep(sleepSec);
LogContext(logContext).log(Log_DEBUG, "Trying to unlock '" + logInfo + "'");
entryLockStore.unlock(lock);
LogContext(logContext).log(Log_DEBUG, "Unlocked '" + logInfo + "'");
}
private:
EntryLockStore& entryLockStore;
const std::string dirID;
const bool writeLock;
};
TEST(BuddyMirroring, simpleEntryLocks)
{
EntryLockStore entryLockStore;
const unsigned numThreadsEach = 15;
std::list<PThread*> threadList;
// prepare ParentNameLocks
std::string parentIDA = "PIDA";
std::string nameA = "NAMEA";
std::string parentIDB = "PIDB";
std::string nameB = "NAMEB";
unsigned i=0;
for ( ; i<numThreadsEach/2; i++)
{
ParentNameLockTestThread* t = new ParentNameLockTestThread(i, entryLockStore, parentIDA,
nameA);
threadList.push_back(t);
}
for ( ; i<numThreadsEach; i++)
{
ParentNameLockTestThread* t = new ParentNameLockTestThread(i, entryLockStore, parentIDB,
nameB);
threadList.push_back(t);
}
// prepare FileIDLocks
std::string fileIDA = "fileIDA";
std::string fileIDB = "fileIDB";
i=0;
for ( ; i<numThreadsEach/2; i++)
{
FileIDLockTestThread* t = new FileIDLockTestThread(i, entryLockStore, fileIDA);
threadList.push_back(t);
}
for ( ; i<numThreadsEach; i++)
{
FileIDLockTestThread* t = new FileIDLockTestThread(i, entryLockStore, fileIDB);
threadList.push_back(t);
}
// run all threads
for ( std::list<PThread*>::iterator iter = threadList.begin();
iter != threadList.end(); iter++ )
(*iter)->start();
for ( std::list<PThread*>::iterator iter = threadList.begin();
iter != threadList.end(); iter++ )
(*iter)->join();
for ( std::list<PThread*>::iterator iter = threadList.begin();
iter != threadList.end(); iter++ )
SAFE_DELETE(*iter);
}
TEST(BuddyMirroring, rwEntryLocks)
{
EntryLockStore entryLockStore;
const unsigned numThreadsRead = 15;
const unsigned numThreadsWrite = 5;
std::list<PThread*> threadList;
// prepare FileIDLocks for Directories
std::string dirID = "dirID";
for (unsigned i=0 ; i<numThreadsWrite; i++)
{
DirIDLockTestThread* t = new DirIDLockTestThread(i, entryLockStore, dirID, true);
threadList.push_back(t);
}
for (unsigned i=0 ; i<numThreadsRead; i++)
{
DirIDLockTestThread* t = new DirIDLockTestThread(i, entryLockStore, dirID, false);
threadList.push_back(t);
}
// run all threads
for ( std::list<PThread*>::iterator iter = threadList.begin();
iter != threadList.end(); iter++ )
(*iter)->start();
for ( std::list<PThread*>::iterator iter = threadList.begin();
iter != threadList.end(); iter++ )
(*iter)->join();
for ( std::list<PThread*>::iterator iter = threadList.begin();
iter != threadList.end(); iter++ )
SAFE_DELETE(*iter);
}