#ifndef _RYL_DBAGENT_DB_DATA_MGR_H_ #define _RYL_DBAGENT_DB_DATA_MGR_H_ #include #include #include #include #include #include #include #include "SessionData.h" //forward decl. class CDBComponent; namespace DBAgent { namespace DataStorage { // forward decl. class CSessionData; enum DBDataError { DATA_SUCCEEDED = 0, //! ¼º°ø DATA_SERVER_ERROR = 1, //! ¸Þ¸ð¸® ÇÒ´ç ¿À·ù, ¸Ê »ðÀÔ ¿À·ù µî DATA_ALREADY_LOGIN_ERROR = 2, //! ÀÌ¹Ì ·Î±×ÀÎ ÇØ ÀÖÀ½ DATA_ALREADY_LOGOUT_ERROR = 3, //! ÀÌ¹Ì ·Î±×¾Æ¿ô ÇØ ÀÖÀ½ MAX_DATA_ERROR = 4 }; extern const char* g_szDBDataErrorString[MAX_DATA_ERROR]; template > class CDBDataMgr { public: typedef typename Key KeyType; typedef typename Data DataType; enum Const { MAX_MANAGER_NAME = 32 }; // ù¹øÂ° ÀÎÀÚ´Â °ü¸®ÇÒ ´ë»ó // µÎ¹øÂ° ÀÎÀÚ´Â ·Î±×ÀÎ ¸ÊÀº ¸¶Áö¸· ¾÷µ¥ÀÌÆ® ½Ã°£ // ·Î±×¾Æ¿ô ¸ÊÀº »ðÀÔµÈ ½Ã°£ typedef std::pair DBDataPair; typedef std::map > > DataMap; //! DB¸¦ ¿¬°áÇÑ´Ù. void SetDBComponent(CDBComponent* lpDBComponent) { m_lpDBComponent = lpDBComponent; } CDBComponent* GetDBComponent() { return m_lpDBComponent; } //! µ¥ÀÌÅͰ¡ LoginDB¿¡ ÀÖ´ÂÁö, LogoutDB¿¡ ÀÖ´ÂÁö ¾Ë¾Æ ¿Â´Ù. bool IsDataLoginDB(const KeyType& dataKey) { return m_LoginMap.end() != m_LoginMap.find(dataKey); } bool IsDataLogoutDB(const KeyType& dataKey) { return m_LogoutMap.end() != m_LogoutMap.find(dataKey); } //! ¼¼ÆÃµÈ °ü¸®ÀÚ À̸§À» ¾ò¾î¿Â´Ù. const char* GetManagerName() const { return m_szManagerName; } unsigned int GetLoginNum() const { return static_cast(m_LoginMap.size()); } unsigned int GetLogoutNum() const { return static_cast(m_LogoutMap.size()); } //! µ¥ÀÌÅ͸¦ ¾ò¾î¿À°Å³ª, ¾ò¾î¿Â µ¥ÀÌÅ͸¦ ¹ÝȯÇÑ´Ù. virtual DBDataError LoadData(CSessionData& SessionData, KeyType dataKey, DataType*& lpLoadData_Out); virtual DBDataError UnloadData(const CSessionData& SessionData, DataType* lpUnloadData); DataType* GetLogoutData(const KeyType& dataKey); //! ·Î±×¾Æ¿ôµÈ µ¥ÀÌÅ͸¦ ¾ò¾î¿Â´Ù. DBDataError ReloadData(const KeyType& dataKey); //! µ¥ÀÌÅ͸¦ DB·ÎºÎÅÍ ReloadÇÑ´Ù. bool RemoveLogoutData(const KeyType& dataKey); //! ·Î±×¾Æ¿ôµÈ µ¥ÀÌÅ͸¦ ij½¬·ÎºÎÅÍ »èÁ¦ÇÑ´Ù. //! µ¥ÀÌÅÍ °³¼ö°¡ ³Ê¹« ¸¹Àº °æ¿ì, ·Î±×¾Æ¿ôÇÑÁö ¿À·¡µÈ µ¥ÀÌÅ͸¦ Çϳª¾¿ »èÁ¦ÇÑ´Ù. bool ManageUnloadedData(unsigned long dwMaxDataNum); //! ·Î±×ÀÎ ¼Â / ·Î±×¾Æ¿ô ¼Â¿¡ ÀÖ´Â µ¥ÀÌÅ͸¦ ¾÷µ¥ÀÌÆ®ÇÑ´Ù. //! Arg1 : ¾÷µ¥ÀÌÆ®ÇÒ ÃÖ¼Ò°³¼ö, //! Arg2 : ¾÷µ¥ÀÌÆ®¿¡ ¼Ò¸ðÇÒ ÃÖ´ë ½Ã°£ÀÌ´Ù. void UpdateDBData(unsigned long dwMinUpdateNum, unsigned long dwMaxUseTime); //! º¯°æµÈ µ¥ÀÌÅ͸¦ ÀüºÎ Àû¿ëÇÑ ÈÄ Á¦°ÅÇÑ´Ù. void Destroy() { Destroy(m_LoginMap.begin(), m_LoginMap.end()); Destroy(m_LogoutMap.begin(), m_LogoutMap.end()); m_LoginMap.clear(); m_LogoutMap.clear(); } protected: CDBDataMgr() : m_lpDBComponent(0) { memset(m_szManagerName, 0, sizeof(char) * MAX_MANAGER_NAME); } ~CDBDataMgr() { Destroy(); } void SetManagerName(const char* szManagerName) { strncpy(m_szManagerName, szManagerName, MAX_MANAGER_NAME - 1); m_szManagerName[MAX_MANAGER_NAME - 1] = 0; } // KeyTypeÀ» ·Î±×·Î ³²±æ ¹æ¹ýÀ» ¾Ë ¼ö ¾ø±â ¶§¹®¿¡ »ó¼Ó¹Þ¾Æ¼­ ó¸®Çϵµ·Ï ÇÑ´Ù. virtual void Log(LOG_TYPE eLogType, const char* pRtn, const char* pFileName, int nLine, const CSessionData* lpSessionData, const KeyType& dataKey, const char* szErrorMsg) = 0; // Data¸¦ »ý¼º ¹× »èÁ¦ÇÏ´Â ¸Þ¼­µåÀÌ´Ù. Data* CreateData() { return new Data; } void DeleteData(Data* lpDBData) { delete lpDBData; } /* Data* CreateData() { return m_DataPool.construct(); } void DeleteData(Data* lpDBData) { m_DataPool.destruct(lpDBData); } */ private: void Destroy(typename DataMap::iterator first, typename DataMap::iterator last); CDBComponent* m_lpDBComponent; //! DB¿ÍÀÇ ¿¬°á DataMap m_LoginMap; //! ·Î±×ÀÎ µÈ ij¸¯ÅÍ ¸®½ºÆ® DataMap m_LogoutMap; //! ·Î±×¾Æ¿ôµÈ ij¸¯ÅÍ ¸®½ºÆ® boost::object_pool m_DataPool; //! °´Ã¼ Ç® char m_szManagerName[MAX_MANAGER_NAME]; //! °ü¸® ¸Å´ÏÁ®ÀÇ À̸§. }; template class CGreaterLogoutTime { public: typedef typename CDBDataMgr::DataMap::value_type DataType; CGreaterLogoutTime(unsigned long dwCurrentTime) : m_dwCurrentTime(dwCurrentTime) { } bool operator () (const DataType& lhs, const DataType& rhs) { return m_dwCurrentTime - lhs.second.second > m_dwCurrentTime - rhs.second.second; } private: unsigned long m_dwCurrentTime; }; template class CGreaterUpdateTime { public: typedef typename CDBDataMgr::DataMap::value_type DataType; CGreaterUpdateTime(unsigned long dwCurrentTime) : m_dwCurrentTime(dwCurrentTime) { } bool operator () (const DataType& lhs, const DataType& rhs) { return m_dwCurrentTime - lhs.second.first->GetLastDBUpdateTime() > m_dwCurrentTime - rhs.second.first->GetLastDBUpdateTime(); } private: unsigned long m_dwCurrentTime; }; //! µ¥ÀÌÅ͸¦ ·ÎµåÇÑ ÈÄ Session¿¡ ¿¬°áÇÑ´Ù. template DBDataError CDBDataMgr::LoadData(CSessionData& SessionData, KeyType dataKey, Data*& lpLoadData_Out) { lpLoadData_Out = 0; Data* lpDBData = 0; DataMap::iterator pos; DataMap::iterator end; // ·Î±×ÀÎ ¸Ê¿¡ µ¥ÀÌÅͰ¡ ÀÖ´ÂÁö »ìÇÉ´Ù. ÀÖÀ¸¸é ·Î±×ÀÎ ½ÇÆÐ. pos = m_LoginMap.find(dataKey); end = m_LoginMap.end(); if(pos != end) { Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, (pos->second.first->GetKey() != dataKey) ? "µ¥ÀÌÅÍ ·Îµå ½ÇÆÐ : Ű °ªÀÌ ´Ù¸¨´Ï´Ù" : "µ¥ÀÌÅÍ ·Îµå ½ÇÆÐ : ÀÌ¹Ì Ä³¸¯ÅͰ¡ ·Î±×ÀÎ ÇØ ÀÖ½À´Ï´Ù"); return DATA_ALREADY_LOGIN_ERROR; } else { // ·Î±×¾Æ¿ô ¸Ê¿¡¼­ °Ë»öÇÕ´Ï´Ù. pos = m_LogoutMap.find(dataKey); end = m_LogoutMap.end(); if(pos != end) { // µ¥ÀÌÅͰ¡ ÀÖ´Ù. ·Î±×¾Æ¿ô ¸Ê¿¡¼­ »èÁ¦Çϰí, ¼¼ÆÃ Áغñ¸¦ ÇÑ´Ù. lpDBData = pos->second.first; m_LogoutMap.erase(pos); } else { // µ¥ÀÌÅͰ¡ ¾ø´Ù. µ¥ÀÌÅÍ »ý¼º ¹× ·Îµå¸¦ ÇÑ´Ù. if(0 != m_lpDBComponent) { lpDBData = CreateData(); if(0 != lpDBData) { if(!lpDBData->GetFromDB(*m_lpDBComponent, dataKey)) { // DB¿¡¼­ µ¥ÀÌÅÍ ¾ò¾î¿À±â ½ÇÆÐ. GetFromDB³»ºÎ¿¡¼­ ·Î±× ÂïÀ½. DeleteData(lpDBData); lpDBData = 0; } } else { Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ·Îµå ½ÇÆÐ : ¸Þ¸ð¸® ÇÒ´ç¿¡ ½ÇÆÐÇß½À´Ï´Ù"); } } else { Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ·Îµå ½ÇÆÐ : DB¿¬°áÀÌ NULLÀÔ´Ï´Ù"); } } } if(0 != lpDBData) { DBDataPair dataPair(lpDBData, timeGetTime()); if(!m_LoginMap.insert(std::make_pair(dataKey, dataPair)).second) { Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ·Îµå ½ÇÆÐ : LoginMap¿¡ µ¥ÀÌÅÍ »ðÀÔ ½ÇÆÐ(ÀÖÀ» ¼ö ¾øÀ½)"); DeleteData(lpDBData); lpDBData = 0; } else { Log(LOG_INFO, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ·Îµå ¼º°ø"); lpLoadData_Out = lpDBData; return DATA_SUCCEEDED; } } return DATA_SERVER_ERROR; } //! µ¥ÀÌÅ͸¦ Session¿¡¼­ ºÐ¸®ÇÑ ÈÄ ¾ð·ÎµåÇÑ´Ù. template DBDataError CDBDataMgr::UnloadData(const CSessionData& SessionData, Data* lpUnloadData) { if(0 != lpUnloadData) { KeyType dataKey = lpUnloadData->GetKey(); // ·Î±×ÀÎ ¸Ê¿¡¼­ ã¾Æ¼­ Á¦°Å if (0 == m_LoginMap.erase(dataKey)) { Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ¾ð·Îµå ÀÌ»ó : ·Î±×ÀÎ ¸Ê¿¡ ¾ø´Â µ¥ÀÌÅ͸¦ ¾ð·ÎµåÇÕ´Ï´Ù"); } else if(0 == m_lpDBComponent || !lpUnloadData->UpdateDBData(*m_lpDBComponent)) { // µ¥ÀÌÅÍ ¾÷µ¥ÀÌÆ® ½ÇÆÐ. Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ¾ð·Îµå ÀÌ»ó : ¾÷µ¥ÀÌÆ®¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù"); } else if (m_LogoutMap.insert( std::make_pair(dataKey, std::make_pair(lpUnloadData, timeGetTime()))).second) { // µ¥ÀÌÅÍ ¾÷µ¥ÀÌÆ® ¼º°ø. ¸Ê¿¡ ¾¥¼Å ³Ö°í »óÈ£ÂüÁ¶¸¦ ÇØÁ¦ÇÑ´Ù. Log(LOG_INFO, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ¾ð·Îµå ¼º°ø"); // ¼º°ø. ¿©±â¼­ Å»Ãâ return DATA_SUCCEEDED; } else { // ¸»µµ ¾ÈµÈ´Ù. µ¥ÀÌÅͰ¡ º¹»çµÉ ¿ì·Á°¡ ÀÖ´Ù. Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ¾ð·Îµå ½ÇÆÐ : Logout¸Ê¿¡ ÀÌ¹Ì µ¥ÀÌÅͰ¡ ÀÖ½À´Ï´Ù"); } // ÀÏ´Ü ´ýÇÁ¸¦ ³²±â°í »èÁ¦ÇÏ´Â ÆíÀÌ ÁÁ´Ù. if(!lpUnloadData->WriteDataToDumpFile(0)) { Log(LOG_ERROR, LOG_FFL, &SessionData, dataKey, "µ¥ÀÌÅÍ ¾ð·Îµå ½ÇÆÐ : ¾ð·Îµå ½ÇÆÐ ÈÄ, µ¥ÀÌÅ͸¦ ÆÄÀÏ·Î ³²±â´Â µ¥ ½ÇÆÐ"); } // ¸Þ¸ð¸® ¸¯ÀÌ »ý°Üµµ ¾î¿ ¼ö ¾ø´Ù. À߸ø DeleteÇÏ¸é »¶³­´Ù;; // DeleteData(lpUnloadData); } else { ERRLOG4(g_Log, "UID:%10u / CID:%10u / lpUnloadData:0x%p / %s µ¥ÀÌÅÍ ¾ð·Îµå ½ÇÆÐ : ÀÎÀÚ°¡ ÀÌ»óÇÕ´Ï´Ù", SessionData.GetUID(), SessionData.GetCID(), lpUnloadData, m_szManagerName); } return DATA_SERVER_ERROR; } //! µ¥ÀÌÅ͸¦ DB·ÎºÎÅÍ ReloadÇÑ´Ù. template DBDataError CDBDataMgr::ReloadData(const KeyType& dataKey) { if(0 == m_lpDBComponent) { return DATA_SERVER_ERROR; } // ·Î±×ÀÎ ¸Ê¿¡ ÀÌ¹Ì ÀÖÀ¸¸é, ºÒ·¯¿Í¼­´Â ¾ÈµÈ´Ù. DataMap::iterator pos = m_LoginMap.find(dataKey); DataMap::iterator end = m_LoginMap.end(); if(pos != end) { return DATA_ALREADY_LOGIN_ERROR; } // ·Î±×¾Æ¿ô ¸Ê¿¡ ÀÖÀ¸¸é, DB·ÎºÎÅÍ ºÒ·¯ ¿À°í, ¾øÀ¸¸é ±×³É ¸®ÅÏÇÑ´Ù. pos == m_LogoutMap.find(dataKey); end == m_LogoutMap.end(); return (pos != end && !pos->second.first->GetFromDB(*m_lpDBComponent, dataKey)) ? DATA_SERVER_ERROR : DATA_SUCCEEDED; } template bool CDBDataMgr::RemoveLogoutData(const KeyType& dataKey) { // ·Î±×¾Æ¿ô ij½¬¿¡ µ¥ÀÌÅͰ¡ ÀÖÀ¸¸é, ³¯·Á¹ö¸°´Ù. DataMap::iterator pos = m_LogoutMap.find(dataKey); DataMap::iterator end = m_LogoutMap.end(); if(pos != end) { DeleteData(pos->second.first); m_LogoutMap.erase(pos); return true; } return false; } //! µ¥ÀÌÅÍ °³¼ö°¡ ³Ê¹« ¸¹Àº °æ¿ì, ·Î±×¾Æ¿ôÇÑÁö ¿À·¡µÈ µ¥ÀÌÅ͸¦ Çϳª¾¿ »èÁ¦ÇÑ´Ù. template bool CDBDataMgr::ManageUnloadedData(unsigned long dwMaxDataNum) { size_t nLogoutDataNum = m_LogoutMap.size(); if(dwMaxDataNum < nLogoutDataNum) { // ½Ã°£À» º¸°í, Á¦ÀÏ ¿À·¡µÈ ij¸¯À» ³»¸°´Ù. typedef std::vector, boost::pool_allocator > > RemoveMap; RemoveMap removeMap(nLogoutDataNum - dwMaxDataNum); std::partial_sort_copy(m_LogoutMap.begin(), m_LogoutMap.end(), removeMap.begin(), removeMap.end(), CGreaterLogoutTime(timeGetTime())); RemoveMap::iterator pos = removeMap.begin(); RemoveMap::iterator end = removeMap.end(); for(; pos != end; ++pos) { m_LogoutMap.erase(pos->first); DeleteData(pos->second.first); } } return true; } //! ·Î±×ÀÎ ¼Â¿¡ ÀÖ´Â µ¥ÀÌÅ͸¦, ½Ã°£ ¼øÀ¸·Î Á¤·ÄÇØ¼­ °¡Àå ¿À·¡µÈ µ¥ÀÌÅͺÎÅÍ //! ¾÷µ¥ÀÌÆ®ÇÑ´Ù. ÀÎÀÚ´Â ¾÷µ¥ÀÌÆ®¿¡ ¼Ò¸ðÇÒ ÃÖ´ë ½Ã°£ÀÌ´Ù. template void CDBDataMgr::UpdateDBData(unsigned long dwMinUpdateNum, unsigned long dwMaxUseTime) { if(0 != m_lpDBComponent) { typedef std::vector, boost::pool_allocator > > UpdateList; UpdateList updateList(m_LoginMap.size()); unsigned long dwStartTime = timeGetTime(); std::partial_sort_copy(m_LoginMap.begin(), m_LoginMap.end(), updateList.begin(), updateList.end(), CGreaterUpdateTime(dwStartTime)); UpdateList::iterator loginPos = updateList.begin(); UpdateList::iterator loginEnd = updateList.end(); unsigned long dwCurrentTime = timeGetTime(); // ³¡±îÁö µ¹¾Ò°Å³ª, ÃÖ¼Ò °³¼ö ÀÌ»ó ¾÷µ¥ÀÌÆ®Çϰí, ½Ã°£ÀÌ ¿À¹öµÇ¾úÀ¸¸é ±×¸¸ ÇÑ´Ù. for(unsigned long dwUpdateCount = 0; loginPos != loginEnd; ++loginPos) { if (dwMinUpdateNum < dwUpdateCount && dwCurrentTime < dwStartTime + dwMaxUseTime) { break; } Data* lpDBData = loginPos->second.first; if(lpDBData->IsDataChanged()) { lpDBData->UpdateDBData(*m_lpDBComponent); ++dwUpdateCount; dwCurrentTime = timeGetTime(); } } // ij½¬ DBÂÊÀº. ´ëºÎºÐ ¾÷µ¥ÀÌÆ® µÇ¾î Àֱ⠶§¹®¿¡, // ÃÖ±Ù °ÅºÎÅÍ ¾÷µ¥ÀÌÆ® ÇØ ÁÙ ÇÊ¿ä´Â ¾ø´Ù. ±×³É ÀüºÎ ÇѹÙÄû µ¹¾ÆÁØ´Ù. DataMap::iterator logoutPos = m_LogoutMap.begin(); DataMap::iterator logoutEnd = m_LogoutMap.end(); dwCurrentTime = timeGetTime(); for(unsigned long dwUpdateCount = 0; logoutPos != logoutEnd; ++logoutPos) { if (dwMinUpdateNum < dwUpdateCount && dwCurrentTime < dwStartTime + dwMaxUseTime) { break; } Data* lpDBData = logoutPos->second.first; if(lpDBData->IsDataChanged()) { lpDBData->UpdateDBData(*m_lpDBComponent); ++dwUpdateCount; dwCurrentTime = timeGetTime(); } } } } template void CDBDataMgr::Destroy(typename DataMap::iterator first, typename DataMap::iterator last) { for(; first != last; ++first) { Data* lpData = first->second.first; if(0 == m_lpDBComponent || !lpData->UpdateDBData(*m_lpDBComponent)) { // TODO : ÃÖÁ¾ µ¥ÀÌÅÍ ¾÷µ¥ÀÌÆ® ½ÇÆÐ. ij¸¯ÅÍ ±â·ÏÀ» fileµîÀ¸·Î ³²±ä´Ù. Log(LOG_ERROR, LOG_FFL, 0, lpData->GetKey(), lpData->WriteDataToDumpFile(0) ? "µ¥ÀÌÅÍ ÀúÀå ½ÇÆÐ : ¾÷µ¥ÀÌÆ®¿¡ ½ÇÆÐ ÈÄ ÆÄÀÏ·Î ³²±é´Ï´Ù" : "µ¥ÀÌÅÍ ÀúÀå ½ÇÆÐ : ¾÷µ¥ÀÌÆ®, ÆÄÀÏ·Î ³²±â´Â µ¥ ½ÇÆÐÇß½À´Ï´Ù"); } DeleteData(lpData); } } template Data* CDBDataMgr::GetLogoutData(const KeyType& dataKey) { DataMap::iterator logoutPos = m_LogoutMap.find(dataKey); Data* lpDBData = 0; if(logoutPos == m_LogoutMap.end()) { // ·Î±×¾Æ¿ô ¸Ê¿¡ µ¥ÀÌÅͰ¡ ¾ø´Â °æ¿ì DataMap::iterator loginPos = m_LoginMap.find(dataKey); if(loginPos == m_LoginMap.end()) { // ·Î±×ÀÎ ¸Ê¿¡ µé¾îÀÖÁö ¾ÊÀº °æ¿ì¸¸ µ¥ÀÌÅ͸¦ ·Îµå lpDBData = CreateData(); if(0 != lpDBData) { if (lpDBData->GetFromDB(*m_lpDBComponent, dataKey) && m_LogoutMap.insert( std::make_pair(dataKey, std::make_pair(lpDBData, timeGetTime()))).second) { Log(LOG_INFO, LOG_FFL, 0, dataKey, "·Î±×¾Æ¿ô µ¥ÀÌÅÍ ·Îµå ¼º°ø"); } else { DeleteData(lpDBData); lpDBData = 0; } } } } else { // ·Î±×¾Æ¿ô ¸Ê¿¡ µ¥ÀÌÅͰ¡ ÀÖ´Â °æ¿ì lpDBData = logoutPos->second.first; } return lpDBData; } } } #endif