529 lines
15 KiB
C++
529 lines
15 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef RY_PDS_LIB_H
|
|
#define RY_PDS_LIB_H
|
|
|
|
/*
|
|
* Includes
|
|
*/
|
|
#include "pd_utils.h"
|
|
//#include "pd_string_manager.h"
|
|
#include "pd_messages.h"
|
|
|
|
#include "nel/misc/variable.h"
|
|
#include "nel/net/message.h"
|
|
#include "nel/net/unified_network.h"
|
|
|
|
namespace RY_PDS
|
|
{
|
|
|
|
extern NLMISC::CVariable<bool> PDEnableLog;
|
|
//extern NLMISC::CVariable<bool> PDEnableStringLog;
|
|
|
|
/**
|
|
* Interface library to the Persistant Data Service (PDS)
|
|
* This lib is intended to make the link between game server and data server.
|
|
* All methods are for internal use, you should always use generated API to
|
|
* handle Persistant Data System.
|
|
* \author Benjamin Legros
|
|
* \author Nevrax France
|
|
* \date 2004
|
|
*/
|
|
class CPDSLib
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
CPDSLib();
|
|
|
|
|
|
|
|
/**
|
|
* Tells lib PDS is to be used.
|
|
* Transitionnal method to be called at service startup, as long as PDS
|
|
* is not definitely used.
|
|
*/
|
|
void usePDS();
|
|
|
|
/**
|
|
* Tells if PDS is used
|
|
*/
|
|
bool PDSUsed() const { return _UsePDS; }
|
|
|
|
|
|
|
|
/// \name Internal interface
|
|
// @{
|
|
|
|
/**
|
|
* Those function should not be called directly.
|
|
* To create, load, delete or any object manipulation, YOU must
|
|
* refer to the generated API.
|
|
*/
|
|
|
|
/**
|
|
* Tells if PDS is ready
|
|
*/
|
|
bool PDSReady();
|
|
|
|
/**
|
|
* The String Manager embedded in CPDS lib
|
|
*/
|
|
// CPDStringManager& getStringManager() { return _StringManager; }
|
|
|
|
/**
|
|
* Update
|
|
* Call regularly this method once a tick to apply changes to database
|
|
*/
|
|
void update();
|
|
|
|
/**
|
|
* Get Message Queue Size
|
|
*/
|
|
uint getMessageQueueSize();
|
|
|
|
/**
|
|
* Map Class Name
|
|
*/
|
|
TTableIndex mapClassName(const std::string& name);
|
|
|
|
/**
|
|
* Map Class Name
|
|
*/
|
|
std::string mapClassId(TTableIndex table);
|
|
|
|
/**
|
|
* Get Class Name
|
|
*/
|
|
std::string getClassName(const IPDBaseData* obj)
|
|
{
|
|
return mapClassId(obj->getTable());
|
|
}
|
|
|
|
/**
|
|
* Register Class Mapping
|
|
*/
|
|
void registerClassMapping(TTableIndex table, const std::string& name);
|
|
|
|
/**
|
|
* Internal type checking
|
|
*/
|
|
static void checkInternalTypes();
|
|
|
|
/// Init PDS lib, client side only
|
|
void init(const std::string &xml, uint32 overrideDbId = 0);
|
|
|
|
/// Init PDS log
|
|
void initLog(uint logmsg);
|
|
|
|
/// Init PDS log parameter
|
|
void initLogParam(uint logmsg, uint logparam, uint byteSize);
|
|
|
|
/// Connect service to PDS when up
|
|
void connect();
|
|
|
|
/// Disconnect service to PDS
|
|
void disconnect();
|
|
|
|
/// Release PDSLib
|
|
void release();
|
|
|
|
/// PDS is ready
|
|
void ready(uint32 lastUpdateId);
|
|
|
|
/// Register a class with its factory and its fetch
|
|
void registerClass(TTableIndex table, TPDFactory factory, TPDFetch fetch, TPDFetchFailure fetchFailure)
|
|
{
|
|
if (_Factories.size() <= table)
|
|
_Factories.resize(table+1, NULL);
|
|
if (_Fetchs.size() <= table)
|
|
_Fetchs.resize(table+1, NULL);
|
|
if (_FetchFailures.size() <= table)
|
|
_FetchFailures.resize(table+1, NULL);
|
|
|
|
_Factories[table] = factory;
|
|
_Fetchs[table] = fetch;
|
|
_FetchFailures[table] = fetchFailure;
|
|
}
|
|
|
|
/// Set index allocator
|
|
void setIndexAllocator(TTableIndex table, CIndexAllocator& alloc)
|
|
{
|
|
if (_Allocators.size() <= table)
|
|
_Allocators.resize(table+1, NULL);
|
|
|
|
_Allocators[table] = &alloc;
|
|
}
|
|
|
|
|
|
/// Allocate a row in the PDS (key is provided for table that are keymapped
|
|
void allocateRow(TTableIndex table, TRowIndex row, uint64 key);
|
|
|
|
/// Deallocate a row in the PDS
|
|
void deallocateRow(TTableIndex table, TRowIndex row);
|
|
|
|
/// Allocate a row in the PDS (key is provided for table that are keymapped
|
|
void allocateRow(TTableIndex table, TRowIndex row, uint64 key, const NLMISC::CEntityId& id);
|
|
|
|
/// Deallocate a row in the PDS
|
|
void deallocateRow(TTableIndex table, TRowIndex row, const NLMISC::CEntityId& id);
|
|
|
|
/// Create an object of a given type
|
|
IPDBaseData* create(TTableIndex table);
|
|
|
|
/// Create an object from a given class name, assuming it is mapped
|
|
IPDBaseData* create(const std::string& name)
|
|
{
|
|
TTableIndex table = mapClassName(name);
|
|
return (table == INVALID_TABLE_INDEX) ? NULL : create(table);
|
|
}
|
|
|
|
/// Release a row
|
|
void release(TTableIndex table, TRowIndex row);
|
|
|
|
/// Erase an object from its table and key
|
|
void erase(TTableIndex table, uint64 key);
|
|
|
|
/// Load a row and its dependent rows from a mapped table
|
|
void load(TTableIndex table, uint64 key);
|
|
|
|
/// Add a string in pds
|
|
void addString(const NLMISC::CEntityId& eid, const ucstring& str);
|
|
|
|
/// Unmap a string in pds
|
|
void unmapString(const NLMISC::CEntityId& eid);
|
|
|
|
|
|
/// \name Set methods
|
|
// @{
|
|
|
|
template<typename T>
|
|
void set(TTableIndex table, TRowIndex row, TColumnIndex column, const T& value)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s index=%u:%u, column=%u, value='%s'", "set", table, row, column, pdsToString(value).c_str());
|
|
|
|
CDbMessage& msg = nextMessage((uint8)table, row);
|
|
msg.updateValue(column, value);
|
|
}
|
|
|
|
template<typename T>
|
|
void set(TTableIndex table, TRowIndex row, TColumnIndex column, const T& value, const NLMISC::CEntityId& objectId)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s index=%u:%u, column=%u, value='%s' %s", "set", table, row, column, pdsToString(value).c_str(), objectId.toString().c_str());
|
|
|
|
CDbMessage& msg = nextMessage((uint8)table, row);
|
|
msg.updateValue(column, value, objectId);
|
|
}
|
|
|
|
void setParent(TTableIndex table, TRowIndex row, TColumnIndex column, const CObjectIndex& parent)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s index=%u:%u, column=%u, value='%s'", "setParent", table, row, column, parent.toString().c_str());
|
|
|
|
CDbMessage& msg = nextMessage((uint8)table, row);
|
|
msg.setParent(column, parent);
|
|
}
|
|
|
|
void setParent(TTableIndex table, TRowIndex row, TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s index=%u:%u, column=%u, value='%s' %s", "setParent", table, row, column, parent.toString().c_str(), objectId.toString().c_str());
|
|
|
|
CDbMessage& msg = nextMessage((uint8)table, row);
|
|
msg.setParent(column, parent, objectId);
|
|
}
|
|
|
|
void setParent(TTableIndex table, TRowIndex row, TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s index=%u:%u, column=%u, value='%s' newParent=%s previousParent=%s", "setParent", table, row, column, parent.toString().c_str(), newParentId.toString().c_str(), previousParentId.toString().c_str());
|
|
|
|
CDbMessage& msg = nextMessage((uint8)table, row);
|
|
msg.setParent(column, parent, newParentId, previousParentId);
|
|
}
|
|
|
|
void setParent(TTableIndex table, TRowIndex row, TColumnIndex column, const CObjectIndex& parent, const NLMISC::CEntityId& objectId, const NLMISC::CEntityId& newParentId, const NLMISC::CEntityId& previousParentId)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s index=%u:%u, column=%u, value='%s' %s newParent=%s previousParent=%s", "setParent", table, row, column, parent.toString().c_str(), objectId.toString().c_str(), newParentId.toString().c_str(), previousParentId.toString().c_str());
|
|
|
|
CDbMessage& msg = nextMessage((uint8)table, row);
|
|
msg.setParent(column, parent, objectId, newParentId, previousParentId);
|
|
}
|
|
|
|
// @}
|
|
|
|
/// \name LogPush methods
|
|
// @{
|
|
|
|
/// Log
|
|
void log(uint logId)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s %d", "log", logId);
|
|
|
|
nlassert(logId < _LogDescs.size());
|
|
CLogDesc& desc = _LogDescs[logId];
|
|
|
|
_CurrentLogMessage = logId;
|
|
_CurrentLogParam = 0;
|
|
CDbMessage& msg = nextMessage();
|
|
msg.log(logId, desc.ByteSize);
|
|
}
|
|
|
|
/// Start log context
|
|
void pushContext()
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s", "pushContext");
|
|
|
|
CDbMessage& msg = nextMessage();
|
|
msg.pushContext();
|
|
}
|
|
|
|
/// Stop log context
|
|
void popContext()
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s", "popContext");
|
|
|
|
CDbMessage& msg = nextMessage();
|
|
msg.popContext();
|
|
}
|
|
|
|
/// Push a parameter for the log
|
|
template<typename T>
|
|
void logPush(const T& value)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s value='%s'", "push", pdsToString(value).c_str());
|
|
|
|
nlassert(_CurrentLogMessage < _LogDescs.size());
|
|
CLogDesc& desc = _LogDescs[_CurrentLogMessage];
|
|
CLogParam& param = desc.Params[_CurrentLogParam++];
|
|
|
|
CDbMessage& msg = currentMessage();
|
|
nlassert(msg.getType() == CDbMessage::Log);
|
|
nlassert(sizeof(value) == param.ByteSize);
|
|
msg.pushParameter(param.ByteOffset, value);
|
|
|
|
}
|
|
|
|
/// Push a string parameter for the log
|
|
void logPush(const std::string& value)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s value='%s'", "push", pdsToString(value).c_str());
|
|
|
|
nlassert(_CurrentLogMessage < _LogDescs.size());
|
|
CLogDesc& desc = _LogDescs[_CurrentLogMessage];
|
|
CLogParam& param = desc.Params[_CurrentLogParam++];
|
|
|
|
CDbMessage& msg = currentMessage();
|
|
nlassert(msg.getType() == CDbMessage::Log);
|
|
nlassert(sizeof(uint16) == param.ByteSize);
|
|
msg.pushParameter(param.ByteOffset, value);
|
|
}
|
|
|
|
// @}
|
|
|
|
/// \name LogChat methods
|
|
// @{
|
|
|
|
/// Log Chat sentence
|
|
void logChat(const ucstring& sentence, const NLMISC::CEntityId& sender, const std::vector<NLMISC::CEntityId>& receivers)
|
|
{
|
|
if (PDVerbose)
|
|
nlinfo("CPDSLib: %12s", "popContext");
|
|
|
|
CDbMessage& msg = nextMessage();
|
|
msg.logChat(sentence, sender, receivers);
|
|
}
|
|
|
|
// @}
|
|
|
|
|
|
/// Fetch data
|
|
void fetchPDSData(NLMISC::IStream &f);
|
|
|
|
/// Notify client of fetch failure
|
|
void notifyFetchFailure(NLMISC::IStream &f);
|
|
|
|
/// Setup index allocators
|
|
void setupIndexAllocators(NLMISC::IStream &f);
|
|
|
|
/// Init object row index
|
|
void setRowIndex(TRowIndex row, IPDBaseData* obj) { obj->__BaseRow = row; }
|
|
|
|
/// Flush acknowledged messages
|
|
void flushAcknowledged(const std::vector<uint32>& ack);
|
|
|
|
/// Flush acknowledged messages until message
|
|
void flushAcknowledged(uint32 ack);
|
|
|
|
|
|
/// Init String Manager
|
|
// void initStringManager() { _StringManagerInitialised = true; }
|
|
/// Init String Manager
|
|
void initAllocs() { _AllocsInitialised = true; }
|
|
/// Init String Manager
|
|
// bool stringManagerInitialised() const { return _StringManagerInitialised; }
|
|
/// Init String Manager
|
|
bool allocsInitialised() const { return _AllocsInitialised; }
|
|
|
|
|
|
static CPDSLib* getLib(uint32 libId) { return (_Libs.size() <= libId) ? NULL : _Libs[libId]; }
|
|
|
|
static std::vector<CPDSLib*> _Libs;
|
|
|
|
/// Get Database Id
|
|
uint32 getDatabaseId() const { return _DatabaseId; }
|
|
|
|
/// Get Database Root directory. If wantRemoteDir is true, only a relative path will be returned if PDRootDirectory is empty.
|
|
static std::string getPDSRootDirectory(const std::string& shard = "", bool wantRemoteDir=false);
|
|
|
|
/// Get Database Root directory. If wantRemoteDir is true, only a relative path will be returned if PDRootDirectory is empty.
|
|
static std::string getRootDirectory(uint databaseId, const std::string& shard = "", bool wantRemoteDir=false);
|
|
|
|
/// Get Logging directory
|
|
static std::string getLogDirectory(uint databaseId, const std::string& shard = "");
|
|
|
|
/// Get Lib Logging directory
|
|
// std::string getLogDirectory(const std::string& shard = "") const;
|
|
|
|
/// Get Logging directory for remote access through BS interface
|
|
static std::string getRemoteLogDirectory(uint databaseId, const std::string& shard = "");
|
|
|
|
// /// Get Lib Logging directory for remote access through BS interface
|
|
std::string getRemoteLogDirectory(const std::string& shard = "") const;
|
|
|
|
/// Get Number of Enqueued Messages
|
|
uint32 enqueuedMessages() const { return _DbMessageQueue.getNumMessagesEnqueued(); }
|
|
|
|
|
|
|
|
/// Get Xml Description
|
|
const std::string& getXmlDescription() const { return _XmlDescription; }
|
|
|
|
private:
|
|
|
|
std::vector<TPDFactory> _Factories;
|
|
std::vector<TPDFetch> _Fetchs;
|
|
std::vector<TPDFetchFailure> _FetchFailures;
|
|
std::vector<CIndexAllocator*> _Allocators;
|
|
// CPDStringManager _StringManager;
|
|
|
|
std::string _XmlDescription;
|
|
|
|
bool _PDSConnected;
|
|
bool _PDSReady;
|
|
|
|
typedef std::pair<uint32, NLNET::CMessage*> TQueuedMessage;
|
|
typedef std::deque<TQueuedMessage> TQueuedMessages;
|
|
|
|
class CQueuedMessagePred
|
|
{
|
|
public:
|
|
|
|
bool operator () (const TQueuedMessage& a, const TQueuedMessage& b) const
|
|
{
|
|
return a.first < b.first;
|
|
}
|
|
|
|
};
|
|
|
|
TQueuedMessages _QueuedMessages;
|
|
CDbMessageSplitQueue _DbMessageQueue;
|
|
std::vector<CUpdateLog> _UpdateLogs;
|
|
|
|
uint32 _DatabaseId;
|
|
|
|
uint32 _UpdateId;
|
|
|
|
|
|
bool _UsePDS;
|
|
NLMISC::TTime _PreviousLogSave;
|
|
CTimestamp _LogStartDate;
|
|
CTimestamp _PreviousTickDate;
|
|
|
|
|
|
bool _AllocsInitialised;
|
|
// bool _StringManagerInitialised;
|
|
|
|
struct CLogParam
|
|
{
|
|
uint ByteOffset;
|
|
uint ByteSize;
|
|
};
|
|
|
|
class CLogDesc
|
|
{
|
|
public:
|
|
|
|
CLogDesc() : Log(0xffffffff), ByteSize(0) { }
|
|
|
|
uint Log;
|
|
uint ByteSize;
|
|
std::vector<CLogParam> Params;
|
|
|
|
};
|
|
|
|
uint _CurrentLogMessage;
|
|
uint _CurrentLogParam;
|
|
|
|
std::map<std::string, TTableIndex> _ClassMapName;
|
|
std::vector<std::string> _ClassMapId;
|
|
|
|
/// Logs Descriptions
|
|
std::vector<CLogDesc> _LogDescs;
|
|
|
|
/// Fake message to be used if log is not enabled
|
|
CDbMessage _FakeMessage;
|
|
|
|
/// Get next message
|
|
CDbMessage& nextMessage()
|
|
{
|
|
return PDEnableLog ? _DbMessageQueue.nextMessage() : _FakeMessage;
|
|
}
|
|
CDbMessage& nextMessage(uint8 table, uint32 row)
|
|
{
|
|
return PDEnableLog ? _DbMessageQueue.nextMessage(table, row) : _FakeMessage;
|
|
}
|
|
|
|
/// Get Current message
|
|
CDbMessage& currentMessage() { return _DbMessageQueue.currentMessage(); }
|
|
|
|
/// PDS up callback
|
|
static void onPDSUp(const std::string &serviceName, NLNET::TServiceId sid, void *arg);
|
|
|
|
/// PDS down callback
|
|
static void onPDSDown(const std::string &serviceName, NLNET::TServiceId sid, void *arg);
|
|
};
|
|
|
|
|
|
}; // RY_PDS
|
|
|
|
#endif //RY_PDS_LIB_H
|
|
|
|
|
|
|