This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+671
View File
@@ -0,0 +1,671 @@
#include "ReplicateInsert.h"
#include <errno.h>
#include <string.h>
#include "Logger.h"
#include "Database.h"
#include "ServiceConfig.h"
#include "Util.h"
// 처리 loop 간의 sleep time 정의
// - 매 지정된 sec 마다 queue 를 검사하여 RCDB 에 저장 처리.
#define DEFAULT_SLEEP_TIME 3
// RCDB 접속 실패 또는 Query 실패 등의 상황 발생시
#define MAX_SLEEP_TIME 30
// Query 문장 저장을 위한 Buffer 크기
#define DEFAULT_QUERY_BUFFER_SIZE 2048
// 생성자
// @param [in] pCCompleteData replication 완료 content 정보를 저장하는 queue
CReplicateInsert::CReplicateInsert( CDataQueue<CCompleteData> * pCompleteQueue )
: m_pCompleteQueue( pCompleteQueue )
{
m_threadHandle = 0;
m_uSleep = DEFAULT_SLEEP_TIME;
// NEW 2014-06-16 신규 멤버 변수 초기화 코드 추가.
// Init() 에서 RCDB 접속 실패가 발생 가능하므로.. 구형 RCDB 형상을 사용토록 설정.
m_bServiceTableSeparate = false;
}
// 소멸자
CReplicateInsert::~CReplicateInsert()
{
// Thread 동작 정지 처리
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 이 다른 Thread Handle 일 수 있으므로
// 업무 Flow 수정시 주의할 것
if( m_threadHandle != 0 )
pthread_cancel( m_threadHandle );
}
// 초기화 작업 수행
bool CReplicateInsert::Init()
{
// 생성자를 통해 전달받은 queue 포인터가 NULL 인 경우... 오류 처리
if( m_pCompleteQueue == NULL )
{
LOG( LERR, "replication complete queue is null" );
return false;
}
// Report log 를 처리할 객체 초기화.
if( m_reportLog.Init( CServiceConfig::GetInstance()->GetLogPath() ) == false )
{
std::string strErrorMessage;
m_reportLog.GetLastError( strErrorMessage );
LOG( LERR, "report log init fail. [%s]", strErrorMessage.c_str() );
return false;
}
// RCDB 접속 정보 Load.
m_rcdbInfo.Load();
// RCDB 접속 처리를 위한 객체 생성
DataBase rcdb;
// RCDB 접속 시도 및 접속 실패시
if( rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort
, m_rcdbInfo.m_strRcdbName, m_rcdbInfo.m_strRcdbAcct
, m_rcdbInfo.m_strRcdbAcctPw ) == NULL )
{
LOG( LERR, "RCDB connection failed." );
return false;
}
else
{
// 접속 성공한 경우...
LOG( LINF, "RCDB connection test ok..." );
// NEW 2014-06-19 huibong
// 서비스 table 분리된 신규 형상인지.. 구형 형상인지 체크하여
// m_bServiceTableSeparate 변수 설정 처리.
// 해당 변수 초기화는 생성자에서 1차로 수행함.
char szQuery[1024];
snprintf( szQuery, 1023,
"SELECT * FROM pg_tables WHERE schemaname = 'public' AND tablename = 't_dav_resource' " );
rcdb.PgDoExec( szQuery );
if( rcdb.PgResult( DataBase::NOT_CLEAR ) < 0 )
{
// Query 수행 결과 오류 발생시...
// - pg_tables 가 존재하지 않을 경우 오류 발생 가능...
// - 이는 RCDB 가 아직 적절하게 구성되지 않았다는 의미이므로... Init()함수를 오류로 처리한다.
LOG( LERR, "RCDB t_dav_resource exist check failed.[%s][%s]", rcdb.GetErrorMessage().c_str(), szQuery );
rcdb.PgClear();
rcdb.PgCloseDB();
return false;
}
else
{
// Query 수행이 정상인 경우.
int nResult = rcdb.GetNoTuples();
if( nResult > 0 )
{
// t_dav_resource 테이블이 존재하는 경우...
m_bServiceTableSeparate = false;
_LOG( LINF, "CReplicateInsert: t_dav_resource table exist.[Old RCDB Type]" );
}
else
{
// t_dav_resource 테이블이 존재하지 않는 서비스별 테이블 분리 형상인 경우.
m_bServiceTableSeparate = true;
_LOG( LINF, "CReplicateInsert: t_dav_resource table not exist.[New RCDB Type]" );
}
}
// RCDB 조회 결과 set 를 clear 처리 후 RCDB 접속 해제.
rcdb.PgClear();
rcdb.PgCloseDB();
return true;
}
}
// Thread 를 생성하여 할당된 작업을 수행.
bool CReplicateInsert::Start()
{
int nRet = ::pthread_create( &m_threadHandle, NULL, CReplicateInsert::threadFunc, this );
if( nRet != 0 )
{
// Thread 생성 실패시
int errorNum = errno;
LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
return true;
}
// Thread function
void* CReplicateInsert::threadFunc( void* arg )
{
CReplicateInsert* pObject = reinterpret_cast<CReplicateInsert *>( arg );
pthread_detach( pthread_self() );
while( 1 )
{
pthread_testcancel();
pObject->Execute();
pthread_testcancel();
// 1회 수행 후 지정된 시간 만큼 대기
sleep( pObject->m_uSleep );
}
// NEW 2014-06-19 huibong
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
pObject->m_threadHandle = 0;
return NULL;
}
// 스레드 내에서 각 loop 단위 처리 호출 함수.
void CReplicateInsert::Execute()
{
// Queue 상에 처리할 Data 가 존재할 경우...
if( m_pCompleteQueue->GetSize() > 0 )
{
bool bResult;
// t_dav_resource 테이블 사용 형상인 경우.
if( m_bServiceTableSeparate == false )
{
bResult = InsertToOldDB();
}
else
{
// 서비스별 Table 이 분리된 신규 형상인 경우.
bResult = InsertToDB();
}
// 처리 결과에 따라 loop sleep time 조정
if( bResult == true )
m_uSleep = DEFAULT_SLEEP_TIME;
else
{
// RCDB 연결 실패, Queury 수행 실패 등의 오류 발생시
m_uSleep = MAX_SLEEP_TIME;
}
}
else
{
// queue 상에 처리할 Data 가 존재하지 않는 경우.
m_uSleep = DEFAULT_SLEEP_TIME;
}
}
// RCDB 상에 복제 완료된 content 정보를 insert 처리한다. ( t_dav_resource 사용 )
bool CReplicateInsert::InsertToOldDB()
{
// 1. RCDB 와 연결 처리.
DataBase rcdb;
if( rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort
, m_rcdbInfo.m_strRcdbName, m_rcdbInfo.m_strRcdbAcct
, m_rcdbInfo.m_strRcdbAcctPw ) == NULL )
{
// RCDB 접속이 실패
LOG( LERR, "RCDB connection failed." );
return false;
}
// 2. 루프를 돌면서 queue 에 저장된 data 를 처리한다.
// queue 에서 꺼낸 정보를 저장하기 위한 변수
CCompleteData resultData;
// Query 문장 저장을 위한 버퍼 생성
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
// Query 수행 결과값 저장을 위한 변수..
int nResult = 0;
while( m_pCompleteQueue->GetSize() > 0 )
{
// queue 에 저장된 첫번째 data 복사 (queue 에서 삭제된 상태 아님)
resultData = m_pCompleteQueue->Front();
// URI의 '(작은따옴표) 문자가 있을 경우 SQL 오류 방지를 위하여 관련 문자를 다르게 변경함
std::string orgURI = stringreplace(resultData.m_OriginData.m_szURI, "'", "''");
// 원본 조회 서브 쿼리 절에서 분리함 2012.02.10
// PGPool 경우 INSERT~SELECT 사용 지향
// 해당 서브절에 SELECT 값이 DB01,DB02 서로 다른 값을 참조될 수 있다.
// 3. 원본 존재 여부 확인
// Replication 처리가 완료된 Content 에 대해 meta 정보 입력전 실제 원본이 존재하는지 확인한다.
sprintf( szQuery,
"SELECT "
" sp_user_seq, sp_svc_tran_id, "
" '%s', "
" resource_type, uri, filename_org, '%s', "
" depth, display_name, get_content_language, "
" get_content_length, get_content_type, "
" get_etag, get_lastmodified, creation_date, "
" lock_discovery, source, supported_lock, deleted_yn, 'R', file_lastmodified " // is_cache = R
"FROM t_dav_resource "
"WHERE filename_hash = '%s' "
"AND uri = '%s' "
"AND get_content_length = %lld "
"AND is_cache = 'N' AND host_name = '%s' ;",
resultData.m_szTargetHostName.c_str(),
resultData.m_szTargetFileNameHash.c_str(),
resultData.m_OriginData.m_szFileNameHash.c_str(),
orgURI.c_str(),
resultData.m_OriginData.m_nContentLength,
resultData.m_OriginData.m_szOriginHostName.c_str() );
// Query 수행 및 결과 확인
rcdb.PgDoExec( szQuery );
nResult = rcdb.PgResult( DataBase::NOT_CLEAR );
if( nResult < 0 )
{
// RCDB t_dav_resource 테이블 조회 실패시
// - RCDB 연결 관련 실패시 : nResult = -4
// - uri 상의 특수문자로 인해 query 오류 : nResult = -4
// - 즉 오류 반환값이 동일하기 때문에 어떠한 문제로 query 가 실패했는지 판단 못함.
// 우선 DB 연결 문제일 수 있으므로...
// RCDB 재접속 시도.
rcdb.PgClear();
rcdb.PgCloseDB();
sleep( 1 );
if( rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort
, m_rcdbInfo.m_strRcdbName, m_rcdbInfo.m_strRcdbAcct
, m_rcdbInfo.m_strRcdbAcctPw ) == NULL )
{
// RCDB 접속 실패 문제인 경우..
// - 본 처리 함수 종료 처리하여 다음 loop 에서 재시도토록 처리.
LOG( LERR, "select query fail because RCDB connection error. [%d][%s]"
, nResult, rcdb.GetErrorMessage().c_str());
rcdb.PgCloseDB();
return false;
}
else
{
// uri 상에 특수 문자 문제로 query 실패시
// - Report 로그에 관련 내역 기록
// - queue 에서 해당 정보를 삭제 처리한 후 계속 수행한다.
LOG( LERR, "select query fail. queue forced pop.[%s][%d][%s]"
, orgURI.c_str(), nResult, rcdb.GetErrorMessage().c_str() );
m_reportLog.Write( "WAR", "[%s][Replication contents RCDB insert fail. check uri.[%s]]"
, PROG_NAME, orgURI.c_str());
rcdb.PgClear();
m_pCompleteQueue->Pop();
continue;
}
}
// 결과 Row 수 확인.
nResult = rcdb.GetNoTuples();
if( nResult <= 0 )
{
// Replication 생성된 content 가 RCDB 에 존재하지 않는 경우...
// - RCDB 에 저장하지 않고 그냥 버린다.
// - 이로 인해 FHS 에 meta 기준으로 삭제 불가능한 파일이 남게 된다.
_LOG( LINF, "Replication content[%s] not found in RCDB.", orgURI.c_str() );
rcdb.PgClear();
m_pCompleteQueue->Pop();
continue;
}
// 조회된 원본 정보를 list 에 저장
std::vector<string> srcinfo;
std::string strResult;
for( int j = 0 ; j < 21; j++ )
{
strResult = rcdb.GetValue( 0, j );
strResult = stringreplace( strResult, "'", "''" );
srcinfo.push_back( strResult );
}
// Select Query 의 결과를 Clear
rcdb.PgClear();
// 4. Replication 된 Content 정보를 Meta 정보로 Insert
// INSERT 작업시 앞에서 조회된 원본 정보를 이용하여 INSERT 한다.
sprintf( szQuery,
"INSERT INTO t_dav_resource "
"( "
" sp_user_seq, sp_svc_tran_id, "
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
" depth, display_name, get_content_language, "
" get_content_length, get_content_type, "
" get_etag, get_lastmodified, creation_date, "
" lock_discovery, source, supported_lock, deleted_yn, is_cache ,file_lastmodified) "
"VALUES "
"( "
" %s, %s, "
" '%s', "
" %s, '%s', '%s', '%s', "
" %s, '%s', '%s', "
" %s, '%s', "
" '%s', %s, %s, "
" '%s', %s, '%s', '%s', '%s', %s );", // is_cache = R
srcinfo[0].c_str(),srcinfo[1].c_str(),srcinfo[2].c_str(),srcinfo[3].c_str(),
srcinfo[4].c_str(),srcinfo[5].c_str(),srcinfo[6].c_str(),srcinfo[7].c_str(),
srcinfo[8].c_str(),srcinfo[9].c_str(),srcinfo[10].c_str(),srcinfo[11].c_str(),
srcinfo[12].c_str(),srcinfo[13].c_str(),srcinfo[14].c_str(),srcinfo[15].c_str(),
srcinfo[16].c_str(),srcinfo[17].c_str(),srcinfo[18].c_str(),srcinfo[19].c_str(),srcinfo[20].c_str()
);
// INSERT query 수행
rcdb.PgDoExec( szQuery );
nResult = rcdb.PgResult( DataBase::CLEAR );
if( nResult < 0 )
{
// RCDB INSERT 작업시 오류가 발생한 경우...
// - uri 문제는 앞의 SELECT query 에서 체크했으므로 아니고....
// - DB 연결 문제 역시 바로 앞에서 체크 했으므로 아닐 가능성이 큼.
// - 가장 큰 오류는 Query 오류일 가능성이 크므로...
// - Queue 에 pop 처리한다.
// Report 로그에 관련 내역 기록
LOG( LERR, "insert query fail. queue forced pop.[%s][%d][%s]"
, orgURI.c_str(), nResult, rcdb.GetErrorMessage().c_str() );
m_reportLog.Write( "WAR", "[%s][Replication contents RCDB insert fail. Check query[%s][%s]]"
, PROG_NAME, orgURI.c_str(), rcdb.GetErrorMessage().c_str() );
// queue 에서 해당 정보를 삭제 처리한 후 계속 수행한다.
rcdb.PgClear();
m_pCompleteQueue->Pop();
continue;
}
rcdb.PgClear();
// NEW 2012-09-24 huibong Replication 최종 정합성 검증 기능 추가
// 원본 존재 여부를 확인한 후 Insert 를 수행하지만...
// 해당 interval 동안 원본이 MOVE 또는 Rename, Delete 되는 상황이 발생하여 잘못된 Replication이 발생하고..이로 인해 서비스 장애가 발생 가능
// INSERT 작업 후 원본에 대한 정합성 여부를 다시 한번 확인하여
// 원본이 변경된 경우 INSERT 된 Meta 정보를 DELETE 처리한다.
// 5. INSERT 된 Meta 정보에 대해 원본이 존재하는지 다시 한번 확인하여
// 원본이 변경된 경우 INSERT 된 정보를 DELETE 한다. (deleted_yn = 'Y', 물리 Content 자동 제거 처리 목적 )
sprintf( szQuery,
"SELECT "
" uri, get_content_length, deleted_yn "
"FROM t_dav_resource "
"WHERE filename_hash = '%s' "
"AND uri = '%s' "
"AND get_content_length = %lld "
"AND is_cache = 'N' AND host_name = '%s' AND deleted_yn = '%s' ;",
resultData.m_OriginData.m_szFileNameHash.c_str(),
orgURI.c_str(),
resultData.m_OriginData.m_nContentLength,
resultData.m_OriginData.m_szOriginHostName.c_str(),
srcinfo[18].c_str()
);
rcdb.PgDoExec( szQuery );
nResult = rcdb.PgResult( DataBase::NOT_CLEAR );
if( nResult < 0 )
{
// 최종 검증을 위한 Check query 가 실패한 경우..
// query 구문은 앞의 2번 query 를 통해 검증되었으므로.. query 문제가 아닐 듯.
// 본 오류는 대부분 RCDB 연결 관련 문제인 듯.
// - 로깅 처리 후
// - RCDB 에 이미 INSERT 처리 되었으므로... queue pop 처리
// - DB 세션 종료 처리 후 .. return 하여.. sleep 후 다음 루프가 동작하도록 처리.
LOG(LERR, "replication last check query fail.[%s][%d][%s][%s]"
, orgURI.c_str(), nResult, rcdb.GetErrorMessage().c_str(), szQuery );
rcdb.PgClear();
rcdb.PgCloseDB();
m_pCompleteQueue->Pop();
return false;
}
// 조회된 결과 row 수 확인
nResult = rcdb.GetNoTuples();
rcdb.PgClear();
if( nResult <= 0 )
{
// 원본이 변경된 경우......
// 앞에서 INSERT 된 Replication 정보를 deleted_yn = 'Y' 처리한다.
LOG( LWAR, "replication check source not found. insert replication value set deleted [%s]"
, orgURI.c_str() );
sprintf( szQuery,
"UPDATE t_dav_resource SET deleted_yn = 'Y', get_lastmodified = %lld "
"WHERE uri = '%s' "
" AND host_name = '%s' "
" AND filename_hash = '%s' "
" AND get_content_length = %lld "
" AND is_cache = 'R' "
" AND deleted_yn = 'N' ;",
longtime_now(),
orgURI.c_str(),
resultData.m_szTargetHostName.c_str(),
resultData.m_szTargetFileNameHash.c_str(),
resultData.m_OriginData.m_nContentLength );
rcdb.PgDoExec( szQuery );
nResult = rcdb.PgResult( DataBase::CLEAR );
if( nResult < 0 )
{
// 삭제 처리 작업이 실패한 경우...
// RCDB 연결 문제로 인한 가능성이 가장 크므로...
// - 로깅 후..
// - RCDB 연결 해제...
// - queue pop 후 다음 루프에서 처리토록 return 처리.
LOG( LERR, "invalid replication delete fail.[%s][%s]"
, orgURI.c_str(), rcdb.GetErrorMessage().c_str());
m_reportLog.Write( "WAR", "[%s][Invalid replication contents exist.[%s]]"
, PROG_NAME, orgURI.c_str() );
rcdb.PgClear();
rcdb.PgCloseDB();
m_pCompleteQueue->Pop();
return false;
}
}
// 1 개 replication content 에 대한 RCDB insert 작업이 완료된 경우.
// - RCDB clear 처리후
// - queue pop.
rcdb.PgClear();
m_pCompleteQueue->Pop();
_LOG( LDBG, "replication rcdb Insert [%s|%s]->[%s|%s|%llu]"
, resultData.m_OriginData.m_szOriginHostName.c_str()
, resultData.m_OriginData.m_szURI.c_str()
, resultData.m_szTargetHostName.c_str()
, resultData.m_szTargetFileNameHash.c_str()
, resultData.m_OriginData.m_nContentLength
);
}
// queue 에 저장된 정보 처리 작업이 완료된 경우...
// - RCDB 연결 해제 처리.
rcdb.PgClear();
rcdb.PgCloseDB();
return true;
}
// RCDB 상에 복제 완료된 content 정보를 insert 처리한다. ( t_meta_xxx 사용 )
// - 신규 RCDB 관련 미사용 Column 항목 제거 처리.
bool CReplicateInsert::InsertToDB()
{
// 1. RCDB 와 연결 처리.
DataBase rcdb;
if( rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort
, m_rcdbInfo.m_strRcdbName, m_rcdbInfo.m_strRcdbAcct
, m_rcdbInfo.m_strRcdbAcctPw ) == NULL )
{
// RCDB 접속이 실패
LOG( LERR, "RCDB connection failed." );
return false;
}
// 2. 루프를 돌면서 queue 에 저장된 data 를 처리한다.
// queue 에서 꺼낸 정보를 저장하기 위한 변수
CCompleteData resultData;
// Query 문장 저장을 위한 버퍼 생성
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
// Query 수행 결과값 저장을 위한 변수..
int nResult = 0;
while( m_pCompleteQueue->GetSize() > 0 )
{
// queue 에 저장된 첫번째 data 복사 (queue 에서 삭제된 상태 아님)
resultData = m_pCompleteQueue->Front();
// URI의 '(작은따옴표) 문자가 있을 경우 SQL 오류 방지를 위하여 관련 문자를 다르게 변경함
std::string orgURI = stringreplace( resultData.m_OriginData.m_szURI, "'", "''" );
// 원본 조회 서브 쿼리 절에서 분리함 2012.02.10
// PGPool 경우 INSERT~SELECT 사용 지향
// 해당 서브절에 SELECT 값이 DB01,DB02 서로 다른 값을 참조될 수 있다.
// CHG 2015-02-12 huibong
// 신규 RCDB 형상에 맞도록 처리 Flow 단순화 (#21354)
// - RCDB 구조가 pgpool -> streaming replicaton 구조로 변경됨
// - 이에 따라 기존 SELECT 후 INSERT, 검수, DELETE flow 에 대한 단순화 가능함.
sprintf( szQuery,
"INSERT INTO t_meta_%s " // 신형 RCDB 형상
"( "
" sp_user_seq, sp_svc_tran_id, "
" host_name, "
" resource_type, uri, filename_org, filename_hash, "
" depth, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, is_cache , file_lastmodified "
") "
"SELECT "
" sp_user_seq, sp_svc_tran_id, "
" '%s', "
" resource_type, uri, filename_org, '%s', "
" depth, display_name, "
" get_content_length, get_content_type, "
" get_lastmodified, creation_date, "
" source, deleted_yn, 'R', file_lastmodified " // is_cache = R
"FROM t_meta_%s " // 신형 RCDB 형상
"WHERE filename_hash = '%s' "
"AND uri = '%s' "
"AND get_content_length = %lld "
"AND is_cache = 'N' AND host_name = '%s' ;"
, resultData.m_OriginData.m_szServiceSeq.c_str()
, resultData.m_szTargetHostName.c_str()
, resultData.m_szTargetFileNameHash.c_str()
, resultData.m_OriginData.m_szServiceSeq.c_str()
, resultData.m_OriginData.m_szFileNameHash.c_str()
, orgURI.c_str()
, resultData.m_OriginData.m_nContentLength
, resultData.m_OriginData.m_szOriginHostName.c_str()
);
// INSERT-SELECT query 수행
rcdb.PgDoExec( szQuery );
nResult = rcdb.PgResult( DataBase::NOT_CLEAR );
if( nResult < 0 )
{
// RCDB SELECT-INSERT 작업시 오류가 발생한 경우...
// - RCDB 연결 관련 실패시 : nResult = -4
// - uri 상의 특수문자로 인해 query 오류 : nResult = -4
// - 그외 Query 오류일 가능성이 존재
std::string strPreviousErrorMessage = rcdb.GetErrorMessage();
// 우선 DB 연결 문제일 수 있으므로... RCDB 재접속 시도.
rcdb.PgClear();
rcdb.PgCloseDB();
sleep( 1 );
if( rcdb.PgOpenDB( m_rcdbInfo.m_strRcdbIp, m_rcdbInfo.m_nRcdbPort
, m_rcdbInfo.m_strRcdbName, m_rcdbInfo.m_strRcdbAcct
, m_rcdbInfo.m_strRcdbAcctPw ) == NULL )
{
// RCDB 접속 실패 문제인 경우..
// - 본 처리 함수 종료 처리하여 다음 loop 에서 재시도토록 처리.
LOG( LERR, "Query fail because New RCDB connection error. [%d][%s]"
, nResult, rcdb.GetErrorMessage().c_str() );
rcdb.PgCloseDB();
return false;
}
else
{
// uri 상에 특수 문자 또는 Query 문제인 경우...
// - Report 로그에 관련 내역 기록
// - queue 에서 해당 정보를 삭제 처리한 후 계속 수행한다.
LOG( LERR, "insert-select query fail. queue forced pop.[%s][%d][%s]"
, orgURI.c_str(), nResult, strPreviousErrorMessage.c_str() );
// Report 로그에 관련 내역 기록
m_reportLog.Write( "WAR", "[%s][Replication contents New RCDB insert fail. Check query[%s][%s]]"
, PROG_NAME, orgURI.c_str(), strPreviousErrorMessage.c_str() );
rcdb.PgClear();
m_pCompleteQueue->Pop();
continue;
}
}
// PgResult 호출시 NOT_CLEAR 옵션을 사용했으므로....INSERT 수행 row 수 확인을 위해 GetCmdTuples() 함수를 호출가능.
nResult = rcdb.GetCmdTuples();
if( nResult > 0 )
{
_LOG( LDBG, "replication rcdb Insert [%d] row, [%s|%s]->[%s|%s|%llu]"
, nResult
, resultData.m_OriginData.m_szOriginHostName.c_str()
, resultData.m_OriginData.m_szURI.c_str()
, resultData.m_szTargetHostName.c_str()
, resultData.m_szTargetFileNameHash.c_str()
, resultData.m_OriginData.m_nContentLength
);
}
else
{
// INSERT 처리된 row 가 없는 경우....
// - 생성된 replicaton 파일은 고아 파일이 됨.
_LOG( LWAR, "replication rcdb Insert origin not found. orgin[%s|%s|%llu|%s] orphan[%s|%s|%llu]"
, resultData.m_OriginData.m_szOriginHostName.c_str()
, resultData.m_OriginData.m_szFileNameHash.c_str()
, resultData.m_OriginData.m_nContentLength
, resultData.m_OriginData.m_szURI.c_str()
, resultData.m_szTargetHostName.c_str()
, resultData.m_szTargetFileNameHash.c_str()
, resultData.m_OriginData.m_nContentLength
);
}
// 1 개 replication content 에 대한 RCDB insert 작업이 완료된 경우.
// - RCDB clear 처리후
// - queue pop.
rcdb.PgClear();
m_pCompleteQueue->Pop();
}
// queue 에 저장된 정보 처리 작업이 완료된 경우...
// - RCDB 연결 해제 처리.
rcdb.PgClear();
rcdb.PgCloseDB();
return true;
}