369 lines
9.5 KiB
C++
369 lines
9.5 KiB
C++
#include "CacheDelete.h"
|
|
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
|
|
#include "Logger.h"
|
|
#include "Database.h"
|
|
#include "Util.h"
|
|
#include "ServiceConfig.h"
|
|
|
|
|
|
// Query 문장 저장을 위한 Buffer 크기
|
|
#define DEFAULT_QUERY_BUFFER_SIZE 512
|
|
|
|
// sec 를 micro-sec 로 단위 변환시 환산 계수.
|
|
#define SEC_TO_MICROSEC (1000000LL)
|
|
|
|
// 삭제 작업시 시작 시간을 설정하기 위한 보정값.
|
|
#define CACHE_DELETE_RANGE (60*60*48) // 48시간
|
|
|
|
// 삭제 주기 ( sec 단위)
|
|
#define CAHCE_DEL_CHECK_TERM_SEC (20 * 60) // 20분
|
|
|
|
|
|
// 생성자
|
|
CCacheDelete::CCacheDelete()
|
|
{
|
|
m_threadHandle = 0;
|
|
|
|
// NEW 2014-06-16 신규 멤버 변수 초기화 코드 추가.
|
|
// Init() 에서 RCDB 접속 실패가 발생 가능하므로.. 구형 RCDB 형상을 사용토록 설정.
|
|
m_bServiceTableSeparate = false;
|
|
}
|
|
|
|
// 소멸자
|
|
CCacheDelete::~CCacheDelete()
|
|
{
|
|
// Thread 동작 정지 처리
|
|
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 이 다른 Thread Handle 일 수 있으므로
|
|
// 업무 Flow 수정시 주의할 것
|
|
if( m_threadHandle != 0 )
|
|
pthread_cancel( m_threadHandle );
|
|
}
|
|
|
|
// 객체 초기화 수행
|
|
bool CCacheDelete::Init()
|
|
{
|
|
// 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-23 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, "CCacheDelete: t_dav_resource table exist.[Old RCDB Type]" );
|
|
}
|
|
else
|
|
{
|
|
// t_dav_resource 테이블이 존재하지 않는 서비스별 테이블 분리 형상인 경우.
|
|
m_bServiceTableSeparate = true;
|
|
_LOG( LINF, "CCacheDelete: t_dav_resource table not exist.[New RCDB Type]" );
|
|
}
|
|
}
|
|
|
|
// RCDB 조회 결과 set 를 clear 처리 후 RCDB 접속 해제.
|
|
rcdb.PgClear();
|
|
rcdb.PgCloseDB();
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// thread를 생성하여 업무 flow 를 시작.
|
|
bool CCacheDelete::Start()
|
|
{
|
|
int nRet = ::pthread_create( &m_threadHandle, NULL, CCacheDelete::threadFunc, this );
|
|
if( nRet != 0 )
|
|
{
|
|
// Thread 생성 실패시
|
|
int errorNum = errno;
|
|
LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void * CCacheDelete::threadFunc( void * arg )
|
|
{
|
|
CCacheDelete* pObject = reinterpret_cast<CCacheDelete *>( arg );
|
|
pthread_detach( pthread_self() );
|
|
|
|
while( 1 )
|
|
{
|
|
pthread_testcancel();
|
|
pObject->Execute();
|
|
pthread_testcancel();
|
|
|
|
sleep( CAHCE_DEL_CHECK_TERM_SEC );
|
|
}
|
|
|
|
// NEW 2014-06-23 huibong
|
|
// Thread 종료시 m_threadHandle 값을 초기화 처리.
|
|
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
|
|
pObject->m_threadHandle = 0;
|
|
|
|
// CHG 2014-06-23 huibong
|
|
// detach 된 Thread 에 대해 pthread_exit() 호출시
|
|
// 기준 할당 자원에 대한 해지 처리가 되지 않아 메모리 누수 발생 가능( FreeBSD ftsd 발생)
|
|
// 따라서 이를 해결하기 detach 된 thread 에 대해 pthread_exit() 호출 코드 제거.
|
|
//pthread_exit(NULL);
|
|
return NULL;
|
|
}
|
|
|
|
// 스레드 내에서 각 loop 단위 처리 호출 함수.
|
|
void CCacheDelete::Execute()
|
|
{
|
|
// 구형 t_dav_resource 테이블 사용시
|
|
if( m_bServiceTableSeparate == false )
|
|
{
|
|
DeleteFromOldDB();
|
|
}
|
|
else
|
|
{
|
|
// 신형 RCDB 형상 사용시
|
|
DeleteFromDB();
|
|
}
|
|
}
|
|
|
|
|
|
// RCDB t_dav_resource 테이블에서 유효기간이 지난 Hot Content Cache Content 를 삭제 처리
|
|
// - 구형 RCDB 지원 목적
|
|
bool CCacheDelete::DeleteFromOldDB()
|
|
{
|
|
// 1. 현재 시간정보를 구한다.( micro-second 단위)
|
|
long long timeNow = longtime_now();
|
|
if( timeNow < 0 )
|
|
{
|
|
LOG( LERR, "longtime_now function error [%lld]", timeNow );
|
|
return false;
|
|
}
|
|
|
|
// 2. 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;
|
|
}
|
|
|
|
// 3. t_dav_resource 테이블에서 유효기간이 지난 Cache Content 를 삭제 상태로 update 처리
|
|
|
|
// Query 문장 저장을 위한 버퍼 생성
|
|
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
|
|
int nResult = 0;
|
|
|
|
// 처리 대상 시간 구간 계산 (micro-second 단위 )
|
|
long long timeStart;
|
|
long long timeEnd;
|
|
|
|
// 현재시간 기준으로 Hot Content Cache 의 보존 만료 시간을 계산.
|
|
timeEnd = timeNow - ( CServiceConfig::GetInstance()->GetCacheFileTimeout() * SEC_TO_MICROSEC );
|
|
|
|
// 조회 시작 시간을 계산.
|
|
// - 본 값이 없을 경우... RCDB를 Full Scan 해야 하므로.. RCDB 에 부하 발생 가능.
|
|
// - 따라서 보존 만료 시간 이전 48 시간 정도로 조회 범위를 감소시킨다.
|
|
timeStart = timeNow - ( ( CServiceConfig::GetInstance()->GetCacheFileTimeout() + CACHE_DELETE_RANGE ) * SEC_TO_MICROSEC );
|
|
|
|
snprintf(szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
|
|
"UPDATE t_dav_resource SET deleted_yn = 'Y' ,get_lastmodified = %lld "
|
|
"WHERE is_cache = 'Y' AND deleted_yn = 'N' "
|
|
"AND get_lastmodified >= '%lld' "
|
|
"AND get_lastmodified <= '%lld';"
|
|
, timeNow, timeStart, timeEnd
|
|
);
|
|
|
|
// Query 실행
|
|
rcdb.PgDoExec(szQuery);
|
|
|
|
// Update 처리 결과 Row 수 확인.
|
|
nResult = rcdb.GetCmdTuples();
|
|
|
|
if( nResult > 0 )
|
|
{
|
|
_LOG( LINF, "CCacheDelete: t_dav_resource delete count[%d]", nResult );
|
|
}
|
|
|
|
rcdb.PgClear();
|
|
rcdb.PgCloseDB();
|
|
|
|
return true;
|
|
}
|
|
|
|
// RCDB t_meta_xxx 테이블에서 유효기간이 지난 Hot Content Cache Content 를 삭제 처리
|
|
// - 신형 RCDB 지원 목적
|
|
bool CCacheDelete::DeleteFromDB()
|
|
{
|
|
// 1. 현재 시간정보를 구한다.( micro-second 단위)
|
|
long long timeNow = longtime_now();
|
|
if( timeNow < 0 )
|
|
{
|
|
LOG( LERR, "longtime_now function error [%lld]", timeNow );
|
|
return false;
|
|
}
|
|
|
|
// 2. 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;
|
|
}
|
|
|
|
// Query 문장 저장을 위한 버퍼 생성
|
|
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
|
|
int nResult = 0;
|
|
|
|
|
|
// 3. RCDB 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 DESC "
|
|
);
|
|
|
|
// Query 실행
|
|
rcdb.PgDoExec( szQuery );
|
|
nResult = rcdb.PgResult( DataBase::NOT_CLEAR );
|
|
if( nResult < 0 )
|
|
{
|
|
// Query 오류 발생시
|
|
// - RCDB 연결 실패 또는
|
|
// - t_sms_sp_svc_product 테이블이 존재하지 않을 경우.
|
|
LOG( LERR, "RCDB t_sms_sp_svc_product query error.[%s][%s]"
|
|
, rcdb.GetErrorMessage().c_str(), szQuery );
|
|
|
|
rcdb.PgClear();
|
|
rcdb.PgCloseDB();
|
|
|
|
return false;
|
|
}
|
|
|
|
// 조회된 각 고객사 정보 확인
|
|
nResult = rcdb.GetNoTuples();
|
|
if( nResult <= 0 )
|
|
{
|
|
// 고객사가 존재하지 않는 경우
|
|
_LOG( LINF, "CCacheDelete: service not found from t_sms_sp_svc_product.[%d]"
|
|
, nResult );
|
|
|
|
rcdb.PgClear();
|
|
rcdb.PgCloseDB();
|
|
return true;
|
|
}
|
|
|
|
// 조회된 고객사 정보를 변수에 저장.
|
|
std::vector<std::string> vecService;
|
|
std::string strTemp;
|
|
for( int i = 0; i < nResult; i++ )
|
|
{
|
|
strTemp = rcdb.GetValue( i, 0 );
|
|
if( strTemp.size() > 0 )
|
|
vecService.push_back( strTemp );
|
|
}
|
|
|
|
rcdb.PgClear();
|
|
|
|
// 변수에 저장된 서비스 정보의 수를 최종 확인
|
|
if( vecService.empty() == true )
|
|
{
|
|
// 유효한 서비스 정보가 존재하지 않는 경우.
|
|
_LOG( LINF, "CCacheDelete: service not found from t_sms_sp_svc_product." );
|
|
rcdb.PgCloseDB();
|
|
return true;
|
|
}
|
|
|
|
// 4. 루프를 돌면서
|
|
// 각 서비스별 t_meta_xx 테이블에서 유효기간이 지난 Cache Content 를 삭제 상태로 update 처리
|
|
|
|
// 처리 대상 시간 구간 계산 (micro-second 단위 )
|
|
long long timeStart;
|
|
long long timeEnd;
|
|
|
|
// 현재시간 기준으로 Hot Content Cache 의 보존 만료 시간을 계산.
|
|
timeEnd = timeNow - ( CServiceConfig::GetInstance()->GetCacheFileTimeout() * SEC_TO_MICROSEC );
|
|
|
|
// 조회 시작 시간을 계산.
|
|
// - 본 값이 없을 경우... RCDB를 Full Scan 해야 하므로.. RCDB 에 부하 발생 가능.
|
|
// - 따라서 보존 만료 시간 이전 48 시간 정도로 조회 범위를 감소시킨다.
|
|
timeStart = timeNow - ( ( CServiceConfig::GetInstance()->GetCacheFileTimeout() + CACHE_DELETE_RANGE ) * SEC_TO_MICROSEC );
|
|
|
|
std::vector< std::string >::const_iterator it;
|
|
for( it = vecService.begin(); it != vecService.end(); ++it )
|
|
{
|
|
snprintf( szQuery, DEFAULT_QUERY_BUFFER_SIZE - 1,
|
|
"UPDATE t_meta_%s SET deleted_yn = 'Y' ,get_lastmodified = %lld "
|
|
"WHERE is_cache = 'Y' AND deleted_yn = 'N' "
|
|
"AND get_lastmodified >= '%lld' "
|
|
"AND get_lastmodified <= '%lld';"
|
|
, it->c_str()
|
|
, timeNow, timeStart, timeEnd
|
|
);
|
|
|
|
// Query 실행
|
|
rcdb.PgDoExec( szQuery );
|
|
|
|
// Update 처리 결과 Row 수 확인.
|
|
nResult = rcdb.GetCmdTuples();
|
|
if( nResult > 0 )
|
|
{
|
|
_LOG( LINF, "CCacheDelete: t_meta_%s delete count[%d]", it->c_str(), nResult );
|
|
}
|
|
|
|
rcdb.PgClear();
|
|
}
|
|
|
|
// 작업이 완료된 경우... RCDB 연결 해제.
|
|
rcdb.PgClear();
|
|
rcdb.PgCloseDB();
|
|
|
|
return true;
|
|
}
|