base
This commit is contained in:
@@ -0,0 +1,552 @@
|
||||
#include "MetaCopy.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "RcdbInfo.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
|
||||
#define SQLITE_DB_LOCK_TIMEOUT 1000 // SQLITE_BUSY 상황 발생 문제 해결을 위해 DB Lock 관련 timeout 설정값. (1 sec)
|
||||
#define SQLITE_DB_LOCK_MAX_RETRY 60 // SQLITE_BUSY 발생시 재시도 최대 횟수
|
||||
|
||||
|
||||
// Query 문장 저장을 위한 Buffer 크기
|
||||
#define DEFAULT_QUERY_BUFFER_SIZE 2048
|
||||
|
||||
|
||||
// 생성자
|
||||
// - pLocalDb : sqlite memory db 객체에 대한 포인트
|
||||
CMetaCopy::CMetaCopy( sqlite3 * pLocalDb )
|
||||
: m_pLocalStmt(NULL)
|
||||
{
|
||||
m_pLocalDb = pLocalDb;
|
||||
|
||||
m_ullTotalSelectCount = 0;
|
||||
}
|
||||
|
||||
|
||||
// 소멸자
|
||||
CMetaCopy::~CMetaCopy()
|
||||
{
|
||||
// RCDB 와 연결 해제 처리.
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
// Local DB stmt clear 처리.
|
||||
// - local db 객체는 memory db 로서 전역 객체이므로.. close 하지 않는다.
|
||||
if( m_pLocalStmt != NULL )
|
||||
{
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 객체 초기화 함수
|
||||
// - RCDB 와 연결 생성
|
||||
// - sqlite local memory db 관련 table, index 생성 및 insert stmt 생성 처리.
|
||||
bool CMetaCopy::Init()
|
||||
{
|
||||
// RCDB 접속 정보 저장 관련 객체 생성 및 초기화...
|
||||
CRcdbInfo rcdbInfo;
|
||||
rcdbInfo.Load();
|
||||
|
||||
// sqlite 를 이용하여 local 장비에 저장 목적 file DB 생성 처리 및 세션 연결.
|
||||
if( CreateLocalDb() == false )
|
||||
return false;
|
||||
|
||||
// RCDB 와 연결 생성.
|
||||
if( m_rcdb.PgOpenDB( rcdbInfo.m_strRcdbIp, rcdbInfo.m_nRcdbPort, rcdbInfo.m_strRcdbName, rcdbInfo.m_strRcdbAcct, rcdbInfo.m_strRcdbAcctPw ) == NULL )
|
||||
{
|
||||
// 연결 실패시...
|
||||
LOG( LERR, "RCDB connection failed." );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LINF, "RCDB connection success." );
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// sqlite 를 이용하여 local db 생성 작업을 수행.
|
||||
bool CMetaCopy::CreateLocalDb()
|
||||
{
|
||||
|
||||
// sqlite local memory db 객체는 Main 모듈에서 생성 했으므로...
|
||||
// 그 외 작업을 수행한다.
|
||||
|
||||
// 1. local db 상에 관련 table 생성 작업 수행 처리.
|
||||
int nResult = 0;
|
||||
std::string strQuery;
|
||||
strQuery = "CREATE TABLE meta( resource_id integer, filename_hash text, get_content_length integer, deleted_yn text )";
|
||||
|
||||
char * pStrDbError;
|
||||
int nRetryCount = 0;
|
||||
|
||||
nResult = sqlite3_exec( m_pLocalDb, strQuery.c_str(), NULL, NULL, &pStrDbError );
|
||||
|
||||
while( nResult == SQLITE_BUSY && nRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_free( pStrDbError );
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nRetryCount;
|
||||
|
||||
_LOG( LWAR, "Local db table create SQLITE_BUSY. Retry[%d]", nRetryCount );
|
||||
|
||||
nResult = sqlite3_exec( m_pLocalDb, strQuery.c_str(), NULL, NULL, &pStrDbError );
|
||||
}
|
||||
|
||||
// Table Create Query 가 최종 실패한 경우....
|
||||
if( nResult != SQLITE_OK )
|
||||
{
|
||||
LOG( LERR, "sqlite3 table create failed. [%d][%s]", nResult, pStrDbError );
|
||||
|
||||
sqlite3_free( pStrDbError );
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LINF, "Local db table create success.");
|
||||
}
|
||||
|
||||
// 2. garbage clean 시 select 속도 향상을 위한 Index 생성
|
||||
if( CProcessConfig::GetInstance()->IsRunGarbageClean() == true )
|
||||
{
|
||||
strQuery = "CREATE INDEX index_filename_hash ON meta( filename_hash ) ;";
|
||||
nResult = sqlite3_exec( m_pLocalDb, strQuery.c_str(), NULL, NULL, &pStrDbError );
|
||||
|
||||
while( nResult == SQLITE_BUSY && nRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_free( pStrDbError );
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nRetryCount;
|
||||
|
||||
_LOG( LWAR, "Local db index create SQLITE_BUSY. Retry[%d]", nRetryCount );
|
||||
|
||||
nResult = sqlite3_exec( m_pLocalDb, strQuery.c_str(), NULL, NULL, &pStrDbError );
|
||||
}
|
||||
|
||||
// Index Create Query 가 최종 실패한 경우....
|
||||
if( nResult != SQLITE_OK )
|
||||
{
|
||||
LOG( LERR, "sqlite3 index create failed. [%d][%s]", nResult, pStrDbError );
|
||||
|
||||
sqlite3_free( pStrDbError );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LINF, "Local db index create success." );
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Meta 정보 조회 결과를 local db 에 저장 처리시 사용할 prepared 객체에 대한 초기화 수행.
|
||||
// - prepared sql 을 사용해야... insert 속도가 향상됨.
|
||||
strQuery = "INSERT INTO meta( resource_id, filename_hash, get_content_length, deleted_yn ) VALUES ( ?, ?, ?, ? );";
|
||||
|
||||
nResult = sqlite3_prepare( m_pLocalDb, strQuery.c_str(), strQuery.size(), &m_pLocalStmt, NULL );
|
||||
|
||||
// sqlite3_prepare() 함수 실행시 SQLITE_BUSY 오류가 발생할 수 있으므로.. 재시도 로직을 추가한다.
|
||||
while( nResult == SQLITE_BUSY && nRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nRetryCount;
|
||||
|
||||
_LOG( LWAR, "Local db prepare sql SQLITE_BUSY. Retry[%d]", nRetryCount );
|
||||
|
||||
nResult = sqlite3_prepare( m_pLocalDb, strQuery.c_str(), strQuery.size(), &m_pLocalStmt, NULL );
|
||||
}
|
||||
|
||||
// 최종 실패시...
|
||||
if( nResult != SQLITE_OK )
|
||||
{
|
||||
LOG( LERR, "sqlite3 prepare sql stmt create failed. [%d][%s]", nResult, sqlite3_errmsg(m_pLocalDb) );
|
||||
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CMetaCopy::Start()
|
||||
{
|
||||
// 작업 소요 시간 정보 계산을 위한 변수.
|
||||
// - 시간 동기화로 인한 문제를 해결하기 위해 clock_gettime() 함수 사용.
|
||||
struct timespec timeStart;
|
||||
struct timespec timeEnd;
|
||||
double dTimeInterval = 0.0;
|
||||
|
||||
memset( &timeStart, 0x00, sizeof( struct timespec ) );
|
||||
memset( &timeEnd, 0x00, sizeof( struct timespec ) );
|
||||
|
||||
|
||||
// 작업 시작 로깅 및 시작 시간 정보 추출.
|
||||
_LOG( LINF, "Meta copy start.");
|
||||
clock_gettime( CLOCK_MONOTONIC, &timeStart );
|
||||
|
||||
|
||||
// Query 문장 저장을 위한 버퍼 생성
|
||||
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
|
||||
|
||||
// RCDB Query 수행 결과값 저장을 위한 변수..
|
||||
int nResult = 0;
|
||||
|
||||
|
||||
// 1. t_sms_sp_svc_product 에서 각 고객사 정보를 가져온다.
|
||||
snprintf( szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
|
||||
"SELECT sp_svc_tran_id FROM t_sms_sp_svc_product ORDER BY sp_svc_tran_id ASC;");
|
||||
|
||||
// Query 실행
|
||||
m_rcdb.PgDoExec( szQuery );
|
||||
nResult = m_rcdb.PgResult( DataBase::NOT_CLEAR );
|
||||
if( nResult < 0 )
|
||||
{
|
||||
// t_sms_sp_svc_product 테이블 조회시 오류가 발생한 경우...
|
||||
// - 해당 table 또는 sp_svc_tran_id 컬럼 존재 안할 경우..
|
||||
LOG( LERR, "RCDB t_sms_sp_svc_product table select failed. [%s][%s]", m_rcdb.GetErrorMessage().c_str(), szQuery );
|
||||
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 조회된 각 고객사 정보 확인
|
||||
nResult = m_rcdb.GetNoTuples();
|
||||
if( nResult <= 0 )
|
||||
{
|
||||
// 작업을 수행할 고객사 정보가 RCDB 에 존재하지 않는 경우...
|
||||
// - 고객사가 존재하지 않는 빈깡통 RCDB 인 경우.. 오류일 가능성이 많으므로.. 오류 처리.
|
||||
LOG( LERR, "RCDB t_sms_sp_svc_product table empty. Not found service. Check." );
|
||||
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 루프를 돌면서.. 고객사 정보를 저장 처리.
|
||||
std::vector<std::string> vecService;
|
||||
std::string strTemp;
|
||||
for( int i = 0; i < nResult; i++ )
|
||||
{
|
||||
strTemp = m_rcdb.GetValue( i, 0 );
|
||||
if( strTemp.size() > 0 )
|
||||
vecService.push_back( strTemp );
|
||||
}
|
||||
|
||||
// Query Resultset Clear.
|
||||
m_rcdb.PgClear();
|
||||
|
||||
// 변수에 저장된 서비스 정보의 수를 최종 확인
|
||||
if( vecService.empty() == true )
|
||||
{
|
||||
LOG( LERR, "RCDB t_sms_sp_svc_product table not empty. but valid service not found. Check." );
|
||||
|
||||
m_rcdb.PgCloseDB();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 사용자가 작업대상 경로를 지정한 경우...
|
||||
// /stg/node0
|
||||
// - t_sms_sp_svc_product 테이블을 조회하여 서비스 목록 추출해야 함.
|
||||
// /stg/node0/346
|
||||
// - 서비스 폴더를 지정했으므로.... 다른 서비스 table 까지 불필요하게 조회할 필요 없음.
|
||||
// - 따라서.. t_sms_sp_svc_product 조회 결과에서
|
||||
// - 사용자가 지정한 서비스 seq 가 존재하는 경우.... 해당 table 만 조회하도록 처리.
|
||||
// - 사용자가 지정한 서비스 seq 가 존재하지 않는 경우... 서비스 폴더가 아닐 수 있으므로.. 전체 조회 처리.
|
||||
|
||||
|
||||
std::vector< std::string >::const_iterator it;
|
||||
|
||||
// 사용자가 작업 대상 경로를 지정한 경우...
|
||||
if( CProcessConfig::GetInstance()->IsUserDefineJobRoot() == true )
|
||||
{
|
||||
strTemp = CProcessConfig::GetInstance()->GetJobRoot();
|
||||
|
||||
// 맨 끝의 폴더명만을 추출.
|
||||
string::size_type pos = strTemp.rfind( '/' );
|
||||
if( pos != string::npos )
|
||||
{
|
||||
// 경로의 마지막 문자열 정보 추출.
|
||||
std::string strSvcSeq = strTemp.substr( pos + 1 );
|
||||
|
||||
// vecService 목록에 추출된 정보가 존재하는지 확인.
|
||||
bool bFound = false;
|
||||
for( it = vecService.begin(); it != vecService.end(); ++it )
|
||||
{
|
||||
if( strcmp( it->c_str(), strSvcSeq.c_str() ) == 0 )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( bFound == true )
|
||||
{
|
||||
// 기존 RCDB 에서 추출된 정보 삭제
|
||||
vecService.clear();
|
||||
|
||||
// 사용자가 지정한 서비스 seq 만 조회되도록 처리.
|
||||
vecService.push_back( strSvcSeq );
|
||||
|
||||
_LOG( LINF, "meta copy : user path set [%s]. meta select only service [%s]", CProcessConfig::GetInstance()->GetJobRoot(), strSvcSeq.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 2. 사용자 지정 옵션에 따른 조회 구문을 설정 처리한다.
|
||||
char szWhere[DEFAULT_QUERY_BUFFER_SIZE];
|
||||
memset( szWhere, 0x00, sizeof( szWhere ) );
|
||||
|
||||
// directory 는 빼고 파일만 조회.
|
||||
strcat( szWhere, "AND resource_type = 0 " );
|
||||
|
||||
// integrity check 만 수행할 경우...
|
||||
// - 삭제된 content 는 조회하지 않는다.
|
||||
if( CProcessConfig::GetInstance()->IsRunIntegrityCheck() == true && CProcessConfig::GetInstance()->IsRunGarbageClean() == false )
|
||||
{
|
||||
strcat( szWhere, "AND deleted_yn = 'N' " );
|
||||
}
|
||||
|
||||
// 사용자가 작업 대상 경로를 지정한 경우...
|
||||
if( CProcessConfig::GetInstance()->IsUserDefineJobRoot() == true )
|
||||
{
|
||||
char tempBuffer[DEFAULT_QUERY_BUFFER_SIZE];
|
||||
|
||||
snprintf( tempBuffer, DEFAULT_QUERY_BUFFER_SIZE - 1,
|
||||
"AND filename_hash LIKE '%s/%%' "
|
||||
, CProcessConfig::GetInstance()->GetJobRoot() );
|
||||
|
||||
strcat( szWhere, tempBuffer );
|
||||
}
|
||||
|
||||
strcat( szWhere, " ;" );
|
||||
|
||||
// Local sqlite db 관련 변수
|
||||
int nLocalDbResult = 0;
|
||||
int nLocalRetryCount = 0;
|
||||
|
||||
|
||||
// 3. 루프를 돌면서
|
||||
// 각 서비스별 t_meta_xx 테이블에서 content 정보를 조회한다.
|
||||
//std::vector< std::string >::const_iterator it;
|
||||
for( it = vecService.begin(); it != vecService.end(); ++it )
|
||||
{
|
||||
_LOG( LINF, "Service [%s] meta copy start.", it->c_str() );
|
||||
|
||||
snprintf( szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
|
||||
"SELECT resource_id, filename_hash, get_content_length, deleted_yn FROM t_meta_%s "
|
||||
"WHERE host_name = '%s' %s"
|
||||
, it->c_str()
|
||||
, CProcessConfig::GetInstance()->GetHostname()
|
||||
, szWhere );
|
||||
|
||||
|
||||
// Query 실행
|
||||
m_rcdb.PgDoExec( szQuery );
|
||||
nResult = m_rcdb.PgResult( DataBase::NOT_CLEAR );
|
||||
if( nResult < 0 )
|
||||
{
|
||||
// t_meta_xxx 테이블 조회시 오류가 발생한 경우...
|
||||
LOG( LERR, "RCDB t_meta_%s table select failed. [%s][%s]", it->c_str(), m_rcdb.GetErrorMessage().c_str(), szQuery );
|
||||
|
||||
// local db stmt clear 처리.
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
// RCDB 연결 해제 처리.
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 조회된 row 정보 확인
|
||||
nResult = m_rcdb.GetNoTuples();
|
||||
if( nResult <= 0 )
|
||||
{
|
||||
// 작업 대상 content 가 존재하지 않는 경우....
|
||||
_LOG( LINF, "Service [%s] meta content not exist.", it->c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// sqlite 의 insert 속도 향상을 위해.. begin - commit 구문 사용....
|
||||
// 본 구문을 사용하지 않을 경우.. 초당 180 건 정도 insert 처리됨.
|
||||
nLocalDbResult= sqlite3_exec( m_pLocalDb, "BEGIN;", NULL, NULL, NULL );
|
||||
nLocalRetryCount = 0;
|
||||
|
||||
while( nLocalDbResult == SQLITE_BUSY && nLocalRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nLocalRetryCount;
|
||||
|
||||
_LOG( LWAR, "Local db BEGIN query SQLITE_BUSY. Retry[%d]", nLocalRetryCount );
|
||||
|
||||
nLocalDbResult = sqlite3_exec( m_pLocalDb, "BEGIN;", NULL, NULL, NULL );
|
||||
}
|
||||
|
||||
// 최종 실패시....
|
||||
if( nLocalDbResult != SQLITE_OK )
|
||||
{
|
||||
LOG( LERR, "sqlite3 BEGIN query failed. [%d][%s]", nLocalDbResult, sqlite3_errmsg( m_pLocalDb ) );
|
||||
|
||||
// local db stmt clear 처리.
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
// RCDB 연결 해제 처리.
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 루프를 돌면서 조회된 content 를 local db 에 저장 처리.
|
||||
for( int i = 0; i < nResult; i++ )
|
||||
{
|
||||
// local table 생성 Query
|
||||
// strQuery = "CREATE TABLE meta( resource_id integer, filename_hash text, get_content_length integer, deleted_yn text )";
|
||||
|
||||
// 조회 Query
|
||||
// "SELECT resource_id, filename_hash, get_content_length, deleted_yn FROM t_meta_%s "
|
||||
|
||||
// insert query 에 변수 bind 처리. ( bind 값을 1부터 시작 )
|
||||
// resource_id
|
||||
sqlite3_bind_text( m_pLocalStmt, 1, m_rcdb.GetValue( i, 0 ), strlen( m_rcdb.GetValue( i, 0 ) ), SQLITE_STATIC );
|
||||
|
||||
// filename_hash
|
||||
sqlite3_bind_text( m_pLocalStmt, 2, m_rcdb.GetValue( i, 1 ), strlen( m_rcdb.GetValue( i, 1 ) ), SQLITE_STATIC );
|
||||
|
||||
// get_content_length
|
||||
sqlite3_bind_text( m_pLocalStmt, 3, m_rcdb.GetValue( i, 2 ), strlen( m_rcdb.GetValue( i, 2 ) ), SQLITE_STATIC );
|
||||
|
||||
// deleted_yn
|
||||
sqlite3_bind_text( m_pLocalStmt, 4, m_rcdb.GetValue( i, 3 ), strlen( m_rcdb.GetValue( i, 3 ) ), SQLITE_STATIC );
|
||||
|
||||
// insert query 수행.
|
||||
nLocalDbResult = sqlite3_step( m_pLocalStmt );
|
||||
nLocalRetryCount = 0;
|
||||
|
||||
|
||||
// 만약 BUSY 상태로 인해 오류가 발생하면..지정된 횟수 만큼 재시도
|
||||
while( nLocalDbResult == SQLITE_BUSY && nLocalRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nLocalRetryCount;
|
||||
|
||||
_LOG( LWAR, "Meta insert to local db. SQLITE_BUSY. Retry[%d]", nLocalRetryCount );
|
||||
|
||||
// query 재시도
|
||||
nLocalDbResult = sqlite3_step( m_pLocalStmt );
|
||||
}
|
||||
|
||||
|
||||
if( nLocalDbResult != SQLITE_DONE )
|
||||
{
|
||||
// INSERT 실패 발생시...
|
||||
LOG( LERR, "sqlite3 insert step error. [%d][%s]", nLocalDbResult, sqlite3_errmsg( m_pLocalDb ) );
|
||||
|
||||
// local db stmt clear 처리.
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
// RCDB 와의 연결까지 clear 처리한다.
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Query 수행된 경우.. prepared 문을 재사용하기 위해 reset 처리한다.
|
||||
sqlite3_reset( m_pLocalStmt );
|
||||
}
|
||||
|
||||
} // for
|
||||
|
||||
// sqlite 의 insert 속도 향상을 위해.. begin - commit 구문 사용....
|
||||
// 본 구문을 사용하지 않을 경우.. 초당 180 건 정도 insert 처리됨.
|
||||
nLocalDbResult = sqlite3_exec( m_pLocalDb, "COMMIT;", NULL, NULL, NULL );
|
||||
nLocalRetryCount = 0;
|
||||
|
||||
while( nLocalDbResult == SQLITE_BUSY && nLocalRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nLocalRetryCount;
|
||||
|
||||
_LOG( LWAR, "Local db COMMIT query SQLITE_BUSY. Retry[%d]", nLocalRetryCount );
|
||||
|
||||
nLocalDbResult = sqlite3_exec( m_pLocalDb, "COMMIT;", NULL, NULL, NULL );
|
||||
}
|
||||
|
||||
// 최종 실패시....
|
||||
if( nLocalDbResult != SQLITE_OK )
|
||||
{
|
||||
LOG( LERR, "sqlite3 COMMIT query failed. [%d][%s]", nLocalDbResult, sqlite3_errmsg( m_pLocalDb ) );
|
||||
|
||||
// local db stmt clear 처리.
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
// RCDB 연결 해제 처리.
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Query Resultset Clear.
|
||||
m_rcdb.PgClear();
|
||||
|
||||
|
||||
// 최종 통계 처리를 위해 누적 처리.
|
||||
m_ullTotalSelectCount += nResult;
|
||||
|
||||
_LOG( LINF, "Service [%s] meta count [%d] copy end.", it->c_str(), nResult );
|
||||
|
||||
} // for
|
||||
|
||||
|
||||
// 작업 완료 후... RCDB 와의 연결을 종료 처리한다.
|
||||
m_rcdb.PgClear();
|
||||
m_rcdb.PgCloseDB();
|
||||
|
||||
// 작업 완료 후 Local DB stmt 객체 clear 처리한다.
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
// 작업 완료시 시간 정보 추출 후 소요시간 계산.
|
||||
clock_gettime( CLOCK_MONOTONIC, &timeEnd );
|
||||
|
||||
dTimeInterval = timeEnd.tv_sec - timeStart.tv_sec;
|
||||
dTimeInterval += ( timeEnd.tv_nsec - timeStart.tv_nsec ) * 1e-9;
|
||||
|
||||
// memory db 사용으로 인해
|
||||
// sqlite3_memory_used() 함수를 사용하여 memory 사용량을 로깅하려 했으나..
|
||||
// FreeBSD 6.X 에 설치되는 sqlite 3.4.1 버전에서 sqlite3_memory_used, sqlite3_status 등의 함수를 지원 안함.
|
||||
// 이로 인해 적용 불가함.
|
||||
|
||||
_LOG( LINF, "Meta copy complete. path[%s] total count[%llu], elapsed time: %.1lf sec."
|
||||
, CProcessConfig::GetInstance()->GetJobRoot(), m_ullTotalSelectCount, dTimeInterval );
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user