changes
This commit is contained in:
@@ -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;
|
||||||
@@ -479,4 +481,48 @@ Returns:
|
|||||||
bool DataStore::unlockDataStore()
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -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";
|
||||||
|
|||||||
Reference in New Issue
Block a user