Files
2022-10-26 12:25:11 +08:00

333 lines
11 KiB
C++

#include "stdafx.h"
#include "HighLoadBalancer.h"
//
#include <StreamHashKey.h>
//
#include "GameZone.h"
// @history: waverix, refactoring, changed by _NA001605_EP2_CHANGE_SKILL_BROADCASTER_
namespace nsGrid {
;
struct HLB_SequentialNode : public util::__LList<HLB_SequentialNode>
{
typedef HLB_BufferInfo::NetMsgSizeType NetMsgSizeType;
NetMsgSizeType msg_size;
// Next
// User defined message .... (with msg_size)
};
struct HLB_Buffer
{
HLB_Buffer(const DWORD input_hlb_key)
: HLBKEY(hlb_key)
, hlb_key(input_hlb_key)
{
region_header->size = 0;
util::LList::Init(&sequential_root);
}
// Integrity check (&HLBKEY == &m_HLBKey)
//
const DWORD& HLBKEY;
DWORD hlb_key;
HLB_SequentialNode sequential_root;
#pragma pack(push, 1)
WAR_MSG_HDR region_header[1];
uint8_t region_stream[HighLoadBalancer::kMaxRegionStreamSize];
//
#pragma pack(pop)
};
//==================================================================================================
// Sync Message Format (v0200)
//
// -----------------------------------------------------------------------------
// | MSG_BASE | WAR_MSG_HDR | MSGSUB_SYNC_MESSAGEs
// | HLBKEY | m_HLBKey | ulong(size) | byte stream[xxxx] ...
// -----------------------------------------------------------------------------
// MSGSUB_SYNC_MESSAGEs
// -----------------------------------------------------------------------------
// | __LListNode | Size | TypeCode |
// | prev | next | uint16_t | BYTE |
// -----------------------------------------------------------------------------
// |-> MSGSUB_(SYNC, SKILL, ...)
}; // end of namespace
//==================================================================================================
// Sequential Message Format (v0100)
//
// -----------------------------------------------------------------------------
// | WAR_MSG_HDR | NORMAL_MESSAGEs or SEQUENTIAL_STREAM
// | ulong(size) | byte stream[xxxx] ...
// -----------------------------------------------------------------------------
// NORMAL_MESSAGEs
// -----------------------------------------------------------------------------
// | Size | header | body |
// | uint16_t | MSG_BASE | .... |
// -----------------------------------------------------------------------------
// SEQUENTIAL_STREAM buffer format
// -----------------------------------------------------------------------------
// | sequential_root | ... | LinkedListNode | NetMsgSizeType | UserMessage |
// -----------------------------------------------------------------------------
//==================================================================================================
// EP2 removed
// Post Action Synchronization Message Stream Format (v0.1.0.0)
// SectorIdx | Size | MSGSUB_xxx | SectorIdx | Size | MSGSUB_xxx | ...
// 0~ | > 0 | TAG_ | BODY_ | 0~ | > 0 | TAG_ | BODY_ | ...
#ifdef BUF_ALIGN_PTR
#error "this macro should be used as local declaration only"
#endif
#define BUF_ALIGN_PTR(__size) (((__size) + ((sizeof(void*)) - 1)) & (~((sizeof(void*)) - 1)))
void HLB_BufferInfo::AppendTimeSyncMsg(MSG_BASE* const msg, const WORD msg_size)
{
HLB_SequentialNode* root = sequential_root_;
WAR_MSG_HDR::MSG_SIZE_T header_offset = region_header_->size;
; header_offset = BUF_ALIGN_PTR(header_offset);
//const uint16_t size = GetSize();
WAR_MSG_HDR::MSG_SIZE_T next_offset = header_offset + sizeof(*root) + msg_size;
//
if (next_offset >= HighLoadBalancer::kMaxRegionStreamSize)
{
HighLoadBalancer::Instance()->Update(game_field_, true);
// recalculate
header_offset = region_header_->size;
header_offset = BUF_ALIGN_PTR(header_offset);
next_offset = header_offset + sizeof(*root) + msg_size;
};
//
HLB_SequentialNode* const dest = reinterpret_cast<HLB_SequentialNode*>(
reinterpret_cast<uint8_t*>(region_header_ + 1) + header_offset);
;{
util::LList::Init(dest);
dest->msg_size = msg_size;
};
;{
CopyMemory((dest + 1), msg, msg_size);
};
;{
region_header_->size = next_offset;
//
util::LList::AddPrev(dest, root);
};
}
void HLB_BufferInfo::AppendTimeSyncMsgArray(const DWORD number_of_messages,
BYTE** const IN message_array, WORD* const message_size_array)
{
WAR_MSG_HDR::MSG_SIZE_T total_size = 0;
if (DWORD loop = number_of_messages)
{
NetMsgSizeType* size_it = message_size_array;
while (loop--) {
total_size += *size_it++;
}
};
BOOST_STATIC_ASSERT(static_cast<NetMsgSizeType>(-1) > static_cast<NetMsgSizeType>(0) &&
static_cast<NetMsgSizeType>(-1) == USHRT_MAX);
if (total_size == 0 || total_size > USHRT_MAX) {
return;
}
//-----------------------------------------------
HLB_SequentialNode* root = sequential_root_;
WAR_MSG_HDR::MSG_SIZE_T header_offset = region_header_->size;
; header_offset = BUF_ALIGN_PTR(header_offset);
//const uint16_t size = GetSize();
WAR_MSG_HDR::MSG_SIZE_T next_offset = header_offset + sizeof(*root) + total_size;
//
if (next_offset >= HighLoadBalancer::kMaxRegionStreamSize)
{
HighLoadBalancer::Instance()->Update(game_field_, true);
// recalculate
header_offset = region_header_->size;
header_offset = BUF_ALIGN_PTR(header_offset);
next_offset = header_offset + sizeof(*root) + total_size;
};
//
HLB_SequentialNode* const dest = reinterpret_cast<HLB_SequentialNode*>(
reinterpret_cast<uint8_t*>(region_header_ + 1) + header_offset);
;{
util::LList::Init(dest);
dest->msg_size = static_cast<NetMsgSizeType>(total_size);
};
if (DWORD loop = number_of_messages)
{
uint8_t* msg_it = reinterpret_cast<uint8_t*>(dest + 1);
NetMsgSizeType* input_size_it = message_size_array;
uint8_t** input_msg_it = message_array;
while (loop--) {
CopyMemory(msg_it, *input_msg_it++, *input_size_it);
msg_it += *input_size_it++;
}
};
;{
region_header_->size = next_offset;
//
util::LList::AddPrev(dest, root);
};
}
//==================================================================================================
// HighLoadBalancer
//
HighLoadBalancer* HighLoadBalancer::instance_static_ = 0;
void HighLoadBalancer::CreateInstance()
{
if (instance_static_ == NULL) {
instance_static_ = new HighLoadBalancer;
};
}
void HighLoadBalancer::DestroyInstance()
{
SAFE_DELETE(instance_static_);
}
//--------------------------------------------------------------------------------------------------
HighLoadBalancer::~HighLoadBalancer()
{
FOREACH_CONTAINER(MSG_STREAM_BUFFER_POOLLIST::value_type& pool_node, msg_buffer_pool_,
MSG_STREAM_BUFFER_POOLLIST)
{
nsGrid::HLB_Buffer* hlb_buffer = pool_node;
TAllocFree(hlb_buffer);
}
FOREACH_CONTAINER(MSG_STREAM_BUFFER_INDEXER::value_type& index_node, msg_buffer_indexer_,
MSG_STREAM_BUFFER_INDEXER)
{
nsGrid::HLB_Buffer* hlb_buffer = index_node.second;
if (hlb_buffer) {
TAllocFree(hlb_buffer);
}
}
}
//--------------------------------------------------------------------------------------------------
void
HighLoadBalancer::RegisterBuffer(GameField* const game_field)
{
const ulong hash_key = util::StreamHashKey::GetMemoryHashKey(&game_field, sizeof(game_field));
HLB_Buffer*& hlb_buffer = msg_buffer_indexer_[hash_key]; // reference
if (hlb_buffer != NULL) {
return;
};
const bool is_pool_empty = msg_buffer_pool_.empty();
hlb_buffer = is_pool_empty ? (HLB_Buffer*)TAllocMalloc(sizeof(*hlb_buffer))
: msg_buffer_pool_.front();
new (hlb_buffer) HLB_Buffer(hash_key);
HLB_BufferInfo*& field_hlb_buffer = game_field->m_pHLB; // reference
if (field_hlb_buffer == NULL) {
field_hlb_buffer = TAllocNew(HLB_BufferInfo);
}
;{
field_hlb_buffer->game_field_ = game_field;
field_hlb_buffer->region_header_ = hlb_buffer->region_header;
field_hlb_buffer->sequential_root_ = &hlb_buffer->sequential_root;
};
if (is_pool_empty == false) {
msg_buffer_pool_.pop_front();
}
}
//--------------------------------------------------------------------------------------------------
void
HighLoadBalancer::UnRegisterBuffer(GameField* const game_field)
{
const ulong hash_key = util::StreamHashKey::GetMemoryHashKey(&game_field, sizeof(game_field));
MSG_STREAM_BUFFER_INDEXER::iterator it = msg_buffer_indexer_.find(hash_key);
if (it == msg_buffer_indexer_.end())
{ // game_field->m_pSyncStreamRoot은 여기서만 제어하는 것을 전제한다. 따라서 그냥 0설정
game_field->m_pHLB = NULL;
return;
}
// found
HLB_BufferInfo*& field_hlb_buffer = game_field->m_pHLB;
if (field_hlb_buffer) {
TAllocDelete(HLB_BufferInfo, field_hlb_buffer);
}
field_hlb_buffer = 0;
// 남겨진 정보 보낼까도 생각해 봤지만, 필드가 종료되는 시점이다...
// 유저가 있을 리 없잖아? 아니 없어야 한다.
// (부연) - 더 이상 의미 없는 정보일 가능성이 높다.
;{
HLB_Buffer* const hlb_buffer = it->second;
msg_buffer_indexer_.erase(it);
msg_buffer_pool_.push_back(hlb_buffer);
};
}
//--------------------------------------------------------------------------------------------------
void
HighLoadBalancer::RecyclingBuffer(GameField* const pGameField)
{
HLB_BufferInfo* const hlb_buffer = pGameField->m_pHLB;
if (hlb_buffer)
{
hlb_buffer->region_header_->size = 0;
util::LList::Init(hlb_buffer->sequential_root_);
}
}
void HighLoadBalancer::Update(GameField* const game_field, const BOOLEAN need_flush)
{
__UNUSED(need_flush);
HLB_BufferInfo* const hlb_buffer = game_field->m_pHLB;
if (hlb_buffer == NULL) {
return;
}
WAR_MSG_HDR* const region_header = hlb_buffer->region_header_;
//const BOOLEAN need_flush_internal
// = need_flush ? true
// : (kMaxRegionStreamAlarmSize < region_header->size);
//if (need_flush_internal == false) {
// return;
//}
//
// #1: send time sync buffer
HLB_SequentialNode* const sequential_root = hlb_buffer->sequential_root_;
HLB_SequentialNode* seq_it = static_cast<HLB_SequentialNode*>(sequential_root->next);
for ( ; seq_it != sequential_root; seq_it = static_cast<HLB_SequentialNode*>(seq_it->next))
{
g_pGameServer->SendToServer(AGENT_SERVER,
reinterpret_cast<MSG_BASE*>(seq_it + 1), seq_it->msg_size);
};
// #2: notify region events
game_field->SectorGridRef.Update(game_field);
//
;{ // clear
region_header->size = 0;
util::LList::Init(sequential_root);
};
return;
}
//==================================================================================================
//==================================================================================================
//==================================================================================================