beegfs/storage/source/session/SessionStore.cpp
2025-08-10 01:34:16 +02:00

302 lines
7.3 KiB
C++

#include "SessionStore.h"
#include <boost/scoped_array.hpp>
#include <mutex>
/**
* @return NULL if no such session exists
*/
std::shared_ptr<Session> SessionStore::referenceSession(NumNodeID sessionID) const
{
std::lock_guard<Mutex> const lock(mutex);
auto iter = sessions.find(sessionID);
if (iter != sessions.end())
return iter->second;
return nullptr;
}
std::shared_ptr<Session> SessionStore::referenceOrAddSession(NumNodeID sessionID)
{
std::lock_guard<Mutex> lock(mutex);
auto iter = sessions.find(sessionID);
if (iter != sessions.end())
return iter->second;
// add as new session and reference it
LogContext log("SessionStore (ref)");
log.log(Log_DEBUG, std::string("Creating a new session. SessionID: ") + sessionID.str());
auto session = std::make_shared<Session>(sessionID);
sessions[sessionID] = session;
return session;
}
/**
* @param masterList must be ordered; contained nodes will be removed and may no longer be
* accessed after calling this method.
* @return contained sessions must be cleaned up by the caller
*/
std::list<std::shared_ptr<Session>> SessionStore::syncSessions(
const std::vector<NodeHandle>& masterList)
{
std::lock_guard<Mutex> const lock(mutex);
std::list<std::shared_ptr<Session>> result;
auto sessionIter = sessions.begin();
auto masterIter = masterList.begin();
while (sessionIter != sessions.end() && masterIter != masterList.end())
{
NumNodeID currentSession = sessionIter->first;
NumNodeID currentMaster = (*masterIter)->getNumID();
if(currentMaster < currentSession)
{ // session doesn't exist locally
// note: we add sessions only on demand
masterIter++;
}
else
if(currentSession < currentMaster)
{ // session is removed
auto session = std::move(sessionIter->second);
sessionIter++; // (removal invalidates iterator)
result.push_back(std::move(session));
sessions.erase(std::prev(sessionIter));
}
else
{ // session unchanged
masterIter++;
sessionIter++;
}
}
// remaining sessions are removed
while(sessionIter != sessions.end() )
{
auto session = std::move(sessionIter->second);
sessionIter++; // (removal invalidates iterator)
result.push_back(std::move(session));
sessions.erase(std::prev(sessionIter));
}
return result;
}
/**
* @return number of sessions
*/
size_t SessionStore::getAllSessionIDs(NumNodeIDList* outSessionIDs) const
{
std::lock_guard<Mutex> const lock(mutex);
size_t retVal = sessions.size();
for (auto iter = sessions.begin(); iter != sessions.end(); iter++)
outSessionIDs->push_back(iter->first);
return retVal;
}
size_t SessionStore::getSize() const
{
std::lock_guard<Mutex> const lock(mutex);
return sessions.size();
}
void SessionStore::serializeForTarget(Serializer& ser, uint16_t targetID) const
{
ser % uint32_t(sessions.size());
for (auto it = sessions.begin(), end = sessions.end(); it != end; ++it)
{
ser % it->first;
it->second->serializeForTarget(ser, targetID);
}
LOG_DEBUG("SessionStore serialize", Log_DEBUG, "count of serialized Sessions: " +
StringTk::uintToStr(sessions.size()));
}
void SessionStore::deserializeForTarget(Deserializer& des, uint16_t targetID)
{
uint32_t elemCount;
des % elemCount;
if (unlikely(!des.good()))
return;
for(unsigned i = 0; i < elemCount; i++)
{
NumNodeID key;
des % key;
if (unlikely(!des.good()))
return;
auto session = boost::make_unique<Session>();
session->deserializeForTarget(des, targetID);
if (unlikely(!des.good()))
{
session->getLocalFiles()->deleteAllSessions();
return;
}
auto searchResult = this->sessions.find(key);
if (searchResult == this->sessions.end())
{
this->sessions.insert({key, std::move(session)});
}
else
{ // exist so local files will merged
searchResult->second->mergeSessionLocalFiles(session.get());
}
}
LOG_DEBUG("SessionStore deserialize", Log_DEBUG, "count of deserialized Sessions: " +
StringTk::uintToStr(elemCount));
}
bool SessionStore::loadFromFile(std::string filePath, uint16_t targetID)
{
LogContext log("SessionStore (load)");
log.log(Log_DEBUG,"load sessions of target: " + StringTk::uintToStr(targetID));
bool retVal = false;
boost::scoped_array<char> buf;
int readRes;
struct stat statBuf;
int retValStat;
if(!filePath.length() )
return false;
std::lock_guard<Mutex> const lock(mutex);
int fd = open(filePath.c_str(), O_RDONLY, 0);
if(fd == -1)
{ // open failed
log.log(Log_DEBUG, "Unable to open session file: " + filePath + ". " +
"SysErr: " + System::getErrString() );
goto err_unlock;
}
retValStat = fstat(fd, &statBuf);
if(retValStat)
{ // stat failed
log.log(Log_WARNING, "Unable to stat session file: " + filePath + ". " +
"SysErr: " + System::getErrString() );
goto err_stat;
}
buf.reset(new char[statBuf.st_size]);
readRes = read(fd, buf.get(), statBuf.st_size);
if(readRes <= 0)
{ // reading failed
log.log(Log_WARNING, "Unable to read session file: " + filePath + ". " +
"SysErr: " + System::getErrString() );
}
else
{ // parse contents
Deserializer des(buf.get(), readRes);
deserializeForTarget(des, targetID);
retVal = des.good();
}
if (!retVal)
log.logErr("Could not deserialize SessionStore from file: " + filePath);
err_stat:
close(fd);
err_unlock:
return retVal;
}
/**
* Note: setStorePath must be called before using this.
*/
bool SessionStore::saveToFile(std::string filePath, uint16_t targetID) const
{
LogContext log("SessionStore (save)");
log.log(Log_DEBUG,"save sessions of target: " + StringTk::uintToStr(targetID));
bool retVal = false;
boost::scoped_array<char> buf;
unsigned bufLen;
ssize_t writeRes;
if(!filePath.length() )
return false;
std::lock_guard<Mutex> const lock(mutex);
// create/trunc file
int openFlags = O_CREAT|O_TRUNC|O_WRONLY;
int fd = open(filePath.c_str(), openFlags, 0666);
if(fd == -1)
{ // error
log.logErr("Unable to create session file: " + filePath + ". " +
"SysErr: " + System::getErrString() );
goto err_unlock;
}
// file created => store data
{
Serializer lengthCalc;
serializeForTarget(lengthCalc, targetID);
bufLen = lengthCalc.size();
buf.reset(new (std::nothrow) char[bufLen]);
if (!buf)
{
LOG(SESSIONS, ERR, "Unable to allocate serializer memory", filePath);
goto err_closefile;
}
}
{
Serializer ser(buf.get(), bufLen);
serializeForTarget(ser, targetID);
if (!ser.good())
{
log.logErr("Unable to serialize session file: " + filePath + ".");
goto err_closefile;
}
}
writeRes = write(fd, buf.get(), bufLen);
if(writeRes != (ssize_t)bufLen)
{
log.logErr("Unable to store session file: " + filePath + ". " +
"SysErr: " + System::getErrString() );
goto err_closefile;
}
retVal = true;
LOG_DEBUG_CONTEXT(log, Log_DEBUG, "Session file stored: " + filePath);
// error compensation
err_closefile:
close(fd);
err_unlock:
return retVal;
}