#include "GarbageCleanThread.h"

#include "Logger.h"

#include <errno.h>
#include <string.h>
#include <time.h>


// Expire 처리를 위한 시간( sec )
// - vmasd 정보는  6 sec 마다 전송되므로... 기존에도 20 sec expire 처리했음.
// - csagentd 는 4 sec 마다 전송하지만.. tcp 세션(timeout 6 sec)이라.. 정상적인 상황이라면 정리할 필요 없음.
#define CLIENT_SHM_EXPIRE_TIME  20

// 작업 수행 주기 ( sec )
// - 빠른 판단으로 clean 처리를 해야.. FHS, RCDB 에 잘못된 정보가 전달되지 않음
// - 2018-02-22 #31703 일감에서 각 FHS 에서 정보 수신 timeout 발생시 대기가 아닌 세션을 종료하도록 수정
//              이로 인해 기존과 같이 빠른 garbage 처리가 필요하지 않아.. 동작 주기를 2 sec -> 4 sec 로 수정.
#define CLEAN_JOB_INTERVAL       4


// 생성자
CGarbageCleanThread::CGarbageCleanThread( CShmManager * pShmManager )
	: m_pShmManager( pShmManager )
{
	// Thread handle 초기화
	m_threadHandle = 0;
}

// 소멸자
CGarbageCleanThread::~CGarbageCleanThread()
{
	// Thread 가 동작 중인 경우 Thread 동작 정지 처리.
	if( m_threadHandle != 0 )
	{
		pthread_cancel( m_threadHandle );
	}
}

// Thread 를 생성하여 cache 작업 수행
bool CGarbageCleanThread::Start( void )
{
	int nResult = pthread_create( &m_threadHandle, NULL, CGarbageCleanThread::threadFunc, this );
	if( nResult != 0 )
	{
		// Thread 생성 실패시...
		int errorNum = errno;
		LOG( LERR, "GarbageCleanThread: Thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );

		return false;
	}

	return true;
}

// Thread 함수
void * CGarbageCleanThread::threadFunc( void * arg )
{
	CGarbageCleanThread * pObject = reinterpret_cast<CGarbageCleanThread *>( arg );
	pthread_detach( pthread_self() );
	
	// 주기적으로 공유메모리 clean 작업 수행
	while( 1 )
	{
		pthread_testcancel();
		pObject->Execute();
		pthread_testcancel();
				
		// 지정된 주기마다...
		sleep( CLEAN_JOB_INTERVAL );
	}
	
	// Thread 종료시 Handle 초기화
	pObject->m_threadHandle = 0;

	return NULL;
}


// 실제 공유메모리 clean 처리를 담당하는 함수.
void CGarbageCleanThread::Execute()
{
	// expire 시간 정보
	time_t    expireTime;

	// 현재 시간 정보 추출.
	// - 시간 동기화 오차보정 관련 방어를 위해 clock_gettime(CLOCK_MONOTONIC) 로 추출된 정보와
	// - 공유메모리 service.update_time_clock_sec 항목을 비교토록 처리.
	struct timespec currentClock;
	memset( &currentClock, 0x00, sizeof( struct timespec ) );
	
	clock_gettime( CLOCK_MONOTONIC, &currentClock );
		
	// expire 처리할 시간 계산.
	if( currentClock.tv_sec <= CLIENT_SHM_EXPIRE_TIME )
	{
		// 추출된 시간 정보가 너무 작은 경우...
		// - 이럴 경우는 거의 없지만.. 혹시나 해서...
		LOG( LWAR, "GarbageCleanThread: expire clock value[%lu] too low. clean job skip.", currentClock.tv_sec );
		return;
	}
	else
	{
		int result;

		expireTime = currentClock.tv_sec - CLIENT_SHM_EXPIRE_TIME;
		//_LOG( LDBG, "GarbageCleanThread: expire clock value[%lu]", expireTime );

		// 공유메모리에 expire 처리 요청.
		result= m_pShmManager->ExpireClient( expireTime );

		if( result > 0 )
		{
			_LOG( LINF, "GarbageCleanThread: client expire count[%d] expire_clock[%lu]", result, expireTime );
		}
	}

	return;
}
