Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDClient rework #623

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,15 @@ link_directories(${PROJECT_BINARY_DIR})
# Load all of our third party directories
add_subdirectory(thirdparty)

# Include Boost
find_package(Boost COMPONENTS interprocess)

if(Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})

target_link_libraries(dGame ${Boost_LIBRARIES})
endif()

# Glob together all headers that need to be precompiled
file(
GLOB HEADERS_DDATABASE
Expand Down
22 changes: 22 additions & 0 deletions dDatabase/CDAbstractProvider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "GeneralUtils.h"

#include "Game.h"
#include "dLogger.h"
#include "dServer.h"

#include "CDTable.h"

template <
typename KeyType,
typename MappedType
>
class CDAbstractProvider
{
public:
virtual void LoadClient() = 0;
virtual void LoadHost() = 0;

virtual const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) = 0;
};
124 changes: 124 additions & 0 deletions dDatabase/CDAbstractSharedMemoryMap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#pragma once

#include "GeneralUtils.h"

#include "Game.h"
#include "dLogger.h"
#include "dServer.h"

#include "CDTable.h"

#include "CDAbstractProvider.h"

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#include <chrono>

template <
typename KeyType,
typename MappedType
>
class CDAbstractSharedMemoryMap : public CDAbstractProvider<KeyType, 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> Map;

public:
std::map<KeyType, MappedType> m_CacheMap;

std::string m_Name;

size_t m_Size;

bool m_Host;
Map* m_HostEntries;

boost::interprocess::managed_shared_memory m_ClientSegment;
ShmemAllocator* m_ClientAllocInst;
boost::interprocess::offset_ptr<Map> m_ClientEntires;

CDAbstractSharedMemoryMap(std::string name, size_t size)
{
m_Name = name;
m_Size = size;
m_Host = false;
m_HostEntries = nullptr;
m_ClientAllocInst = nullptr;
m_ClientEntires = nullptr;

LoadClient();
}

const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
const auto& cacheIt = m_CacheMap.find(key);
if (cacheIt != m_CacheMap.end()) {
return cacheIt->second;
}

const auto& it = m_ClientEntires->find(key);
if (it == m_ClientEntires->end()) {
return defaultValue;
}

return it->second;
}

const void SetEntry(const KeyType& key, const MappedType& value) {
if (m_Host) {
// If we are already hosting, we cannot add to the map, throw an error
throw std::runtime_error("Can not add to a map that is already being hosted");
}

m_CacheMap.emplace(key, value);
}

void LoadClient() override {
try {
m_ClientSegment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, m_Name.c_str());

m_ClientAllocInst = new ShmemAllocator(m_ClientSegment.get_segment_manager());

m_ClientEntires = m_ClientSegment.find<Map>(m_Name.c_str()).first;

if (m_ClientEntires == nullptr) {
throw std::runtime_error("Could not find shared memory segment " + m_Name);
}

} catch (std::exception &e) {
// Not open
}
}

void LoadHost() override {
try {
boost::interprocess::shared_memory_object::remove(m_Name.c_str());

boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, m_Name.c_str(), m_Size);

ShmemAllocator alloc(segment.get_segment_manager());

m_HostEntries = segment.construct<Map>(m_Name.c_str()) (std::less<KeyType>(), alloc);

// Copy cache
for (const auto& pair : m_CacheMap) {
m_HostEntries->insert(std::make_pair(pair.first, pair.second));
}

m_Host = true;

LoadClient();
} catch (std::exception &e) {
// Make sure the smemory is removed
boost::interprocess::shared_memory_object::remove(m_Name.c_str());

throw e;
}
}
};
150 changes: 150 additions & 0 deletions dDatabase/CDAbstractSharedMemoryProvider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#pragma once

#include "CDAbstractProvider.h"

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#include <chrono>
#include <mutex>

template <
typename KeyType,
typename MappedType
>
class CDAbstractSharedMemoryProvider : public CDAbstractProvider<KeyType, 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> Map;

public:
std::string m_Name;
std::string m_MapName;
std::function <ValueType(CppSQLite3Query&)> m_ParseEntry;
std::function <int32_t(int32_t)> m_CalculateSize;

bool m_Cache;

std::unordered_map<KeyType, MappedType> m_CacheMap;

bool m_Host;
Map* m_HostEntries;

boost::interprocess::managed_shared_memory m_ClientSegment;
ShmemAllocator* m_ClientAllocInst;
boost::interprocess::offset_ptr<Map> m_ClientEntires;

CDAbstractSharedMemoryProvider(std::string name, std::function <ValueType(CppSQLite3Query&)> parseEntry, std::function <int32_t(int32_t)> calculateSize, bool cache)
{
m_Name = name;
m_MapName = name + "Map";
m_ParseEntry = parseEntry;
m_CalculateSize = calculateSize;
m_Cache = cache;
m_Host = false;
m_HostEntries = nullptr;

LoadClient();
}

const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
if (m_Host) {
auto it = m_HostEntries->find(key);
if (it == m_HostEntries->end())
{
return defaultValue;
}
return it->second;
}

if (m_Cache) {
auto it = m_CacheMap.find(key);
if (it != m_CacheMap.end()) {
return it->second;
}
}

const auto& it = m_ClientEntires->find(key);
if (it == m_ClientEntires->end())
{
if (m_Cache) {
m_CacheMap.emplace(key, defaultValue);
}

return defaultValue;
}

if (m_Cache) {
m_CacheMap.emplace(key, it->second);
}

return it->second;
}

void LoadClient() override {
try {
m_ClientSegment = boost::interprocess::managed_shared_memory(boost::interprocess::open_read_only, m_MapName.c_str());

m_ClientAllocInst = new ShmemAllocator(m_ClientSegment.get_segment_manager());

m_ClientEntires = m_ClientSegment.find<Map>(m_Name.c_str()).first;

if (m_ClientEntires == nullptr) {
throw std::runtime_error("Could not find shared memory segment " + m_Name);
}

} catch (boost::interprocess::interprocess_exception& e) {
// Not open
}
}

void LoadHost() override {
try {
boost::interprocess::shared_memory_object::remove(m_MapName.c_str());

auto sizeQuery = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM " + m_Name);

if (sizeQuery.eof()) {
throw std::runtime_error("Could not get size of table " + m_Name);
return;
}

int32_t size = sizeQuery.getIntField(0);

size = m_CalculateSize(size);

boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only, m_MapName.c_str(), size);

ShmemAllocator alloc_inst (segment.get_segment_manager());

m_HostEntries = segment.construct<Map>(m_Name.c_str()) (std::less<KeyType>(), alloc_inst);

auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM " + m_Name);

while (!tableData.eof()) {
ValueType entry = m_ParseEntry(tableData);

m_HostEntries->insert(entry);

tableData.nextRow();
}

tableData.finalize();

m_Host = true;

LoadClient();
} catch (std::exception &e) {
// Make sure the smemory is removed
boost::interprocess::shared_memory_object::remove(m_MapName.c_str());

throw e;
}
}
};
74 changes: 74 additions & 0 deletions dDatabase/CDAbstractSqliteProvider.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include "GeneralUtils.h"

#include "Game.h"
#include "dLogger.h"
#include "dServer.h"

#include "CDTable.h"

#include "CDAbstractProvider.h"

template <
typename KeyType,
typename MappedType
>
class CDAbstractSqliteProvider : public CDAbstractProvider<KeyType, MappedType>
{
typedef std::pair<const KeyType, MappedType> ValueType;

public:
std::string m_Name;
std::function <ValueType(CppSQLite3Query&)> m_ParseEntry;

std::unordered_map<KeyType, MappedType> m_Entries;

CDAbstractSqliteProvider(std::string name, std::function <ValueType(CppSQLite3Query&)> parseEntry, bool cache)
{
m_Name = name;
m_ParseEntry = parseEntry;

LoadClient();
}

void LoadClient() override {
// First, get the size of the table
uint32_t size = 0;
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM " + m_Name);
while (!tableSize.eof()) {
size = tableSize.getIntField(0, 0);

tableSize.nextRow();
}

tableSize.finalize();

// Reserve the size
m_Entries.reserve(size);

// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM " + m_Name);
while (!tableData.eof()) {
auto entry = m_ParseEntry(tableData);

m_Entries.insert(entry);

tableData.nextRow();
}

tableData.finalize();
}

void LoadHost() override {
return;
}

const MappedType& GetEntry(const KeyType& key, const MappedType& defaultValue) override {
auto it = m_Entries.find(key);
if (it != m_Entries.end()) {
return it->second;
}
return defaultValue;
}
};
Loading