Files
2026-08-07 17:38:18 +09:00

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;
}