base
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user