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
@@ -0,0 +1,359 @@
// CHG 2020-11-09 huibong FreeBSD 12.2 컴파일시 오류 발생 관련 header 추가 (#33297)
// - unlink(), sleep() 사용 컴파일 오류 발생 관련 #include <unistd.h> 구문 추가
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include "LogFileProcessThread.h"
#include "HostInfo.h"
/// 테스트를 위해 값을 4,7에서 0, 23로 변경했음.
#define TIME_SCOPE_FIRST_BEGIN 0
#define TIME_SCOPE_FIRST_END 23
#define TIME_SCOPE_BEGIN 4
#define TIME_SCOPE_END 7
using namespace std;
CLogFileProcessThread::CLogFileProcessThread(string myname)
{
// 멤버 변수 초기화
m_threadHandle = 0;
m_szMyName = myname;
m_nToday = GetToday();
m_TimeScope.begin = TIME_SCOPE_FIRST_BEGIN;
m_TimeScope.end = TIME_SCOPE_FIRST_END;
SetStatus( LFP_READY );
bFirst = true;
}
CLogFileProcessThread::~CLogFileProcessThread()
{
}
bool CLogFileProcessThread::ThreadInit(const sig_atomic_t *sighandle)
{
m_sighandle = sighandle;
return true;
}
int CLogFileProcessThread::Rand( uint32_t max, uint32_t key )
{
srand( time(NULL) + key );
return ( rand() % max );
}
bool CLogFileProcessThread::IsBeginWork( struct tm& now )
{
int status = GetStatus();
switch( status )
{
/// READY 상태는 현재 시간이 작업 구간에 있는지를 확인 할 수 있는 상태이다.
case LFP_READY:
return IsInWorkTimeScope( now.tm_hour );
/// DONE 상태는 오늘 이미 작업을 마쳤기 때문에 날자가 변경 되었는지를 확인해서
/// 날자가 변경 되었으면 상태를 READY로 변경해서 작업 시간에 작업을 다시 할 수 있도록 한다.
case LFP_DONE:
if( IsChangedDay( now.tm_mday ) == true )
{
LOG( LDEV1, "call SetStatus( LFP_READY )" );
SetStatus( LFP_READY );
m_nToday = now.tm_mday;
}
break;
/// SLEEP, WORKING 상태를 이미 작업이 시작된 상태로 IsBeginWork() 함수가 외부에 노출 되지 않았기 때문에
/// 정상적인 경우에는 SLEEP, WORKING 상태에서 IsBeginWork() 함수가 호출 될 수 없다.
case LFP_SLEEP:
case LFP_WORKING:
default:
LOG( LWAR, "%s is invalid status.", GetStrStatus( GetStatus() ).c_str() );
break;
}
return false;
}
bool CLogFileProcessThread::IsInWorkTimeScope( int hour )
{
if( hour >= m_TimeScope.begin && hour < m_TimeScope.end )
{
return true;
}
return false;
}
void CLogFileProcessThread::SetStatus( LogFileProcessStatus status )
{
switch( status )
{
case LFP_READY:
case LFP_SLEEP:
case LFP_WORKING:
case LFP_DONE:
_LOG( LINF, "change status of %s %s to %s.", m_szMyName.c_str(), GetStrStatus( m_nStatus ).c_str(), GetStrStatus( status ).c_str() );
m_nStatus = status;
break;
default:
_LOG( LERR, "can't set status of CLogFileProcess because of invalid status(%d)", status );
}
}
string CLogFileProcessThread::GetStrStatus( LogFileProcessStatus status )
{
string res = "";
switch( status )
{
case LFP_READY:
res = "READY";
break;
case LFP_SLEEP:
res = "SLEEP";
break;
case LFP_WORKING:
res = "WORKING";
break;
case LFP_DONE:
res = "DONE";
default:
res = "UNKNOWN";
break;
}
return res;
}
bool CLogFileProcessThread::IsChangedDay( int day )
{
bool res = ( m_nToday != day ? true : false );
return res;
}
bool CLogFileProcessThread::IsDirectory( string path )
{
struct stat dirStat;
if( lstat ( path.c_str(), &dirStat ) != 0 )
{
LOG( LERR, "lstat failed. check path(%s).", path.c_str() );
return false;
}
// 해당 정보가 Directory 가 아닌 경우
if( S_ISDIR( dirStat.st_mode ) == false )
{
LOG( LDBG, "%s is not directory.", path.c_str() );
return false;
}
return true;
}
bool CLogFileProcessThread::Unlink( string filename )
{
if( IsDirectory( filename ) == true )
{
LOG( LWAR, "can't unlink file(%s) because %s is direcotry.", filename.c_str(), filename.c_str() );
return false;
}
int error = unlink( filename.c_str() );
if( error == -1 )
{
LOG( LWAR, "can't unlink file(%s). errno=%d, error=%s",
filename.c_str(), error, strerror( error ) );
return false;
}
_LOG( LINF, "unlinke file: %s", filename.c_str() );
return true;
}
int CLogFileProcessThread::GetMaxSleepSecond( struct tm& now )
{
if( IsInWorkTimeScope( now.tm_hour ) == false )
{
LOG( LWAR, "can't get sleep time because of invalid hour(%d).", now.tm_hour );
return -1;
}
/// (현재 시간 + 1분)에서 (m_TimeScope.end - 1 )시 59분까지의 남은 분을 계산한다. 초 단위 생략.
/// (남은 분 * 60)으로 초 단위로 환산한 범위에서 random 한 값을 반환 한다.
// 우선 시간을 빼고 분만 가지고 계산.
// 58분 경우 59로 계산 되므로 해당 값이 '0'되는 것을 방지 하기 위해서 59 => 60으로 변경 한다.
int min = 60 - ( now.tm_min + 1 );
if( min < 0 )
{
LOG( LERR, "can't get sleep time because invalid time[%02d:%02d:%02d].",
now.tm_hour, now.tm_min, now.tm_sec );
return -1;
}
/// 시간을 계산해서 분에 더한다.
int hour = ( m_TimeScope.end - 1 ) - now.tm_hour;
if( hour < 0 )
{
LOG( LERR, "can't get sleep time because invalid time[%02d:%02d:%02d].",
now.tm_hour, now.tm_min, now.tm_sec );
return -1;
}
min += (hour * 60);
/// 분을 초로 환산한다.
int sec = min * 60;
return sec;
}
int CLogFileProcessThread::GetToday()
{
time_t timestamp = time( NULL );
struct tm now;
localtime_r( &timestamp, &now );
return now.tm_mday;
}
///@brief 이 함수에서 컨트롤 로직이 표현된다.
void CLogFileProcessThread::Execute()
{
time_t timestamp;
struct tm now;
while (*m_sighandle == 0)
{
/// 현재 시각 확인
timestamp = time( NULL );
localtime_r( &timestamp, &now );
/// 작업 시작 여부 확인.
if( IsBeginWork( now ) == false )
{
LOG( LDEV1, "I'm sleeping now for 1 minute." );
/// 작업을 하지 않아야 하면 1분 대기.
sleep( 60 ); /// 60초
continue;
}
/// 여기서 부터 작업 시작.
/// 현재 시간부터 TIME_SCOPE_END까지 최대 대기 할 수 있는 시간을 초 단위로 가지고 온다.
int maxSleepSecond = GetMaxSleepSecond( now );
if( maxSleepSecond < 0 )
{
LOG( LERR, "invalid max sleep time. current time = [%02d:%02d:%02d].",
now.tm_hour, now.tm_min, now.tm_sec );
continue;
}
/// 0 ~ maxSleepSecond 사이의 랜덤한 값을 가지고 온다.
CHostInfo hostInfo;
int sleeptime = Rand( maxSleepSecond, hostInfo.GetHostNumber() );
_LOG( LINF, "CLogFileProcess will begin work after %d seconds.", sleeptime );
if ( bFirst == true )
sleeptime = 5;
/// 위에서 계산한 sleeptime 만큼 대기한 후에 실제 작업 시작.
LOG( LDEV1, "call SetStatus( LFP_SLEEP )" );
SetStatus( LFP_SLEEP );
sleep( sleeptime );
/// 여기서 부터 실제 작업 시작.
/// 실제 작업 구현은 CLogFileProcess를 상속받은 자식 클래스에서 구현한다.
LOG( LDEV1, "call SetStatus( LFP_WORKING )" );
SetStatus( LFP_WORKING );
if( DoWork() == false )
{
LOG( LWAR, "log file process failed." );
}
// DoWork가 한번 이상 수행 되면 아래이 시간 되어야 한다.
bFirst = false;
// 새벽 4~7시 사이...
m_TimeScope.begin = TIME_SCOPE_BEGIN;
m_TimeScope.end = TIME_SCOPE_END;
/// 작업이 끝나면 작업의 성공 여부에 상관 없이 상태를 LFP_DONE로 변경한다.
LOG( LDEV1, "call SetStatus( LFP_DONE )" );
SetStatus( LFP_DONE );
}
LOG(LERR, "Thread Terminated...");
}
void* CLogFileProcessThread::EntryPoint(void* arg)
{
CLogFileProcessThread* pObject = reinterpret_cast<CLogFileProcessThread *>(arg);
pthread_detach( pthread_self() );
pObject->Execute();
pObject->m_threadHandle = 0;
return 0;
}
bool CLogFileProcessThread::Start()
{
int nRet = ::pthread_create(&m_threadHandle, 0, CLogFileProcessThread::EntryPoint, this);
if( nRet )
{
LOG(LERR, "Thread create failed.: errno:%d errmsg:%s", errno, strerror(errno));
return false;
}
LOG(LDBG, "Thread create succeed");
sleep(0);
return true;
}