gdle/Source/ObjectIDGen.cpp
2018-12-31 21:35:32 -06:00

213 lines
4.5 KiB
C++

#include "StdAfx.h"
#include "ObjectIDGen.h"
#include "DatabaseIO.h"
#include "Server.h"
const uint32_t IDQUEUEMAX = 250000;
const uint32_t IDQUEUEMIN = 50000;
const uint32_t IDRANGESTART = 0x80000000;
const uint32_t IDRANGEEND = 0xff000000;
const uint32_t IDEPHEMERALSTART = 0x60000000;
const uint32_t IDEPHEMERALMASK = 0x6fffffff;
CObjectIDGenerator::CObjectIDGenerator()
{
m_ephemeral = IDEPHEMERALSTART;
if (g_pConfig->UseIncrementalID())
{
WINLOG(Data, Normal, "Using Incremental ID system.....\n");
}
else
{
// Verify IDRanges tables exists and has values
if (g_pDBIO->IDRangeTableExistsAndValid())
{
WINLOG(Data, Normal, "Using ID Mined system.....\n");
}
else
{
isIdRangeValid = false;
}
}
LoadRangeStart();
LoadState();
}
CObjectIDGenerator::~CObjectIDGenerator()
{
}
void CObjectIDGenerator::LoadState()
{
if (!g_pConfig->UseIncrementalID())
{
g_pDB2->QueueAsyncQuery(
new AvailableIdQuery(
m_dwHintDynamicGUID, IDQUEUEMAX, listOfIdsForWeenies, m_lock, m_bLoadingState));
//queryInProgress = true;
//std::list<unsigned int> startupRange = g_pDBIO->GetNextIDRange(m_dwHintDynamicGUID, IDQUEUEMAX);
//m_dwHintDynamicGUID += IDQUEUEMAX;
SaveRangeStart();
//DEBUG_DATA << "New Group count:" << startupRange.size();
//for (std::list<unsigned int>::iterator it = startupRange.begin(); it != startupRange.end(); ++it)
// listOfIdsForWeenies.push(*it);
//if (listOfIdsForWeenies.empty())
// outOfIds = true;
//startupRange.clear();
//m_bLoadingState = false;
//queryInProgress = false;
}
else
m_dwHintDynamicGUID = g_pDBIO->GetHighestWeenieID(IDRANGESTART, IDRANGEEND);
}
DWORD CObjectIDGenerator::GenerateGUID(eGUIDClass type)
{
switch (type)
{
case eDynamicGUID:
{
DWORD result = 0;
if (!g_pConfig->UseIncrementalID())
{
if (outOfIds || listOfIdsForWeenies.empty())
{
SERVER_ERROR << "Dynamic GUID overflow!";
return 0;
}
{
std::scoped_lock lock(m_lock);
result = listOfIdsForWeenies.front();
listOfIdsForWeenies.pop();
}
if (!m_bLoadingState /*&& !queryInProgress*/ && listOfIdsForWeenies.size() < IDQUEUEMIN)
{
m_bLoadingState = true;
LoadState();
}
}
else
{
if (m_dwHintDynamicGUID >= IDRANGEEND)
{
SERVER_ERROR << "Dynamic GUID overflow!";
return 0;
}
result = ++m_dwHintDynamicGUID;
}
return result;
}
case eEphemeral:
{
m_ephemeral &= IDEPHEMERALMASK;
return m_ephemeral++;
}
}
return 0;
}
void CObjectIDGenerator::SaveRangeStart()
{
BinaryWriter banData;
banData.Write<DWORD>(m_dwHintDynamicGUID);
if (!g_pConfig->UseIncrementalID())
{
g_pDBIO->CreateOrUpdateGlobalData(DBIO_GLOBAL_ID_RANGE_START, banData.GetData(), banData.GetSize());
}
}
void CObjectIDGenerator::LoadRangeStart()
{
void *data = NULL;
DWORD length = 0;
if (!g_pConfig->UseIncrementalID())
{
g_pDBIO->GetGlobalData(DBIO_GLOBAL_ID_RANGE_START, &data, &length);
BinaryReader reader(data, length);
m_dwHintDynamicGUID = reader.ReadDWORD() + IDQUEUEMIN;
if (m_dwHintDynamicGUID < IDRANGESTART)
m_dwHintDynamicGUID = IDRANGESTART;
AvailableIdQuery query(m_dwHintDynamicGUID, IDQUEUEMAX, listOfIdsForWeenies, m_lock, m_bLoadingState);
query.PerformQuery((MYSQL*)g_pDB2->GetInternalConnection());
}
}
bool AvailableIdQuery::PerformQuery(MYSQL *c)
{
if (!c)
return false;
MYSQL_STMT *statement = mysql_stmt_init(c);
bool failed = false;
if (statement)
{
std::string query = "SELECT unused FROM idranges WHERE unused > ? limit 250000" ;
mysql_stmt_prepare(statement, query.c_str(), query.length());
MYSQL_BIND params = { 0 };
params.buffer = &m_start;
params.buffer_length = sizeof(uint32_t);
params.buffer_type = MYSQL_TYPE_LONG;
params.is_unsigned = true;
failed = mysql_stmt_bind_param(statement, &params);
if (!failed)
{
failed = mysql_stmt_execute(statement);
if (!failed)
{
uint32_t value = 0;
MYSQL_BIND result = { 0 };
result.buffer = &value;
result.buffer_length = sizeof(uint32_t);
result.buffer_type = MYSQL_TYPE_LONG;
result.is_unsigned = true;
failed = mysql_stmt_bind_result(statement, &result);
bool done = failed;
while (!done)
{
std::scoped_lock lock(m_lock);
for (int i = 0; i < 5000 && !failed; i++)
{
if (!(done = mysql_stmt_fetch(statement)))
{
m_queue.push(value);
m_start = value;
}
}
std::this_thread::yield();
}
}
}
mysql_stmt_close(statement);
}
m_busy = false;
if (failed)
SERVER_ERROR << "Error in AvailableIdQuery::PerformQuery: " << mysql_error(c);
return !failed;
}