base
This commit is contained in:
@@ -0,0 +1,512 @@
|
||||
#include "GarbageClean.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "Logger.h"
|
||||
#include "ProcessConfig.h"
|
||||
|
||||
|
||||
#define SQLITE_DB_LOCK_TIMEOUT 1000 // SQLITE_BUSY 상황 발생 문제 해결을 위해 DB Lock 관련 timeout 설정값. (1 sec)
|
||||
#define SQLITE_DB_LOCK_MAX_RETRY 60 // SQLITE_BUSY 발생시 재시도 최대 횟수
|
||||
|
||||
|
||||
// meta 에 존재하지 않아.. unlink 여부 판단시... 삭제 방지 day 값
|
||||
// - unlink 대상인 경우.. 최종 수정일, 최종 access 시간이 본 설정값 이하이면 삭제되지 않도록 처리.
|
||||
// - 2019-08-29 일감 #32774 에 의해 7일 -> 2일로 변경 처리함.
|
||||
#define UNLINK_PREVENT_MAX_DAY 2
|
||||
|
||||
|
||||
// unlink slow 모드인 경우.. unlink 후 sleep 시간 (sec)
|
||||
// - 2 sec sleep : 일 4만건 unlink
|
||||
// - 1 sec sleep : 일 8만건 unlink
|
||||
#define UNLINK_SLOW_MODE_SLEEP 1
|
||||
|
||||
|
||||
// 생성자
|
||||
// - pLocalDb : sqlite memory db 객체에 대한 포인트
|
||||
CGarbageClean::CGarbageClean( sqlite3 * pLocalDb )
|
||||
: m_pLocalStmt( NULL )
|
||||
{
|
||||
m_pLocalDb = pLocalDb;
|
||||
}
|
||||
|
||||
|
||||
// 소멸자
|
||||
CGarbageClean::~CGarbageClean()
|
||||
{
|
||||
m_vecTargetDirectory.clear();
|
||||
|
||||
// Local DB stamt clear
|
||||
if( m_pLocalStmt != NULL )
|
||||
{
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 객체 초기화 함수
|
||||
bool CGarbageClean::Init()
|
||||
{
|
||||
// 작업대상 폴더 정보를 저장할 변수 초기화.
|
||||
m_vecTargetDirectory.clear();
|
||||
|
||||
// Local sqlite db 관련 변수
|
||||
int nResult = 0;
|
||||
int nRetryCount = 0;
|
||||
|
||||
|
||||
// strQuery = "CREATE TABLE meta( resource_id integer, filename_hash text, get_content_length integer, deleted_yn text )";
|
||||
|
||||
// 조회 처리를 수행할 stmt 객체 생성.
|
||||
// - 결과 추출 오류 발생시 sqlite3_column_int() 함수가 0 을 반환하므로.. 오류 와.. 실제 미존재 상태를 구분하기 위해... +1 처리함.
|
||||
std::string strQuery;
|
||||
strQuery = "SELECT count( resource_id ) +1 FROM meta WHERE filename_hash = ? ;";
|
||||
|
||||
nResult = sqlite3_prepare( m_pLocalDb, strQuery.c_str(), strQuery.size(), &m_pLocalStmt, NULL );
|
||||
|
||||
// sqlite3_prepare() 함수 실행시 SQLITE_BUSY 오류가 발생할 수 있으므로.. 재시도 로직을 추가한다.
|
||||
while( nResult == SQLITE_BUSY && nRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nRetryCount;
|
||||
|
||||
_LOG( LWAR, "Local db prepare sql SQLITE_BUSY. Retry[%d]", nRetryCount );
|
||||
|
||||
nResult = sqlite3_prepare( m_pLocalDb, strQuery.c_str(), strQuery.size(), &m_pLocalStmt, NULL );
|
||||
}
|
||||
|
||||
// 최종 실패시...
|
||||
if( nResult != SQLITE_OK )
|
||||
{
|
||||
LOG( LERR, "sqlite3 prepare sql stmt create failed. [%d][%s]", nResult, sqlite3_errmsg( m_pLocalDb ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// garbage clean 작업 수행.
|
||||
// - bGarbageCleanSlow : unlink 수행 후 sleep 를 호출하는 slow 모드로 동작시킬지 여부.
|
||||
// - bGarbageForceDelete: unlink 처리시 access time 정보를 check 할지 여부
|
||||
bool CGarbageClean::Start( bool bGarbageCleanSlow, bool bGarbageForceDelete )
|
||||
{
|
||||
// 작업 소요 시간 정보 계산을 위한 변수.
|
||||
// - 시간 동기화로 인한 문제를 해결하기 위해 clock_gettime() 함수 사용.
|
||||
struct timespec timeStart;
|
||||
struct timespec timeEnd;
|
||||
double dTimeInterval = 0.0;
|
||||
|
||||
memset( &timeStart, 0x00, sizeof( struct timespec ) );
|
||||
memset( &timeEnd, 0x00, sizeof( struct timespec ) );
|
||||
|
||||
// Meta 에 존재하지 않는 파일 삭제 처리 관련...
|
||||
// 현재 시간 정보 추출하여.. 정의된 보호 시간을 뺀다.
|
||||
time_t unlinkPreventMaxTime;
|
||||
unlinkPreventMaxTime = time( 0 ) - ( UNLINK_PREVENT_MAX_DAY * 24 * 60 * 60 );
|
||||
|
||||
// 작업 시작 로깅 및 시작 시간 정보 추출.
|
||||
_LOG( LINF, "Garbage clean start." );
|
||||
_LOG( LINF, "- unlink speed: %s", ( bGarbageCleanSlow == true ? "slow" : "normal" ) );
|
||||
_LOG( LINF, "- unlink modifiy time max prevent : %d day, %ld time.", UNLINK_PREVENT_MAX_DAY, unlinkPreventMaxTime);
|
||||
if( bGarbageForceDelete == false )
|
||||
{
|
||||
_LOG( LINF, "- unlink access time max prevent : %d day, %ld time.", UNLINK_PREVENT_MAX_DAY, unlinkPreventMaxTime );
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LINF, "- unlink access time not check. force unlink." );
|
||||
}
|
||||
|
||||
|
||||
clock_gettime( CLOCK_MONOTONIC, &timeStart );
|
||||
|
||||
// 통계 정보 저장을 위한 변수
|
||||
// 각 폴더별 삭제 count
|
||||
unsigned long long ullDirTotalCount = 0; // 각 폴더별 처리한 count 정보 저장.
|
||||
unsigned long long ullDirUnlinkCount = 0; // 각 폴더별 삭제한 count 정보 저장.
|
||||
|
||||
unsigned long long ullTotalCount = 0; // 누적 처리 count 정보 저장.
|
||||
unsigned long long ullTotalUnlinkCount = 0; // 누적 삭제 count 정보를 저장
|
||||
unsigned long long ullTotalUnlinkSize = 0; // 누적 삭제 Size 정보를 저장
|
||||
|
||||
|
||||
// 1. 설정된 대상 경로를 바탕으로.. 실제 최하위 서비스 폴더 목록 list 를 추출한다.
|
||||
if( GetTargetDir() == false )
|
||||
{
|
||||
// 오류 발생시.. 해당 모듈에서 로깅 처리 했으므로.. 실패로 처리.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_LOG( LINF, "Garbage clean [%s] sub service directory count [%lu]", CProcessConfig::GetInstance()->GetJobRoot(), m_vecTargetDirectory.size() );
|
||||
}
|
||||
|
||||
// 2. 추출된 각 경로에 대해.. 파일 정보를 추출하여.. 검증 수행.
|
||||
DIR * pDir = NULL;
|
||||
struct dirent * pDirEntry = NULL;
|
||||
std::vector< std::string >::iterator it;
|
||||
|
||||
// 파일에 대한 정보를 저장할 변수.
|
||||
std::string strFullFileName;
|
||||
int nFullFileNameExistCount;
|
||||
struct stat stFileStat;
|
||||
|
||||
// Local sqlite db 관련 변수
|
||||
int nResult = 0;
|
||||
int nRetryCount = 0;
|
||||
|
||||
|
||||
for( it = m_vecTargetDirectory.begin(); it != m_vecTargetDirectory.end(); ++it )
|
||||
{
|
||||
pDir = opendir( it->c_str() );
|
||||
if( pDir == NULL )
|
||||
{
|
||||
// 폴더 open 실패시...
|
||||
// - 오류 내역 로깅하고 계속 진행.
|
||||
|
||||
LOG( LERR, "directory[%s] open faild. [%d][%s]", it->c_str(), errno, strerror( errno ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
// 개별 폴더 통계 초기화.
|
||||
ullDirTotalCount = 0;
|
||||
ullDirUnlinkCount = 0;
|
||||
|
||||
_LOG( LINF, "Garbage clean [%s] start", it->c_str() );
|
||||
|
||||
while( ( pDirEntry = readdir( pDir ) ) != NULL )
|
||||
{
|
||||
// 만약 하위에 폴더, 링크, FIFO 등이 존재할 수 있으므로...
|
||||
// 이를 제외하고 only 파일만 비교 처리.
|
||||
|
||||
// man 5 dir
|
||||
// d_type 정의 내역.
|
||||
// #define DT_DIR 4
|
||||
// #define DT_REG 8
|
||||
|
||||
if( pDirEntry->d_type == DT_REG )
|
||||
{
|
||||
// '.'으로 시작하는 숨김 파일 등은 제외 처리. ( '.', '..', '..sujournal' 등 )
|
||||
if( pDirEntry->d_name[0] == '.' )
|
||||
continue;
|
||||
|
||||
// 진행 사항 로깅.
|
||||
if( ullDirTotalCount % 10000 == 0 && ullDirTotalCount != 0 )
|
||||
{
|
||||
_LOG( LINF, "Garbage checking. [%s] count[%10llu] unlink[%10llu]"
|
||||
, it->c_str(), ullDirTotalCount, ullDirUnlinkCount );
|
||||
}
|
||||
|
||||
// 통계 정보 증감 처리
|
||||
++ullDirTotalCount;
|
||||
|
||||
// 파일명 전체 경로 정보 조합
|
||||
strFullFileName = it->c_str();
|
||||
strFullFileName.append( "/" );
|
||||
strFullFileName.append( pDirEntry->d_name );
|
||||
|
||||
// 이제 실제로 파일이 존재하는지 local DB 에서 확인한다.
|
||||
// select query 에 변수 bind 처리. ( bind 값을 1부터 시작 )
|
||||
// - bind 처리시.. SQLITE_TRANSIENT 도 사용할 수 있으나.. 내부 copy 로 속도 느림
|
||||
// - query 처리 중간에 변수값이 변경될 가능성 없으므로.. SQLITE_STATIC 사용.
|
||||
nResult = sqlite3_bind_text( m_pLocalStmt, 1, strFullFileName.c_str(), strFullFileName.size(), SQLITE_STATIC );
|
||||
if( nResult != SQLITE_OK )
|
||||
{
|
||||
// bind 처리 실패시....
|
||||
LOG( LERR, "sqlite3 bind error.[%s] [%d][%s]", strFullFileName.c_str(), nResult, sqlite3_errmsg( m_pLocalDb ) );
|
||||
|
||||
// reset 처리 후.. 다음 항목을 진행 처리
|
||||
sqlite3_reset( m_pLocalStmt );
|
||||
continue;
|
||||
}
|
||||
|
||||
// Query 실행.
|
||||
nResult = sqlite3_step( m_pLocalStmt );
|
||||
nRetryCount = 0;
|
||||
|
||||
while( nResult == SQLITE_BUSY && nRetryCount < SQLITE_DB_LOCK_MAX_RETRY )
|
||||
{
|
||||
sqlite3_busy_timeout( m_pLocalDb, SQLITE_DB_LOCK_TIMEOUT );
|
||||
++nRetryCount;
|
||||
|
||||
LOG( LWAR, "sqlite3 step SQLITE_BUSY, Retry[%d]", nRetryCount );
|
||||
|
||||
// query 재시도
|
||||
nResult = sqlite3_step( m_pLocalStmt );
|
||||
}
|
||||
|
||||
// SELECT query 수행시....
|
||||
// - 결과 row 가 2 개 이상인 경우....SQLITE_ROW(100) 을 반환하고.. 더 이상 조회 결과가 없는 경우.....SQLITE_DONE (101) 반환.
|
||||
// - 결과가 없거나...결과 row 가 1개 인 경우.. SQLITE_DONE (101) 을 반환한다.
|
||||
// - 따라서 SQLITE_DONE 을 반환한다고 해서.. 결과가 없는 것으로 판단하면 안됨.
|
||||
|
||||
// select query 수행시 오류가 발생한 경우...
|
||||
if( nResult != SQLITE_ROW && nResult != SQLITE_DONE )
|
||||
{
|
||||
LOG( LERR, "sqlite3 step error.[%s] [%d][%s]", strFullFileName.c_str(), nResult, sqlite3_errmsg( m_pLocalDb ) );
|
||||
|
||||
// 만약 오류 코드가 SQLITE_ERROR, SQLITE_INTERNAL, SQLITE_EMPTY, SQLITE_SCHEMA 등이라면.... DB에 문제 있는 것으로 보고.. 작업 중지.
|
||||
if( nResult == SQLITE_ERROR || nResult == SQLITE_INTERNAL || nResult == SQLITE_EMPTY || nResult == SQLITE_SCHEMA )
|
||||
{
|
||||
LOG( LERR, "sqlite3 db not valid. garbage clean stop.");
|
||||
|
||||
closedir( pDir );
|
||||
pDir = NULL;
|
||||
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// 그 외 오류에 대해서는 무시하고 계속 진행.
|
||||
}
|
||||
else
|
||||
{
|
||||
// SELECT query 수행시....
|
||||
// - 결과 row 가 2 개 이상인 경우....SQLITE_ROW(100) 을 반환하고.. 더 이상 조회 결과가 없는 경우.....SQLITE_DONE (101) 반환.
|
||||
// - 결과가 없거나...결과 row 가 1개 인 경우.. SQLITE_DONE (101) 을 반환한다.
|
||||
// - 따라서 SQLITE_DONE 을 반환한다고 해서.. 결과가 없는 것으로 판단하면 안됨.
|
||||
|
||||
// strQuery = "SELECT count( resource_id ) +1 FROM meta WHERE filename_hash = ? ;";
|
||||
// - sqlite3_column_int() 호출시 오류가 발생할 경우에 대한 처리를 위해 +1 처리함.
|
||||
|
||||
// 조회 결과를 변수에 저장 처리.
|
||||
nFullFileNameExistCount = sqlite3_column_int( m_pLocalStmt, 0 );
|
||||
|
||||
// nFullFileNameExistCount == 0 : sqlite3_column_int() 함수 오류로 default 값이 반환된 경우...
|
||||
// nFullFileNameExistCount == 1 : Meta 에 해당 파일 정보 미존재시.
|
||||
// 그 이외에는 Meta 에 해당 파일 정보 존재로 처리.
|
||||
|
||||
//_LOG( LINF, "[GARBAGE] Meta SELECT. [%s] count [%d]", strFullFileName.c_str(), nFullFileNameExistCount -1 );
|
||||
|
||||
if( nFullFileNameExistCount == 1 )
|
||||
{
|
||||
// Meta 에 해당 파일 미존재시.
|
||||
|
||||
// 해당 파일 속성 정보 추출.
|
||||
if( stat( strFullFileName.c_str(), &stFileStat ) == 0 )
|
||||
{
|
||||
// 만약 해당 파일이 Meta에 존재하지 않는 경우...
|
||||
// 최종 수정일 정보를 추출하여... UNLINK_PREVENT_MAX_DAY 일이 지났는지 확인 후.
|
||||
// UNLINK_PREVENT_MAX_DAY 일 이상된 content 인 경우.. 삭제 처리한다.
|
||||
|
||||
// 파일의 최종 수정 시간이 UNLINK_PREVENT_MAX_DAY 일 이상이면 삭제 처리
|
||||
// - difftime() 함수를 사용해도 되지만.. CPU 사용률이 거의 100% 수준이라... CPU 부하 낮추기 위해 날코딩 처리.
|
||||
if( stFileStat.st_mtime < unlinkPreventMaxTime )
|
||||
{
|
||||
// access time 을 check 하지 않고.. unlink 처리 수행한다.
|
||||
if( bGarbageForceDelete == true )
|
||||
{
|
||||
// 해당 파일 unlink 처리.
|
||||
unlink( strFullFileName.c_str() );
|
||||
|
||||
++ullDirUnlinkCount;
|
||||
ullTotalUnlinkSize += stFileStat.st_size;
|
||||
|
||||
_LOG( LINF, "[GARBAGE] unlink with force[%s] mtime[%ld] size[%jd]"
|
||||
, strFullFileName.c_str(), stFileStat.st_mtime, stFileStat.st_size );
|
||||
|
||||
// unlink slow 모드인 경우.. unlink 처리 후.. 정의된 시간만큼 sleep 처리한다.
|
||||
if( bGarbageCleanSlow == true )
|
||||
sleep( UNLINK_SLOW_MODE_SLEEP );
|
||||
}
|
||||
else if( stFileStat.st_atime < unlinkPreventMaxTime )
|
||||
{
|
||||
// -f 옵션을 사용하지 않은 상태이고 access time 이 2일 이상인 경우
|
||||
// 삭제 처리를 수행한다.
|
||||
|
||||
// 해당 파일 unlink 처리.
|
||||
unlink( strFullFileName.c_str() );
|
||||
|
||||
++ullDirUnlinkCount;
|
||||
ullTotalUnlinkSize += stFileStat.st_size;
|
||||
|
||||
_LOG( LINF, "[GARBAGE] unlink[%s] atime[%ld] mtime[%ld] size[%jd]"
|
||||
, strFullFileName.c_str(), stFileStat.st_atime, stFileStat.st_mtime, stFileStat.st_size );
|
||||
|
||||
// unlink slow 모드인 경우.. unlink 처리 후.. 정의된 시간만큼 sleep 처리한다.
|
||||
if( bGarbageCleanSlow == true )
|
||||
sleep( UNLINK_SLOW_MODE_SLEEP );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// 파일의 최종 수정 시간은 UNLINK_PREVENT_MAX_DAY 값을 초과했지만.
|
||||
// force mode 가 아니고, access 시간이 UNLINK_PREVENT_MAX_DAY 일 이내인 경우..
|
||||
// - 로깅만 처리.
|
||||
_LOG( LINF, "[%s] meta not exist, but access occurred within [%d] day. a[%ld] m[%ld] limit[%ld] size[%jd]"
|
||||
, strFullFileName.c_str(), UNLINK_PREVENT_MAX_DAY, stFileStat.st_atime, stFileStat.st_mtime, unlinkPreventMaxTime, stFileStat.st_size );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 파일의 최종 수정 시간이 UNLINK_PREVENT_MAX_DAY 일 이내인 경우..
|
||||
// - 로깅만 처리.
|
||||
_LOG( LINF, "[%s] meta not exist, but modify occurred within [%d] day. a[%ld] m[%ld] limit[%ld] size[%jd]"
|
||||
, strFullFileName.c_str(), UNLINK_PREVENT_MAX_DAY, stFileStat.st_atime, stFileStat.st_mtime, unlinkPreventMaxTime, stFileStat.st_size );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// stat 호출 오류인 경우...
|
||||
// - multi thread 가 아직 1 process 구조라서.. errno 를 그대로 사용....
|
||||
// - 만약 multi thread 구조로 변경할 경우.. errno 그대로 사용하면 안됨.
|
||||
|
||||
// garbage clean 를 very slow 모드로 동작시킬 경우...
|
||||
// - 작업 시간이 오래 걸려...
|
||||
// - 해당 물리 파일이 rc_gcmd 등의 다른 프로세스에 의해 삭제될 가능성이 존재함.
|
||||
// - 이를 경우... 다음과 같은 오류 발생
|
||||
// [17:25:42] [ERR ] [GARBAGE] meta not exist. but file stat call error. name[/stg/node0/250/22a753b521dfc43ae468854c2089e8ef] [2][No such file or directory]
|
||||
// - 따라서.. 다른 프로세스에 의해 삭제된 경우.. 불필요하게 오류 찍을 필요 없다.
|
||||
|
||||
if( errno != ENOENT )
|
||||
{
|
||||
_LOG( LERR, "[GARBAGE] meta not exist. but file stat call error. name[%s] [%d][%s]", strFullFileName.c_str(), errno, strerror( errno ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if( nFullFileNameExistCount == 0 )
|
||||
{
|
||||
//sqlite3_column_int() 함수 오류로 default 값이 반환된 경우...
|
||||
LOG( LERR, "sqlite3 column get error.[%s] [%d][%s]", strFullFileName.c_str(), nFullFileNameExistCount, sqlite3_errmsg( m_pLocalDb ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Meta 에 해당 파일 정보 존재로 처리.
|
||||
//_LOG( LINF, "[GARBAGE] Meta OK. [%s] count [%d]", strFullFileName.c_str(), nFullFileNameExistCount - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// Query 수행된 경우.. prepared 문을 재사용하기 위해 reset 처리한다.
|
||||
sqlite3_reset( m_pLocalStmt );
|
||||
}
|
||||
|
||||
} // while( ( pDirEntry = readdir( pDir ) ) != NULL )
|
||||
|
||||
|
||||
// open 처리된 dir 객체를 close 처리한다.
|
||||
closedir( pDir );
|
||||
pDir = NULL;
|
||||
|
||||
|
||||
// 통계 저장 처리
|
||||
ullTotalCount += ullDirTotalCount;
|
||||
ullTotalUnlinkCount += ullDirUnlinkCount;
|
||||
|
||||
|
||||
_LOG( LINF, "Garbage clean [%s] end. unlink count[ %llu / %llu ] ", it->c_str(), ullDirUnlinkCount, ullDirTotalCount );
|
||||
|
||||
|
||||
} // for( it = m_vecTargetDirectory.begin(); it != m_vecTargetDirectory.end(); ++it )
|
||||
|
||||
|
||||
// 작업 완료 후 stmt 객체 clear
|
||||
sqlite3_finalize( m_pLocalStmt );
|
||||
m_pLocalStmt = NULL;
|
||||
|
||||
// 작업 완료시 시간 정보 추출 후 소요시간 계산.
|
||||
clock_gettime( CLOCK_MONOTONIC, &timeEnd );
|
||||
|
||||
dTimeInterval = timeEnd.tv_sec - timeStart.tv_sec;
|
||||
dTimeInterval += ( timeEnd.tv_nsec - timeStart.tv_nsec ) * 1e-9;
|
||||
|
||||
_LOG( LINF, "Garbage clean complete. path[%s] unlink mode[%s] elapsed time: %.1lf sec."
|
||||
, CProcessConfig::GetInstance()->GetJobRoot()
|
||||
, ( bGarbageCleanSlow == true ? "slow" : "normal" )
|
||||
, dTimeInterval );
|
||||
|
||||
_LOG( LINF, "Garbage clean report: total count[%llu] unlink count[%llu] unlink size[%llu byte]"
|
||||
, ullTotalCount, ullTotalUnlinkCount, ullTotalUnlinkSize );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 설정된 기본 경로를 바탕으로.. 작업대상 폴더명 정보를 추출하여.. 멤버변수에 저장 처리.
|
||||
bool CGarbageClean::GetTargetDir()
|
||||
{
|
||||
// 사용자가 입력했거나.. 기본으로 설정된 경로에서...
|
||||
// 실제 정리 작업을 수행할 서비스 폴더를 추출한다.
|
||||
// - 서비스 폴더가 아닌 경우.. 운영 목적으로 설정한 파일들이 존재하여..
|
||||
// - 삭제될 수 있으므로...
|
||||
// - 서비스 폴더에 대해서만 정리 작업이 수행되도록 한다.
|
||||
|
||||
// 추출 방식
|
||||
// - 직접 코드로 opendir, readdir 함수를 이용하여 추출 가능하지만....
|
||||
// - 불필요하게 시간이 오래 걸리고.. 버그의 가능성 존재.
|
||||
// - 따라서 외부 명령어를 이용하여..
|
||||
// - 하위 폴더 정보를 추출하고.... 서비스 폴더인지 검증 처리.
|
||||
|
||||
// 외부 tool
|
||||
// find /stg/node0 -type d -print
|
||||
// find /stg/node0 -type d -print | grep '/[1-9]*$'
|
||||
|
||||
// 참고사항
|
||||
// main 모듈에서 root 경로에 대한
|
||||
// 맨 끝의 '/' 제거 및
|
||||
// 존재 여부 확인 했으므로... 그냥 사용하면 됨.
|
||||
|
||||
char tempBuffer[2048];
|
||||
std::string strTempPath;
|
||||
FILE * fd = NULL;
|
||||
|
||||
// trim 처리 관련 변수
|
||||
std::string::size_type pos;
|
||||
|
||||
|
||||
// 명령어 조립
|
||||
snprintf( tempBuffer, sizeof( tempBuffer ), "find %s -type d -print | grep '/[0-9]*$'", CProcessConfig::GetInstance()->GetJobRoot() );
|
||||
fd = popen( tempBuffer, "r" );
|
||||
if( fd == NULL )
|
||||
{
|
||||
int errorNum = errno;
|
||||
LOG( LERR, "service directory search error. popen error. [%d][%s]", errorNum, strerror( errorNum ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 작업 대상 경로를 저장할 멤버 변수 초기화.
|
||||
m_vecTargetDirectory.clear();
|
||||
|
||||
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
||||
while( fgets( tempBuffer, sizeof( tempBuffer ) - 1, fd ) != NULL )
|
||||
{
|
||||
// 결과 맨 끝에 줄바꿈 문자가 있어.. trim 처리 필요
|
||||
strTempPath = tempBuffer;
|
||||
if( strTempPath.length() == 0 )
|
||||
continue;
|
||||
|
||||
pos = strTempPath.find_last_not_of( " \a\b\f\n\r\t\v" );
|
||||
if( pos != std::string::npos )
|
||||
strTempPath.erase( pos + 1 );
|
||||
|
||||
// 원래는 추출된 전체 경로.. (/stg/node0/290 ) 에서
|
||||
// 마지막 290 정보 추출하여 숫자인지 비교해야 하지만...
|
||||
// 귀찬아서.. 외부 명령어의 grep 으로 비교 처리 넣어버림...
|
||||
|
||||
// 따라서.. 추출된 폴더 정보를 바로 저장 처리하면 됨.
|
||||
|
||||
m_vecTargetDirectory.push_back( strTempPath );
|
||||
}
|
||||
|
||||
pclose( fd );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user