Abstracted the CDClient tables

There is now an option to utilize shared memory for some CDClient tables by adding `CD_PROVIDER_MEMORY=1` to the CMakeVariables.txt file.

Allows masterconfig.ini to specify another run command for the world server, to allow for easier debugging through `valgrind`.
This commit is contained in:
wincent
2022-08-11 16:36:03 +02:00
parent 45ae46f6f1
commit 56f371216b
23 changed files with 661 additions and 328 deletions

View File

@@ -5,47 +5,27 @@
#include "dLogger.h"
#include "dServer.h"
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <functional>
#include <utility>
#include <chrono>
#include "CDProvider.h"
typedef size_t KeyType;
typedef float MappedType;
typedef std::pair<const KeyType, MappedType> ValueType;
typedef boost::interprocess::allocator<ValueType, boost::interprocess::managed_shared_memory::segment_manager> ShmemAllocator;
typedef boost::interprocess::map<KeyType, MappedType, std::less<KeyType>, ShmemAllocator> CDBehaviorParameterMap;
CDBehaviorParameterMap *table = nullptr;
boost::interprocess::managed_shared_memory segment;
ShmemAllocator* alloc_inst;
boost::interprocess::offset_ptr<CDBehaviorParameterMap> m;
CD_PROVIDER(BehaviorParameterProvider, size_t, float);
//! Constructor
CDBehaviorParameterTable::CDBehaviorParameterTable(void) {
try {
segment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, "CDBehaviorParameterTable");
NEW_CD_PROVIDER(BehaviorParameterProvider, "BehaviorParameter", [](CppSQLite3Query& query) {
size_t hash = 0;
alloc_inst = new ShmemAllocator(segment.get_segment_manager());
int32_t behaviorID = query.getIntField(0, -1);
std::string parameterID = query.getStringField(1, "");
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, parameterID);
m = segment.find<CDBehaviorParameterMap>("CDBehaviorParameter").first;
float value = query.getFloatField(2, -1.0f);
if (m == nullptr) {
Game::logger->Log("CDBehaviorParameterTable", "CDBehaviorParameter segment is nullptr!\n");
}
// Load the entire table into m_Entries
/*for (auto it = m->begin(); it != m->end(); ++it) {
m_Entries.insert(std::make_pair(it->first, it->second));
}*/
} catch (std::exception &e) {
// Not open, we are master
}
return std::make_pair(hash, value);
}, [](int32_t size) {
return 40 * 1000 * 1000;
}, false);
}
//! Destructor
@@ -62,95 +42,10 @@ float CDBehaviorParameterTable::GetEntry(const uint32_t behaviorID, const std::s
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, name);
// Search for specific parameter
try {
/*boost::interprocess::managed_shared_memory segment(boost::interprocess::open_read_only, "CDBehaviorParameterTable");
// If the segment manager is not null, then the segment exists
// Get the table from the segment
ShmemAllocator alloc_inst (segment.get_segment_manager());
boost::interprocess::offset_ptr<CDBehaviorParameterMap> m = segment.find<CDBehaviorParameterMap>("CDBehaviorParameter").first;
if (m == nullptr) {
Game::logger->Log("CDBehaviorParameterTable", "CDBehaviorParameter segment is nullptr!\n");
return defaultValue;
}*/
// Start a timer
auto start = std::chrono::high_resolution_clock::now();
auto it = m->find(hash);
bool found = it != m->end();
// End the timer
auto end = std::chrono::high_resolution_clock::now();
// Get duraction
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);
// Reset the timer
/*start = std::chrono::high_resolution_clock::now();
auto nativeIt = m_Entries.find(hash);
bool nativeFound = nativeIt != m_Entries.end();
// End the timer
end = std::chrono::high_resolution_clock::now();
// Get duraction
auto nativeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start);*/
//Game::logger->Log("CDBehaviorParameterTable", "Duration: (sm) %fms / (m) %fms -> %f\n", duration.count() / 1000000.0f, nativeDuration.count() / 1000000.0f, (double) duration.count() / (double) nativeDuration.count());
if (found) {
return it->second;
}
return defaultValue;
}
catch (std::exception &e) {
Game::logger->Log("CDBehaviorParameterTable", "Failed to find entry for behaviorID: %d, parameterID: %s\n%e\n", behaviorID, name.c_str(), e.what());
return defaultValue;
}
return BehaviorParameterProvider->GetEntry(hash, defaultValue);
}
void CDBehaviorParameterTable::CreateSharedMap()
void CDBehaviorParameterTable::LoadHost()
{
boost::interprocess::shared_memory_object::remove("CDBehaviorParameterTable");
Game::logger->Log("CDBehaviorParameterTable", "Create shared memory segment.\n");
// Create the segment, TODO: calculate size
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, "CDBehaviorParameterTable", 40 * 1000 * 1000);
ShmemAllocator alloc_inst (segment.get_segment_manager());
table = segment.construct<CDBehaviorParameterMap>("CDBehaviorParameter") (std::less<KeyType>(), alloc_inst);
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
size_t hash = 0;
while (!tableData.eof()) {
hash = 0;
int32_t behaviorID = tableData.getIntField(0, -1);
std::string parameterID = tableData.getStringField(1, "");
GeneralUtils::hash_combine(hash, behaviorID);
GeneralUtils::hash_combine(hash, parameterID);
float value = tableData.getFloatField(2, -1.0f);
table->insert(ValueType(hash, value));
tableData.nextRow();
}
tableData.finalize();
BehaviorParameterProvider->LoadHost();
}

View File

@@ -19,10 +19,8 @@ struct CDBehaviorParameter {
//! BehaviorParameter table
class CDBehaviorParameterTable : public CDTable {
private:
std::unordered_map<size_t, float> m_Entries;
public:
static void CreateSharedMap();
void LoadHost() override;
//! Constructor
CDBehaviorParameterTable(void);

View File

@@ -1,43 +1,25 @@
#include "CDBehaviorTemplateTable.h"
#include "CDProvider.h"
CDBehaviorTemplate EmptyBehaviorTemplate {0, 0, 0, 0};
CD_PROVIDER(BehaviorTemplateProvider, uint32_t, CDBehaviorTemplate);
//! Constructor
CDBehaviorTemplateTable::CDBehaviorTemplateTable(void) {
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM BehaviorTemplate");
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorTemplate");
while (!tableData.eof()) {
NEW_CD_PROVIDER(BehaviorTemplateProvider, "BehaviorTemplate", [](CppSQLite3Query& query) {
CDBehaviorTemplate entry;
entry.behaviorID = tableData.getIntField(0, -1);
entry.templateID = tableData.getIntField(1, -1);
entry.effectID = tableData.getIntField(2, -1);
auto candidateToAdd = tableData.getStringField(3, "");
auto parameter = m_EffectHandles.find(candidateToAdd);
if (parameter != m_EffectHandles.end()) {
entry.effectHandle = parameter;
} else {
entry.effectHandle = m_EffectHandles.insert(candidateToAdd).first;
}
this->entries.push_back(entry);
this->entriesMappedByBehaviorID.insert(std::make_pair(entry.behaviorID, entry));
tableData.nextRow();
}
tableData.finalize();
entry.behaviorID = query.getIntField(0, -1);
entry.templateID = query.getIntField(1, -1);
entry.effectID = query.getIntField(2, -1);
entry.effectHandle = CDTable::SetString(query.getStringField(3, ""));
return std::make_pair(entry.behaviorID, entry);
}, [](int32_t size) {
return 40 * 1000 * 1000;
}, false);
}
//! Destructor
@@ -48,30 +30,10 @@ std::string CDBehaviorTemplateTable::GetName(void) const {
return "BehaviorTemplate";
}
//! Queries the table with a custom "where" clause
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::Query(std::function<bool(CDBehaviorTemplate)> predicate) {
std::vector<CDBehaviorTemplate> data = cpplinq::from(this->entries)
>> cpplinq::where(predicate)
>> cpplinq::to_vector();
return data;
const CDBehaviorTemplate& CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) const {
return BehaviorTemplateProvider->GetEntry(behaviorID, EmptyBehaviorTemplate);
}
//! Gets all the entries in the table
std::vector<CDBehaviorTemplate> CDBehaviorTemplateTable::GetEntries(void) const {
return this->entries;
}
const CDBehaviorTemplate CDBehaviorTemplateTable::GetByBehaviorID(uint32_t behaviorID) {
auto entry = this->entriesMappedByBehaviorID.find(behaviorID);
if (entry == this->entriesMappedByBehaviorID.end()) {
CDBehaviorTemplate entryToReturn;
entryToReturn.behaviorID = 0;
entryToReturn.effectHandle = m_EffectHandles.end();
entryToReturn.effectID = 0;
return entryToReturn;
} else {
return entry->second;
}
void CDBehaviorTemplateTable::LoadHost() {
BehaviorTemplateProvider->LoadHost();
}

View File

@@ -15,17 +15,14 @@ struct CDBehaviorTemplate {
unsigned int behaviorID; //!< The Behavior ID
unsigned int templateID; //!< The Template ID (LOT)
unsigned int effectID; //!< The Effect ID attached
std::unordered_set<std::string>::iterator effectHandle; //!< The effect handle
size_t effectHandle; //!< The effect handle
};
//! BehaviorTemplate table
class CDBehaviorTemplateTable : public CDTable {
private:
std::vector<CDBehaviorTemplate> entries;
std::unordered_map<uint32_t, CDBehaviorTemplate> entriesMappedByBehaviorID;
std::unordered_set<std::string> m_EffectHandles;
public:
void LoadHost() override;
//! Constructor
CDBehaviorTemplateTable(void);
@@ -39,17 +36,5 @@ public:
*/
std::string GetName(void) const override;
//! Queries the table with a custom "where" clause
/*!
\param predicate The predicate
*/
std::vector<CDBehaviorTemplate> Query(std::function<bool(CDBehaviorTemplate)> predicate);
//! Gets all the entries in the table
/*!
\return The entries
*/
std::vector<CDBehaviorTemplate> GetEntries(void) const;
const CDBehaviorTemplate GetByBehaviorID(uint32_t behaviorID);
const CDBehaviorTemplate& GetByBehaviorID(const uint32_t behaviorID) const;
};

View File

@@ -1,58 +1,30 @@
#include "CDComponentsRegistryTable.h"
#define CDCLIENT_CACHE_ALL
#include "CDProvider.h"
CD_PROVIDER(ComponentsRegistryProvider, size_t, int32_t);
//! Constructor
CDComponentsRegistryTable::CDComponentsRegistryTable(void) {
#ifdef CDCLIENT_CACHE_ALL
// First, get the size of the table
unsigned int size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ComponentsRegistry");
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);
tableSize.nextRow();
}
tableSize.finalize();
// Reserve the size
//this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ComponentsRegistry");
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField(0, -1);
entry.component_type = tableData.getIntField(1, -1);
entry.component_id = tableData.getIntField(2, -1);
this->mappedEntries.insert_or_assign(((uint64_t) entry.component_type) << 32 | ((uint64_t) entry.id), entry.component_id);
//this->entries.push_back(entry);
/*
//Darwin's stuff:
const auto& it = this->mappedEntries.find(entry.id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(entry.component_type);
if (iter == it->second.end()) {
it->second.insert(std::make_pair(entry.component_type, entry.component_id));
}
}
else {
std::map<unsigned int, unsigned int> map;
map.insert(std::make_pair(entry.component_type, entry.component_id));
this->mappedEntries.insert(std::make_pair(entry.id, map));
}
*/
tableData.nextRow();
}
tableData.finalize();
#endif
NEW_CD_PROVIDER(ComponentsRegistryProvider, "ComponentsRegistry", [](CppSQLite3Query& query) {
size_t hash = 0;
int32_t componentID = query.getIntField(0, -1);
int32_t componentType = query.getIntField(1, -1);
hash = componentID;
hash = hash << 32;
hash |= componentType;
int32_t componentHandle = query.getIntField(2, -1);
return std::make_pair(hash, componentHandle);
}, [](int32_t size) {
return 10 * 1000 * 1000;
}, true);
}
//! Destructor
@@ -63,69 +35,15 @@ std::string CDComponentsRegistryTable::GetName(void) const {
return "ComponentsRegistry";
}
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue)
{
const auto& iter = this->mappedEntries.find(((uint64_t) componentType) << 32 | ((uint64_t) id));
if (iter == this->mappedEntries.end())
{
return defaultValue;
}
return iter->second;
/*
const auto& it = this->mappedEntries.find(id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(componentType);
if (iter != it->second.end()) {
return iter->second;
}
}
*/
#ifndef CDCLIENT_CACHE_ALL
// Now get the data
std::stringstream query;
query << "SELECT * FROM ComponentsRegistry WHERE id = " << std::to_string(id);
auto tableData = CDClientDatabase::ExecuteQuery(query.str());
while (!tableData.eof()) {
CDComponentsRegistry entry;
entry.id = tableData.getIntField(0, -1);
entry.component_type = tableData.getIntField(1, -1);
entry.component_id = tableData.getIntField(2, -1);
//this->entries.push_back(entry);
//Darwin's stuff:
const auto& it = this->mappedEntries.find(entry.id);
if (it != mappedEntries.end()) {
const auto& iter = it->second.find(entry.component_type);
if (iter == it->second.end()) {
it->second.insert(std::make_pair(entry.component_type, entry.component_id));
}
}
else {
std::map<unsigned int, unsigned int> map;
map.insert(std::make_pair(entry.component_type, entry.component_id));
this->mappedEntries.insert(std::make_pair(entry.id, map));
}
tableData.nextRow();
}
tableData.finalize();
const auto& it2 = this->mappedEntries.find(id);
if (it2 != mappedEntries.end()) {
const auto& iter = it2->second.find(componentType);
if (iter != it2->second.end()) {
return iter->second;
}
}
return defaultValue;
#endif
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, uint32_t componentType, int32_t defaultValue) {
size_t hash = 0;
hash = id;
hash = hash << 32;
hash |= componentType;
return ComponentsRegistryProvider->GetEntry(hash, defaultValue);
}
void CDComponentsRegistryTable::LoadHost() {
ComponentsRegistryProvider->LoadHost();
}

View File

@@ -23,6 +23,7 @@ private:
std::map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
public:
void LoadHost() override;
//! Constructor
CDComponentsRegistryTable(void);

View File

@@ -0,0 +1,70 @@
#include "CDTable.h"
#if defined(CD_PROVIDER_MEMORY)
#include "CDAbstractSharedMemoryMap.h"
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> my_string;
CDAbstractSharedMemoryMap<size_t, boost::interprocess::string>* CDStringMap;
void CDTable::InitalizeHost()
{
CDStringMap->LoadHost();
}
void CDTable::Initalize()
{
CDStringMap = new CDAbstractSharedMemoryMap<size_t, boost::interprocess::string>("CDStringMap", 10 * 1000 * 1000);
}
std::string CDTable::GetString(size_t handle)
{
std::string str = std::string(CDStringMap->GetEntry(handle, "").c_str());
Game::logger->Log("CDTable", "GetString: %s\n", str.c_str());
return str;
}
size_t CDTable::SetString(std::string value)
{
size_t hash = 0;
GeneralUtils::hash_combine(hash, value);
CDStringMap->SetEntry(hash, boost::interprocess::string(value.c_str()));
return hash;
}
#else
std::unordered_map<size_t, std::string> CDStringMap;
void CDTable::InitalizeHost()
{
}
void CDTable::Initalize()
{
}
std::string CDTable::GetString(size_t handle)
{
return CDStringMap[handle];
}
size_t CDTable::SetString(std::string value)
{
size_t hash = 0;
GeneralUtils::hash_combine(hash, value);
CDStringMap[hash] = value;
return hash;
}
#endif

View File

@@ -38,4 +38,27 @@ public:
\return The table name
*/
virtual std::string GetName() const = 0;
//! Loads the table into shared memory
virtual void LoadHost() {};
//! Initalizes the table services
static void Initalize();
//! Initalizes the table services as host
static void InitalizeHost();
//! Get a string from a handle
/*!
\param handle The handle to get the string from
\return The string
*/
static std::string GetString(size_t handle);
//! Set a string
/*!
\param value The string to set
\return The handle to the string
*/
static size_t SetString(std::string value);
};

View File

@@ -1,4 +1,4 @@
set(DDATABASE_TABLES_SOURCES "CDActivitiesTable.cpp"
set(DDATABASE_TABLES_SOURCES "CDTable.cpp" "CDActivitiesTable.cpp"
"CDActivityRewardsTable.cpp"
"CDAnimationsTable.cpp"
"CDBehaviorParameterTable.cpp"