// Include #include #include "sqlpool.h" #include "iocontextpool.h" // Local definitions #pragma warning( disable: 4127 ) // memory¸¦ ¾ÈÀüÇÏ°Ô ÇØÁ¦ #define SafeDelete(P) if (P!=NULL) { delete(P); (P)=NULL; } // Global data // cSQLPool Constructor. cSQLPool::cSQLPool(void) { // Critical Section¸¦ ÃʱâÈ­. InitializeCriticalSection( &mCs ); // SQLEnvironment¸¦ ÃʱâÈ­. mSqlEnv = NULL; // SQLConnection¸¦ ÃʱâÈ­. mPagedPoolUsage = NULL; mNonPagedPoolUsage = NULL; // ¸Þ¸ð¸® Ä«¿îÅÍ ÃʱâÈ­. mQuotaPagedPoolUsage = 0; mQuotaNonPagedPoolUsage = 0; mWorkingSetSize = 0; mPeakWorkingSetSize = 0; memset( mDsn, 0, sizeof(mDsn) ); memset( mUid, 0, sizeof(mUid) ); memset( mPwd, 0, sizeof(mPwd) ); } // ~cSQLPool Destructor. cSQLPool::~cSQLPool(void) { // cSQLPool ThreadPool¸¦ Á¾·áÇÑ´Ù. Shutdown( ); // Critical Section¸¦ ÇØÁ¦. DeleteCriticalSection( &mCs ); } // GetProcessMemoryInfo Method. void cSQLPool::GetProcessMemoryInfo(SIZE_T& quotaPagedPoolUsage, SIZE_T& quotaNonPagedPoolUsage, SIZE_T& workingSetSize) { cCSLock lock( &mCs ); quotaPagedPoolUsage = mQuotaPagedPoolUsage; quotaNonPagedPoolUsage = mQuotaNonPagedPoolUsage; workingSetSize = mWorkingSetSize; } // Initialize Method - ThreadPool::Initialize À§Ä¡¿¡ ÁÖÀ§! bool cSQLPool::Initialize(char* dsn, char* uid, char* pwd, int numWorkerThreads) { // SQLServer »ç¿ëÀ» À§ÇØ ODBC ȯ°æÀ» ¼³Á¤. mSqlEnv = new cSQLEnvironment( ); // Audit º¹»ç. strcpy( mDsn, dsn ); strcpy( mUid, uid ); strcpy( mPwd, pwd ); // ¿¬°á Ç®¸µ Ȱ¼ºÈ­. if ( mSqlEnv->ConnectionPooling( ) == false ) return false; // ODBC, SQL »ç¿ëÀ» ÃʱâÈ­. if ( mSqlEnv->AllocEnv( ) == false ) return false; // SQL_ATTR_ODBC_VERSION ¸¦ SQL_OV_ODBC3 ·Î ¼³Á¤. if ( mSqlEnv->SetEnvAttr( ) == false ) return false; // ¿¬°á Ç®¸µ Á¶°Ç¼³Á¤. if ( mSqlEnv->ConnectionPoolingRelaxedMatch( ) == false ) return false; // ThreadPool Class¸¦ ÃʱâÈ­. // 3¹øÂ° ¸Å°³ ÇÔ¼ö°ª numWorkerThreads¸¦ CPU * 4·Î ÁöÁ¤. return cThreadPool::Initialize( INVALID_HANDLE_VALUE, 0, numWorkerThreads ); } // Shutdown Method - ThreadPool::Shutdown À§Ä¡¿¡ ÁÖÀ§! void cSQLPool::Shutdown(void) { // ThreadPool Class¸¦ Á¾·á. cThreadPool::Shutdown( ); // SQL Context¸¦ ÇØÁ¦. cCSLock lock( &mCs ); PerSQLConnection* temp; while ( mPagedPoolUsage != NULL ) { temp = mPagedPoolUsage; mPagedPoolUsage = mPagedPoolUsage->next; FreeSQLConnection( &temp ); } while ( mNonPagedPoolUsage != NULL ) { temp = mNonPagedPoolUsage; mNonPagedPoolUsage = mNonPagedPoolUsage->next; FreeSQLConnection( &temp ); } // ODBC, SQL »ç¿ëÀ» Á¾·á. if ( mSqlEnv != NULL ) { mSqlEnv->FreeEnv( ); } // ODBC, SQL ¸Þ¸ð¸®¸¦ ÇØÁ¦. SafeDelete( mSqlEnv ); } // AllocSQLConnection Method PerSQLConnection* cSQLPool::AllocSQLConnection(void) { PerSQLConnection* perSQLConnection = (PerSQLConnection*)GlobalAlloc( GPTR, sizeof(PerSQLConnection) ); if ( perSQLConnection != NULL ) { // PerSQLConnection - ÃʱâÈ­ perSQLConnection->sqlConnection = new cSQLConnection( ); // 1. SQLConnection »ý¼º. perSQLConnection->sqlStatement = new cSQLStatement( ); // 2. SQLStatement »ý¼º. perSQLConnection->prev = NULL; // ¼±Çü¸®½ºÆ®ÀÇ Æ÷ÀÎÅÍ - ÀÌÀü. perSQLConnection->next = NULL; // ¼±Çü¸®½ºÆ®ÀÇ Æ÷ÀÎÅÍ - ´ÙÀ½. // Ŭ·¡½º »ý¼º È®ÀÎ. if ( perSQLConnection->sqlConnection != NULL && perSQLConnection->sqlStatement != NULL ) { // SQLEnvironment Ŭ·¡½º¸¦ ÂüÁ¶ÇÏ¿© ÇÚµé »ý¼º. if ( perSQLConnection->sqlConnection->AllocDbc( mSqlEnv ) == true ) { // DBC ¿¬°á. if ( perSQLConnection->sqlConnection->Connect( (SQLCHAR*)mDsn, (SQLCHAR*)mUid, (SQLCHAR*)mPwd ) == true ) { // SQLConnectionŬ·¡½º¸¦ ÂüÁ¶ÇÏ¿© ÇÚµé »ý¼º. if ( perSQLConnection->sqlStatement->AllocStmt( perSQLConnection->sqlConnection ) == true ) { // mWorkingSetSize¸¦ Áõ°¡. mWorkingSetSize++; return perSQLConnection; } } } } } FreeSQLConnection( &perSQLConnection ); return perSQLConnection; } // FreeSQLConnection Method void cSQLPool::FreeSQLConnection(PerSQLConnection** perSQLConnection) { if ( perSQLConnection != NULL ) { SafeDelete( (*perSQLConnection)->sqlStatement ); // 1. SQLStatement ÇØÁ¦. SafeDelete( (*perSQLConnection)->sqlConnection ); // 2. SQLConnection ÇØÁ¦. GlobalFree( (*perSQLConnection) ); (*perSQLConnection) = NULL; // mWorkingSetSize¸¦ °¨¼Ò. mWorkingSetSize--; } } // AttachPool Method - POOL ¿¡ ³ëµå ¿¬°á. void cSQLPool::AttachPool(PerSQLConnection** pool, PerSQLConnection* perSQLConnection) { if ( (*pool) != NULL ) { (*pool)->prev = perSQLConnection; perSQLConnection->prev = NULL; perSQLConnection->next = (*pool); } (*pool) = perSQLConnection; } // DetachPool Method - POOL ¿¡ ³ëµå ¿¬°áÇØÁ¦. void cSQLPool::DetachPool(PerSQLConnection** pool, PerSQLConnection* perSQLConnection) { PerSQLConnection* prev = perSQLConnection->prev; PerSQLConnection* next = perSQLConnection->next; if ( prev == NULL && next == NULL ) { (*pool) = NULL; } else if ( prev == NULL && next != NULL ) { next->prev = NULL; (*pool) = next; } else if ( prev != NULL && next == NULL ) { prev->next = NULL; } else if ( prev != NULL && next != NULL ) { prev->next = next; next->prev = prev; } perSQLConnection->prev = NULL; perSQLConnection->next = NULL; } // GetPool Method // ReleasePool°ú ÇÔ²² LIFO¸¦ ÀÌ·é´Ù. LIFO´Â Context Switching¸¦ ÃÖ¼ÒÈ­ Çϱâ À§ÇØ »ç¿ë PerSQLConnection* cSQLPool::GetPool(void) { cCSLock lock( &mCs ); PerSQLConnection* perSQLConnection = mNonPagedPoolUsage; if ( perSQLConnection != NULL ) { // ÆäÀÌÁö ¾ÈµÈ Ç® »ç¿ë·®¸¦ Â÷°¨. DetachPool( &mNonPagedPoolUsage, perSQLConnection ); mQuotaNonPagedPoolUsage--; // SQLEnvironment Ŭ·¡½º¸¦ ÂüÁ¶ÇÏ¿© ÇÚµé »ý¼º. if ( perSQLConnection->sqlConnection->AllocDbc( mSqlEnv ) == false ) { FreeSQLConnection( &perSQLConnection ); } // DBC ¿¬°á. else if ( perSQLConnection->sqlConnection->Connect( (SQLCHAR*)mDsn, (SQLCHAR*)mUid, (SQLCHAR*)mPwd ) == false ) { FreeSQLConnection( &perSQLConnection ); } // SQLConnectionŬ·¡½º¸¦ ÂüÁ¶ÇÏ¿© ÇÚµé »ý¼º. else if ( perSQLConnection->sqlStatement->AllocStmt( perSQLConnection->sqlConnection ) == false ) { FreeSQLConnection( &perSQLConnection ); } } if ( perSQLConnection == NULL ) { // ÆäÀÌÁö°¡ ¾øÀ» °æ¿ì »õ·Î »ý¼º. perSQLConnection = AllocSQLConnection( ); } if ( perSQLConnection != NULL ) { // ÆäÀÌÁö µÈ Ç® »ç¿ë·®À» Áõ°¨. AttachPool( &mPagedPoolUsage, perSQLConnection ); mQuotaPagedPoolUsage++; } return perSQLConnection; } // ReleasePool Method // GetPool°ú ÇÔ²² LIFO¸¦ ÀÌ·é´Ù. LIFO´Â Context Switching¸¦ ÃÖ¼ÒÈ­ Çϱâ À§ÇØ »ç¿ë void cSQLPool::ReleasePool(PerSQLConnection* perSQLConnection) { cCSLock lock( &mCs ); // ODBC Á¤¸®. perSQLConnection->sqlStatement->FreeStmt( ); perSQLConnection->sqlConnection->Disconnect( ); perSQLConnection->sqlConnection->FreeDbc( ); // ÆäÀÌÁö µÈ Ç® »ç¿ë·®À» Â÷°¨. DetachPool( &mPagedPoolUsage, perSQLConnection ); mQuotaPagedPoolUsage--; // ÆäÀÌÁö ¾ÈµÈ Ç® »ç¿ë·®À» Áõ°¨. AttachPool( &mNonPagedPoolUsage, perSQLConnection ); mQuotaNonPagedPoolUsage++; } // WorkerThread Method DWORD cSQLPool::WorkerThread(void) { PerSQLConnection* perSQLConnection = NULL; PerIoContext* perIoContext = NULL; BOOL retValue; DWORD bytesTransfered; ULONG_PTR completionKey; OVERLAPPED* overlapped; while ( true ) { // ´ë±âÁß I/O °¡Á®¿À±â. retValue = GetQueuedCompletionStatus( mRequestQueue, &bytesTransfered, &completionKey, &overlapped, INFINITE ); // Shutdown. if ( overlapped == POOL_SHUTDOWN ) break; // Error - ¿À·ù. if ( retValue == FALSE || bytesTransfered == 0 ) continue; // SQLConnection - °¡Á®¿À±â. perSQLConnection = GetPool( ); // SQLConnection - ¿¬°áÈ®ÀÎ. if ( perSQLConnection == NULL ) { // 1(¼ø¼­¿¡ ÁÖÀ§), Áö¿¬½Ã°£ 10/1000(s) - CPU °úºÎÈ­ ¹æÁö¿¡ »ç¿ë. Sleep( 10 ); // 2(¼ø¼­¿¡ ÁÖÀ§), ¿¬°áÀÌ ¾È µÇ¾úÀ» °æ¿ì, ´Ù½Ã ½Ãµµ. QueueRequest( completionKey, overlapped, bytesTransfered ); continue; } // OVERLAPPED¸¦ PerIoContext·Î ÄɽºÆÃ. perIoContext = (PerIoContext*)overlapped; // 1. SQL¸¦ ½ÇÇà // 2. PerIoContext »ç¿ë¾È·á. // SQLConnection - ³»º¸³»±â. ReleasePool( perSQLConnection ); } return 0L; }