This commit is contained in:
2026-06-11 16:39:47 +05:30
parent 7454c5a75f
commit dc5da0a7b7
4 changed files with 138 additions and 2 deletions
@@ -11,6 +11,7 @@ Date: 19-May-2026
#include "DataStore.h" #include "DataStore.h"
#include "Config.h" #include "Config.h"
#include "SerializedRecords.h" #include "SerializedRecords.h"
#include "FileHelper.h"
DataStore::DataStore() : DataStore::DataStore() :
m_globalMutex(NULL) {} m_globalMutex(NULL) {}
@@ -37,6 +38,7 @@ bool DataStore::initialize()
{ {
return false; return false;
} }
util::ensureDirectoryExists(config::file::DIRECTORY);
m_users.fileName = config::file::USER_FILE; m_users.fileName = config::file::USER_FILE;
m_users.recordSize = sizeof(SerializedUser); m_users.recordSize = sizeof(SerializedUser);
m_notifications.fileName = config::file::NOTIFICATION_FILE; m_notifications.fileName = config::file::NOTIFICATION_FILE;
@@ -480,3 +482,47 @@ bool DataStore::unlockDataStore()
{ {
return false; return false;
} }
/*
Function: lockDataStore
Description: Acquires the datastore mutex, providing
exclusive access to the shared-memory
datastore. This function blocks until
the mutex becomes available or an error
occurs.
Parameter: None
Return type:
bool
- true : Mutex successfully acquired.
- false : Failed to acquire the mutex.
*/
bool DataStore::lockDataStore()
{
if (m_globalMutex == NULL)
{
return false;
}
DWORD result = WaitForSingleObject(m_globalMutex, INFINITE);
return result == WAIT_OBJECT_0;
}
/*
Function: unlockDataStore
Description: Releases the datastore mutex after a
successful call to lockDataStore(),
allowing other processes to access the
shared-memory datastore.
Parameter: None
Return type:
bool
- true : Mutex successfully released.
- false : Failed to release the mutex.
*/
bool DataStore::unlockDataStore()
{
if (m_globalMutex == NULL)
{
return false;
}
return ReleaseMutex(m_globalMutex) != 0;
}
@@ -79,3 +79,93 @@ private:
template<typename TObject, typename TSerialized> template<typename TObject, typename TSerialized>
void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records); void saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records);
}; };
/*
Function: loadRecords
Description: Loads all serialized records from the specified
shared-memory mapping, deserializes them into
application objects, and returns them as a map
of tracked records. Each loaded record is marked
as CLEAN and assigned its corresponding slot index
within the mapping so that future modifications
can be written back efficiently.
Parameter:
- mapping: Reference to the mapping containing the
serialized records.
Return type:
util::Map<std::string, TrackedRecord<TObject>>
A map containing all loaded records keyed by
their unique identifier.
*/
template<typename TObject, typename TSerialized>
util::Map<std::string, TrackedRecord<TObject>> DataStore::loadRecords(MappingInfo& mapping)
{
util::Map<std::string, TrackedRecord<TObject>> records;
SharedMemory::ensureLatestMapping(mapping);
size_t recordCount = SharedMemory::getRecordCount(mapping);
for (size_t index = 0; index < recordCount; ++index)
{
TSerialized* serialized = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping,index));
TObject* object = TObject::deserialize(*serialized);
TrackedRecord<TObject> trackedRecord;
trackedRecord.data = object;
trackedRecord.state = RecordState::CLEAN;
trackedRecord.slotIndex = index;
records.insert(object->getId(), trackedRecord);
}
return records;
}
/*
Function: saveRecords
Description: Persists all modified and newly added records
contained in the provided map to the specified
shared-memory mapping. Modified records overwrite
their existing slots, while new records are
appended to the end of the mapping. Records marked
as CLEAN are ignored. After persistence, all
temporary objects owned by the tracked records are
destroyed to release memory.
Parameter:
- mapping: Reference to the mapping where records are
stored.
- records: Map containing the records to be persisted.
Return type: void
*/
template<typename TObject, typename TSerialized> void DataStore::saveRecords(MappingInfo& mapping, util::Map<std::string, TrackedRecord<TObject>>& records)
{
SharedMemory::ensureLatestMapping(mapping);
for (int index = 0; index < records.getSize(); ++index)
{
TrackedRecord<TObject>& record = records.getValueAt(index);
if (record.state == RecordState::CLEAN)
{
continue;
}
TSerialized serialized = record.data->serialize();
if (record.state == RecordState::MODIFIED)
{
TSerialized* destination = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping, record.slotIndex));
if (destination)
{
*destination = serialized;
}
}
else if (record.state == RecordState::NEW_RECORD)
{
if (!SharedMemory::ensureCapacityForInsert(mapping))
{
continue;
}
size_t recordCount = SharedMemory::getRecordCount(mapping);
TSerialized* destination = static_cast<TSerialized*>(SharedMemory::getRecordAddress(mapping, recordCount));
*destination = serialized;
SharedMemory::setRecordCount(mapping, recordCount + 1);
}
}
for (int index = 0; index < records.getSize(); ++index)
{
delete records.getValueAt(index).data;
records.getValueAt(index).data = nullptr;
}
}
@@ -4,6 +4,5 @@ enum class RecordState : int
{ {
CLEAN, CLEAN,
NEW_RECORD, NEW_RECORD,
MODIFIED, MODIFIED
DELETED
}; };
@@ -29,6 +29,7 @@ namespace config
namespace file namespace file
{ {
const size_t INITIAL_CAPACITY = 100; const size_t INITIAL_CAPACITY = 100;
constexpr const char* DIRECTORY = "files/";
constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat"; constexpr const char* INVENTORYITEM_FILE = "files/InventoryItem.dat";
constexpr const char* USER_FILE = "files/User.dat"; constexpr const char* USER_FILE = "files/User.dat";
constexpr const char* NOTIFICATION_FILE = "files/Notification.dat"; constexpr const char* NOTIFICATION_FILE = "files/Notification.dat";