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
+421
View File
@@ -0,0 +1,421 @@
#include "CacheOrder.h"
#include <errno.h>
#include <string.h>
#include "Database.h"
#include "Logger.h"
// 처리 loop 간의 sleep time 정의
#define DEFAULT_SLEEP_TIME 3
// RCDB 접속 실패 또는 Query 실패 등의 상황 발생시
#define MAX_SLEEP_TIME 30
// Query 문장 저장을 위한 Buffer 크기
#define DEFAULT_QUERY_BUFFER_SIZE 2048
// 생성자
// param [IN] pQueueCacheRequest Cache 요청 정보 저장 Queue 에 대한 포인터
// param [IN] pListCacheJob Cache 생성 관련 Job List 객체에 대한 포인터
// param [IN] pProperFhs Proper FHS 정보를 저장하는 객체에 대한 포인터
CCacheOrder::CCacheOrder( CDataQueue<CCacheRequestData>* pQueueCacheRequest, CCacheJobList* pCacheJob, CProperFhs * pProperFhs )
: m_pQueueCacheRequest( pQueueCacheRequest )
, m_pCacheJob( pCacheJob )
, m_pProperFhs( pProperFhs )
{
m_threadHandle = 0;
m_uSleep = DEFAULT_SLEEP_TIME;
// NEW 2014-07-07 신규 멤버 변수 초기화 코드 추가.
// Init() 에서 RCDB 접속 실패가 발생 가능하므로.. 구형 RCDB 형상을 사용토록 설정.
m_bServiceTableSeparate = false;
}
// 소멸자
CCacheOrder::~CCacheOrder()
{
// Thread 동작 정지 처리
// - 만약 Thread 가 이미 종료된 경우 m_threadHandle 이 다른 Thread Handle 일 수 있으므로
// 업무 Flow 수정시 주의할 것
if( m_threadHandle != 0 )
pthread_cancel( m_threadHandle );
}
// 객체 초기화 수행
bool CCacheOrder::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, "CCacheOrder: t_dav_resource table exist.[Old RCDB Type]" );
}
else
{
// t_dav_resource 테이블이 존재하지 않는 서비스별 테이블 분리 형상인 경우.
m_bServiceTableSeparate = true;
_LOG( LINF, "CCacheOrder: t_dav_resource table not exist.[New RCDB Type]" );
}
}
// RCDB 조회 결과 set 를 clear 처리 후 RCDB 접속 해제.
rcdb.PgClear();
rcdb.PgCloseDB();
return true;
}
}
// thread를 생성하여 업무 flow 를 시작.
bool CCacheOrder::Start()
{
int nRet = ::pthread_create( &m_threadHandle, 0, CCacheOrder::threadFunc, this );
if( nRet != 0 )
{
// Thread 생성 실패시
int errorNum = errno;
LOG( LERR, "Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
return true;
}
// 스레드 함수
void* CCacheOrder::threadFunc( void* arg )
{
CCacheOrder* pObject = reinterpret_cast<CCacheOrder *>( arg );
pthread_detach( pthread_self() );
while( 1 )
{
pthread_testcancel();
pObject->Execute();
pthread_testcancel();
// 1회 수행 후 지정된 시간 만큼 대기
sleep( pObject->m_uSleep );
}
// NEW 2014-07-07 huibong
// Thread 종료시 m_threadHandle 값을 초기화 처리.
// - 소멸자에서 잘못된 Thread 를 종료할 수 있기 때문.
pObject->m_threadHandle = 0;
return NULL;
}
// 스레드 내에서 각 loop 단위 처리 호출 함수.
void CCacheOrder::Execute()
{
// Request Cache Queue 상에 처리할 Data 가 존재하는 경우.
if( m_pQueueCacheRequest->GetSize() > 0 )
{
bool bResult = PushRequestToJob();
// 처리 결과에 따라 loop sleep time 조정
if( bResult == true )
m_uSleep = DEFAULT_SLEEP_TIME;
else
{
// RCDB 연결 실패, Queury 수행 실패 등의 오류 발생시
m_uSleep = MAX_SLEEP_TIME;
}
}
else
{
// 처리할 Data 가 존재하지 않는 경우.
m_uSleep = DEFAULT_SLEEP_TIME;
}
}
// Cache Requet Queue 에 저장된 요청을 검사하여....
// cache 생성 Job 에 추가하는 기능을 수행
bool CCacheOrder::PushRequestToJob()
{
// RCDB 연결 관련 객체.
// - RCDB 연결은 Job 에 등록가능한 Data 가 존재할 경우에만 수행되도록 한다.
DataBase rcdb;
bool bDbConnected = false; // RCDB 연결 상태 정보 저장 변수
// Queue 에서 Data 를 Pop 한 후
// 해당 정보가 CacheJobList 에 이미 등록된 정보인지 확인
// 미등록 정보인 경우 RCDB 조회를 수행하여
// - Cache 를 수행할 FHS 정보를 선택한 후
// - 해당 Content 정보를 Cache Job 에 등록 처리한다.
// queue 에서 꺼낸 정보를 저장하기 위한 변수
CCacheRequestData requestData;
// Query 문장 저장을 위한 버퍼 생성
char szQuery[DEFAULT_QUERY_BUFFER_SIZE];
// Query 수행 결과값 저장을 위한 변수..
int nResult = 0;
while( m_pQueueCacheRequest->GetSize() > 0 )
{
// queue 에 저장된 첫번째 data 복사 (queue 에서 삭제된 상태 아님)
requestData = m_pQueueCacheRequest->Front();
// 해당 정보를 Job List 에 저장 가능한지 확인
if( m_pCacheJob->IsExist( requestData ) == true )
{
// 이미 동일 정보가 Job List 에 존재하는 경우...
// queue 에서 pop 해서 버림.
_LOG( LINF, "Cache request already exist.[%s]", requestData.m_strFileNameHash.c_str() );
m_pQueueCacheRequest->Pop();
continue;
}
// RCDB 에서 해당 content 에 대한 정보 조회
// DB 연결이 되지 않은 상태인 경우.
// - Queue 항목 중 Job 에 등록해야 하는 항목이 존재할 경우에만 RCDB 연결 목적
if( bDbConnected == false )
{
// 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 접속이 안될때...
// - 현재 Queue 에 저장된 Cache Request 요청을 모두 버리고
// - false 반환하여 특정시간 동안 sleep 되도록 처리.
LOG( LERR, "RCDB connection failed. Cache request all trhow [%u]"
, m_pQueueCacheRequest->GetSize() );
// Queue 요청 모두 삭제 처리
m_pQueueCacheRequest->Init();
return false;
}
else
{
bDbConnected = true;
}
}
// Query 조립
// - 전달받은 filename_hash , content_length, FHS 정보를 이용하여
// - 해당 물리 파일과 연결된 uri 추출 ( uri 를 직접 수신할 경우..대소문자 무시 기능 때문에 조회 불가)
// - 추출된 uri 와 연결된 장비 정보를 조회한다.
// - ORDER BY 조건에 의해 is_cache 값이 N-R-Y 순으로 나타남.
// - COPY 등으로 인해 Query 결과에는 중복된 host_name 이 존재 가능함.
// t_dav_resource 테이블 사용 RCDB 인 경우
if( m_bServiceTableSeparate == false )
{
sprintf( szQuery,
"SELECT host_name, filename_hash, is_cache "
"FROM t_dav_resource "
"WHERE uri IN "
" ( SELECT uri FROM t_dav_resource "
" WHERE filename_hash = '%s' "
" AND host_name = '%s' "
" AND get_content_length = %llu "
" AND deleted_yn = 'N' "
" ) "
" AND get_content_length = %llu "
" AND deleted_yn = 'N' "
"ORDER BY is_cache ASC; "
, requestData.m_strFileNameHash.c_str()
, requestData.m_strRequestHost.c_str()
, requestData.m_uContentLength
, requestData.m_uContentLength
);
}
else
{
// 신형 RCDB 형상인 경우.
sprintf( szQuery,
"SELECT host_name, filename_hash, is_cache "
"FROM t_meta_%s "
"WHERE uri IN "
" ( SELECT uri FROM t_meta_%s "
" WHERE filename_hash = '%s' "
" AND host_name = '%s' "
" AND get_content_length = %llu "
" AND deleted_yn = 'N' "
" ) "
" AND get_content_length = %llu "
" AND deleted_yn = 'N' "
"ORDER BY is_cache ASC; "
, requestData.m_strServiceSeq.c_str()
, requestData.m_strServiceSeq.c_str()
, requestData.m_strFileNameHash.c_str()
, requestData.m_strRequestHost.c_str()
, requestData.m_uContentLength
, requestData.m_uContentLength
);
}
// Query 실행 및 결과 확인
rcdb.PgDoExec( szQuery );
nResult = rcdb.PgResult( DataBase::NOT_CLEAR );
if( nResult < 0 )
{
// RCDB t_dav_resource 테이블 조회 실패시
// - RCDB 연결 실패 또는 Query 실패로 인한 문제 발생 가능.
// - 따라서 RCDB 연결 해제 처리, Queue Pop 처리한 후
// - 루프를 계속 수행처리
LOG( LERR, "RCDB t_dav_resource cache select failed.[%s][%s]"
, rcdb.GetErrorMessage().c_str(), szQuery );
rcdb.PgClear();
rcdb.PgCloseDB();
bDbConnected = false;
m_pQueueCacheRequest->Pop();
continue;
}
// 결과 Row 수 확인.
nResult = rcdb.GetNoTuples();
if( nResult <= 0 )
{
// 해당 Content 가 존재하지 않거나... 오류 발생시.
// - 그냥 버린다.
// - 이로 인해 FHS 에 meta 기준으로 삭제 불가능한 파일이 남게 된다.
_LOG( LINF, "cache request content not found in RCDB.[%d] [%s][%s][%llu]"
, nResult
, requestData.m_strRequestHost.c_str()
, requestData.m_strFileNameHash.c_str()
, requestData.m_uContentLength );
}
else
{
// 결과 Row 수가 존재하는 경우...
CCacheData cacheData;
cacheData.m_requestData = requestData;
// 결과 정보 중.. Request 요청을 보낸 장비가 아닌 FHS 을 Cache 생성 원본으로 선택
// - order by 조건에 의해 is_cache 가 N-R-Y 순으로 장비 정보가 나타나므로...
// - 원본, 복제본, cache 본 순으로 사용될 순서가 정해짐.
for( int i = 0; i < nResult; ++i )
{
// host name 이 같지 않은 경우.
if( strcasecmp( rcdb.GetValue( i, 0 ), requestData.m_strRequestHost.c_str() ) != 0 )
{
cacheData.m_strSourceHost = rcdb.GetValue( i, 0 );
cacheData.m_strSourceFilenameHash = rcdb.GetValue( i, 1 );
// source 로 사용할 첫번째 장비를 찾은 경우...
// - 더 이상 루프는 의미가 없으므로..
break;
}
}
// 만약 원본 1개만 존재하는 경우...
// - 그냥 요청 정보를 그대로 사용.
if( cacheData.m_strSourceHost.empty() == true )
{
cacheData.m_strSourceHost = requestData.m_strRequestHost;
cacheData.m_strSourceFilenameHash = requestData.m_strFileNameHash;
}
// ignore FHS list 구성
// - 빠른 처리를 위해 조회 결과 처리시 중복 host_name 정보를 제거한다.
std::list<std::string> ignoreFhsList;
std::string strTemp;
for( int j = 0; j < nResult; ++j )
{
strTemp = rcdb.GetValue( j, 0 );
ignoreFhsList.push_back( strTemp );
}
// 중복 제거 ( sort() 후 unique() 함수 호출해야 중복 제거 가능 )
ignoreFhsList.sort();
ignoreFhsList.unique();
// Target FHS 선정 처리
std::vector<std::string> vecProperFhs;
if( m_pProperFhs->GetProperFhs( 1, vecProperFhs, ignoreFhsList ) == false )
{
// Proper FHS 선택 실패시...
// 해당 요청을 그냥 버린다...
_LOG( LWAR, "cache request not found proper fhs. throw.[%s][%s][%llu]"
, requestData.m_strRequestHost.c_str()
, requestData.m_strFileNameHash.c_str()
, requestData.m_uContentLength );
}
else
{
// Proper FHS 선택 성공시..
// - 해당 정보를 CacheData 에 입력한 후...
// - Job 으로 등록 처리
cacheData.m_strTargetHost = vecProperFhs.front();
m_pCacheJob->Register( cacheData );
}
}
// Queue Pop 처리 후
// 다음 Query 사용을 대비하여 결과 set clear 처리.
m_pQueueCacheRequest->Pop();
rcdb.PgClear();
}
// RCDB 연결이 되어 있는 경우.. 종료 처리
if( bDbConnected == true )
{
rcdb.PgClear();
rcdb.PgCloseDB();
}
return true;
}