Files
interactive/rcts/rc_balanced/src/ShmInfoThread.cpp
T
2026-08-07 17:38:18 +09:00

717 lines
24 KiB
C++

#include "ShmInfoThread.h"
#include "Logger.h"
#include "Common.h"
#include "ProcessConfig.h"
#include "../rc_mond/ShmDefine.h"
#include "../rc_mond/ShmControl.h"
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <algorithm> // vector sort 사용 목적
// 매 Loop 마다 Sleep 시간 정보 정의 ( sec 단위)
#define SLEEP_TIME_DEFAULT 20
#define SLEEP_TIME_MAX 60
// rc_mond shared memory 접근을 위한 key 파일.
#define RC_MOND_SHARED_MEMORY_KEY_FILE "/user/service/rc_mond.shm"
// Rebalance 처리 대상 FHS 관련 FHS 의 최소 Storage 사용률 제한값.
// 해당 percent(%) 이상인 장비만 선정되도록 하기 위함
#define REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT 50
// Rebalance 처리 대상 FHS 관련 FHS 의 최대 disk busy 제한값.
// 해당 percent(%) 이하인 장비만 선정되도록 하기 위함
#define REBALANCE_TARGET_DISK_MAX_BUSY_LIMIT 50.0
// Rebalance 대상 FHS 선정을 위한 score 계산시 disk_max_busy 항목에 부여할 가중치 정보.
// - 점수가 높은 FHS 장비가 선정되므로...
// - disk busy 상태인 장비는 선택되지 않도록 0.5 수준으로 설정
// - storage_max_usage : disk_max_busy = 2 : 1 로 계산
#define REBALANCE_TARGET_DISK_MAX_BUSY_WEIGHT 0.5
// Rebalance 대상 FHS 정보를 저장한 list 의 유효시간 (sec)
// - SLEEP_TIME_MAX 값보다 커야 함.
#define TIMEOUT_REBALANCE_LIST 120
// Copy 수신 가능 FHS 의 Disk 여유용량 최소값
// - 1 TB
#define COPY_TARGET_DISK_MIN_AVAILABLE_LIMIT (1099511627776ULL)
// COPY 수신 가능 FHS 선정을 위한 score 계산시 disk_max_busy 항목에 부여할 가중치 정보.
// - 참고로 rc_mond 의 Top FHS 선정은 storage_max_usage : disk_max_busy = 1 : 4 로 계산하여 처리
// - Copy Target 은 실제 copy 처리를 수행하는 thread 가 많지 않고...
// - 되도록 여유 용량이 많은 장비에 copy 하는 것이 효과적이므로...
// - storage_max_usage : disk_max_busy = 1 : 2 로 계산
#define COPY_TARGET_DISK_MAX_BUSY_WEIGHT 2.0
// Copy 대상 FHS 정보를 저장한 list 의 유효시간 (sec)
// - default sleep time 값보다 커야 함
#define TIMEOUT_COPY_LIST 30
// 공유메모리에 저장된 FHS 정보 중 적합한 FHS 정보를 찾기 위해
// FHS 와 각 점수 정보를 저장하기 위한 구조체
struct FhsScore {
char hostname[HOST_NAME_LENGTH + 1]; // hostname, NULL 포함 최대 64자까지만 허용됨.
double score; // 계산된 score, 작을수록 idle
};
CShmInfoThread::CShmInfoThread()
{
// 멤버변수 초기화
m_threadHandle = 0;
m_uSleep = SLEEP_TIME_DEFAULT;
m_listRebalanceFhs.clear();
m_listCopyTargetFhs.clear();
// 시간 정보 초기화.
memset( &m_timeLastRefreshRebalanceFhs, 0x00, sizeof( struct timespec ) );
memset( &m_timeLastRefreshCopyTargetFhs, 0x00, sizeof( struct timespec ) );
pthread_mutex_init( &m_mutexRebalanceFhs, NULL );
pthread_mutex_init( &m_mutexCopyTargetFhs, NULL );
}
CShmInfoThread::~CShmInfoThread()
{
// thread 가 동작 중인 경우.. thread 중지 처리
if( m_threadHandle != 0 )
{
pthread_cancel( m_threadHandle );
}
sleep( 1 ); // thread 종료 잠시 대기
pthread_mutex_destroy( &m_mutexRebalanceFhs );
pthread_mutex_destroy( &m_mutexCopyTargetFhs );
}
///////////////////////////////
bool CShmInfoThread::Start()
{
// 작업 thread 생성
int nResult = pthread_create( &m_threadHandle, NULL, CShmInfoThread::threadFunc, this );
if( nResult != 0 )
{
// thread 생성 실패
int errorNum = errno;
LOG( LERR, "[SHM INF] thread create failed.[%d][%s]", errorNum, strerror( errorNum ) );
return false;
}
return true;
}
bool CShmInfoThread::GetRebalanceTargetFhs( std::string & szResultHost, std::list<std::string>& listIgnoreFHS )
{
// Rebalance 대상 FHS 목록 중....
// 전달받은 listIgnoreFHS 에 등록된 FHS 정보를 제외하고....
// 남은 FHS 정보 중.. 맨 처음 나오는 정보를 전달한다.
// 1. 저장된 list 정보가 갱신이 되지 않아 오래된 경우.... 버린다.
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
if( currentClock.tv_sec - m_timeLastRefreshRebalanceFhs.tv_sec > TIMEOUT_REBALANCE_LIST )
{
LOG( LWAR, "[SHM INF] rebalance list expired. %d sec.", TIMEOUT_REBALANCE_LIST );
return false;
}
// 2. 저장된 list 정보가 존재하지 않는 경우... false 반환 처리
if( m_listRebalanceFhs.size() <= 0 )
{
LOG( LWAR, "[SHM INF] rebalance list empty.");
return false;
}
std::list<std::string>::const_iterator it;
std::list<std::string>::const_iterator itIgnore;
std::string szHost;
pthread_mutex_lock( &m_mutexRebalanceFhs );
for( it = m_listRebalanceFhs.begin(); it != m_listRebalanceFhs.end(); ++it )
{
szHost = *it;
// 추출된 FHS 가 ignore list 에 존재하는지 확인
itIgnore = std::find( listIgnoreFHS.begin(), listIgnoreFHS.end(), szHost );
if( itIgnore == listIgnoreFHS.end() )
{
// ignore list 에 존재하지 않는 경우...
// 해당 장비를 선택하고.. loop 종료 처리
szResultHost = szHost;
pthread_mutex_unlock( &m_mutexRebalanceFhs );
_LOG( LDBG, "[SHM INF] proper rebalance fhs [%s] selected.",szResultHost.c_str() );
return true;
}
}
// 적합한 장비를 찾지 못한 경우.
pthread_mutex_unlock( &m_mutexRebalanceFhs );
_LOG( LDBG, "[SHM INF] proper rebalance fhs not selectd. total[%lu], ignore[%lu]."
, m_listRebalanceFhs.size(), listIgnoreFHS.size() );
return false;
}
// copy content 를 저장할 target FHS 정보를 반환
// 2021-01-07 NEW huibong 이동 대상 content 선택 관련 mode 기능 추가 (#33306)
// - 복사 가능 FHS 가 존재하는지 검색 관련 오류 발생시 반환값 정보를 좀더 세분화 처리
// - 정상 처리시 : return 1
// - 복사 가능 물리적 FHS 가 없는 경우 : return -1
// - 복사 가능 물리 FHS 는 존재하지만 ignore 목록에 포함되어.. 실제 복사 가능 FHS 가 없는 경우 : return 0
int CShmInfoThread::GetCopyTargetFhs( std::string & szResultHost, std::list<std::string>& listIgnoreFHS )
{
// COPY 수신 가능 FHS list 에서
// 전달받은 Ignore FHS 에 등록된 FHS 를 제외하고
// 남은 FHS 중 맨 처음 나오는 정보를 전달한다.
// 1. 저장된 list 정보가 갱신이 되지 않아 오래된 경우.... 버린다.
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
if( currentClock.tv_sec - m_timeLastRefreshCopyTargetFhs.tv_sec > TIMEOUT_COPY_LIST )
{
LOG( LWAR, "[SHM INF] copy target info list expired. %d sec.", TIMEOUT_COPY_LIST );
// 복사 가능 물리 FHS 가 아예 없는 경우... -1 return
return -1;
}
// 2. 저장된 list 정보가 존재하지 않는 경우
if( m_listCopyTargetFhs.size() <= 0 )
{
LOG( LWAR, "[SHM INF] ] copy target info list empty." );
// 복사 가능 물리 FHS 가 아예 없는 경우... -1 return
return -1;
}
std::list<std::string>::const_iterator it;
std::list<std::string>::const_iterator itIgnore;
std::string szHost;
pthread_mutex_lock( &m_mutexCopyTargetFhs );
for( it = m_listCopyTargetFhs.begin(); it != m_listCopyTargetFhs.end(); ++it )
{
szHost = *it;
// 추출된 FHS 가 ignore list 에 존재하는지 확인
itIgnore = std::find( listIgnoreFHS.begin(), listIgnoreFHS.end(), szHost );
if( itIgnore == listIgnoreFHS.end() )
{
// ignore list 에 존재하지 않는 경우...
// 해당 장비를 선택하고.. loop 종료 처리
szResultHost = szHost;
pthread_mutex_unlock( &m_mutexCopyTargetFhs );
_LOG( LDBG, "[SHM INF] proper copy target [%s] selected.", szResultHost.c_str() );
// 복사 가능 물리 FHS 가 존재하는 경우 ... 1 return
return 1;
}
}
// 적합한 장비를 찾지 못한 경우.
pthread_mutex_unlock( &m_mutexCopyTargetFhs );
LOG( LWAR, "[SHM INF] proper copy target fhs not selectd. total[%lu], ignore[%lu]."
, m_listCopyTargetFhs.size(), listIgnoreFHS.size() );
// 복사 가능 물리 FHS 가 존재하지만.. ignore 에 포함되어.. 실제 가능 FHS 가 전혀 없는 경우 ... 0 return
return 0;
}
bool CShmInfoThread::IsValidCopyTargetFhs( void )
{
// 1. 저장된 list 정보가 갱신이 되지 않아 오래되었는지 check
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
bool bResult = true;
pthread_mutex_lock( &m_mutexCopyTargetFhs );
if( currentClock.tv_sec - m_timeLastRefreshCopyTargetFhs.tv_sec > TIMEOUT_COPY_LIST )
{
LOG( LWAR, "[SHM INF] copy target list expired. %d sec.", TIMEOUT_COPY_LIST );
bResult = false;
}
else
{
if( m_listCopyTargetFhs.empty() == true )
{
LOG( LWAR, "[SHM INF] copy target list empty." );
bResult = false;
}
}
pthread_mutex_unlock( &m_mutexCopyTargetFhs );
return bResult;
}
//////////////////////////////
void * CShmInfoThread::threadFunc( void * arg )
{
CShmInfoThread * pObject = reinterpret_cast<CShmInfoThread *>(arg);
pthread_detach( pthread_self() );
while( 1 )
{
pthread_testcancel();
pObject->Execute();
pthread_testcancel();
// 지정된 주기로 실행
sleep( pObject->m_uSleep );
}
// thread 종료시 handle 정보 초기화
pObject->m_threadHandle = 0;
return NULL;
}
void CShmInfoThread::Execute()
{
// 다음 sleep time 은 default 로 처리
// - 하위 flow 에서 문제 발생하면 sleep time 을 max 로 조정
m_uSleep = SLEEP_TIME_DEFAULT;
// rc_mond 가 기동 중인지 check
// - 미기동 상태이면... 기동시까지 대기.
if( IsRunRcMonD() == false )
{
m_uSleep = SLEEP_TIME_MAX;
_LOG( LERR, "[SHM INF] %s process not running. max sleep %u sec.", PROCESS_NAME_RC_MONITORING_DAEMON, m_uSleep );
return;
}
// 공유메모리 접근
key_t iShmKey;
// 공유메모리 key 생성을 위한 임시 파일 생성 처리.
FILE * pShmFile = fopen( RC_MOND_SHARED_MEMORY_KEY_FILE, "r" );
if( pShmFile == NULL )
{
// 공유메모리 접근 key file 존재하지 않는 경우....
m_uSleep = SLEEP_TIME_MAX;
_LOG( LERR, "[SHM INF] %s shared memory key file(%s) not exist. max sleep %u sec."
, PROCESS_NAME_RC_MONITORING_DAEMON , RC_MOND_SHARED_MEMORY_KEY_FILE , m_uSleep );
return;
}
else
{
// 공유메모리 접근 key file 존재하는 경우
fclose( pShmFile );
pShmFile = NULL;
}
// 공유메모리 접근 key 값 추출
iShmKey = ftok( RC_MOND_SHARED_MEMORY_KEY_FILE, 1 );
if( iShmKey == (key_t)-1 )
{
// 공유메모리 접근 key 획득 실패시
m_uSleep = SLEEP_TIME_MAX;
_LOG( LERR, "[SHM INF] %s shared memory key generate fail with file(%s). max sleep %u sec."
, PROCESS_NAME_RC_MONITORING_DAEMON , RC_MOND_SHARED_MEMORY_KEY_FILE , m_uSleep );
return;
}
// 공유메모리 attach 처리
CShmControl< struct RcInfo > shmCtl;
if( shmCtl.Attach( iShmKey, sizeof( struct RcInfo ) ) == false )
{
// 공유메모리 접근 실패시
m_uSleep = SLEEP_TIME_MAX;
_LOG( LERR, "[SHM INF] %s shared memory attach fail with key(%d). max sleep %u sec."
, PROCESS_NAME_RC_MONITORING_DAEMON, iShmKey, m_uSleep );
return;
}
_LOG( LDBG, "[SHM INF] start." );
// 공유메모리 최상위 접근 포인터 획득
struct RcInfo * pShm = shmCtl.GetShmPtr();
// copy 처리 수신 가능 FHS 추출 및 rebalance 대상 FHS 추출 목록 update
if( RefreshFhsList( pShm ) == false )
{
// 실패 발생시 다음 sleep time 최대 설정.
m_uSleep = SLEEP_TIME_MAX;
}
// 공유메모리 접근 해제
shmCtl.Detach();
pShm = NULL;
return;
}
bool FhsScoreSortASC( const struct FhsScore & fhs1, const struct FhsScore & fhs2 )
{
return (fhs1.score < fhs2.score);
}
bool FhsScoreSortDESC( const struct FhsScore & fhs1, const struct FhsScore & fhs2 )
{
return (fhs1.score > fhs2.score);
}
bool CShmInfoThread::RefreshFhsList( const struct RcInfo * const pShm )
{
// FHS 의 시스템 정보 업데이트가 오래된 경우..
// - rc_mond 에서 지정된 시간( 20 sec ) 를 초과한 경우.. expire 처리하지만...
// - 오류가 발생할 수 있고... FHS 상태가 이상할 경우.. 해당 장비는 선택하지 않는 것이 좋으므로...
// - 업데이트가 비교적 최근에 발생한 FHS 정보만을 사용토록 한다.
// - csagentd 는 4(service), 10(system) sec 마다 정보 전송...
// - 따라서.. 8 sec 초과된 정보는 사용하지 않도록 한다.
// - local time 은 시간 동기화 영향 받으므로... update_time_clock_sec 항목을 사용하여 판단한다.
time_t expireTime;
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
expireTime = currentClock.tv_sec - 8;
// 1. Write 가능 FHS 의 Storage 사용량 정보를 조회하여 평균을 구한다.
// - 전체 FHS 의 평균을 구하면.. 용량이 충분한데 장비 문제로 강제 업로드 막은 장비까지 계산되어
// - 평균을 낮추 버리는 문제가 발생하여...
// - reblance 수신 FHS 가 다시 rebalance 처리 대상 FHS 가 될 수 있는 문제가 생긴다.
const struct ClientInfo * pClient = NULL;
unsigned int uFhsCount = 0;
unsigned int uFhsTotalUsage = 0;
int index = 0;
unsigned int uFhsAverageUsage = 0;
for( index = 0; index <= pShm->client_max_index; index++ )
{
pClient = &(pShm->client[index]);
// slot 할당되어 있고.. data 가 유효하고..
// write 가능 정상 상태 이고
// system 상태 정보가 정상인 경우...( system 정보가 늦게 수신되므로.. 이를 반영 )
// service 상태 정보가 expire 시간보다 오래되지 않은 최근 업데이트된 FHS 인 경우..
if( pClient->use == 1
&& pClient->valid == 1
&& pClient->service.service_stat == SERVICE_STAT_OK
&& pClient->system.update_time != 0
&& pClient->service.update_time_clock_sec >= expireTime
)
{
// 평균값 계산을 위한 값 처리
uFhsTotalUsage += pClient->system.storage_max_usage;
uFhsCount += 1;
}
}
// write 가능 유효한 FHS 가 없는 경우
if( uFhsCount < 1 )
{
_LOG( LWAR, "[SHM INF] starge average usage calc fail: write available fhs[%u] not exist.", uFhsCount );
return false;
}
// Storage 사용량 평균값 계산
uFhsAverageUsage = (uFhsTotalUsage / uFhsCount) + 1; // 소수점 짤려서.. 86.7% 여도 86 % 로 계산되므로.. 1 보정
_LOG( LINF, "[SHM INF] starge average usage calc ok. write fhs count[%u], avg[%u %%]", uFhsCount, uFhsAverageUsage );
// 2. 평균 Storage 사용률 미만인 FHS 를 Copy 수신 FHS 로 선정한다.
// - 만약 적합한 FHS 가 없는 경우 아래의 rebalance 대상 FHS 로 선정하지 않는다.
if( RefreshCopyTargetFhsList( pShm, uFhsAverageUsage ) == false )
{
return false;
}
// 3. rebalance 대상 FHS 로 선정한다.
// - 평균 Storage 사용률이 70% 미만인 경우... 평균 Storage 사용률보다 3% 이상 높은 FHS 를 rebalance 대상 FHS 로 선정
// - 평균 Storage 사용률이 70% 이상인 경우.. 평균 Storage 사용률보다 1% 이상 높은 FHS 를 rebalance 대상 FHS 로 설정
unsigned int uRebalanceTargetStorageUsage = 0;
if( uFhsAverageUsage < 70 )
{
uRebalanceTargetStorageUsage = uFhsAverageUsage + 3;
}
else
{
uRebalanceTargetStorageUsage = uFhsAverageUsage + 1;
}
if( RefreshRebalanceFhsList( pShm, uRebalanceTargetStorageUsage ) == false )
{
return false;
}
return true;
}
bool CShmInfoThread::RefreshCopyTargetFhsList( const RcInfo * const pShm, unsigned int uStorageMaxUsage )
{
// FHS 의 시스템 정보 업데이트가 오래된 경우..
// - rc_mond 에서 지정된 시간( 20 sec ) 를 초과한 경우.. expire 처리하지만...
// - 오류가 발생할 수 있고... FHS 상태가 이상할 경우.. 해당 장비는 선택하지 않는 것이 좋으므로...
// - 업데이트가 비교적 최근에 발생한 FHS 정보만을 사용토록 한다.
// - csagentd 는 4(service), 10(system) sec 마다 정보 전송...
// - 따라서.. 8 sec 초과된 정보는 사용하지 않도록 한다.
// - local time 은 시간 동기화 영향 받으므로... update_time_clock_sec 항목을 사용하여 판단한다.
time_t expireTime;
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
expireTime = currentClock.tv_sec - 8;
const struct ClientInfo * pClient = NULL;
struct FhsScore stFhsScore;
std::vector<struct FhsScore> vecFhsRank;
int nFhsCount = 0;
vecFhsRank.clear();
// 2021-01-19 NEW huibong move 대상 FHS 선정시 disk busy 허용 max 값 추가 (#33395)
// - conf 처리 관련 변수 사용하도록 수정 처리
double dTargetFhsMaxDiskBusyLimit = CProcessConfig::GetInstance()->GetTargetFhsMaxDiskBusyLimit();
// write 가능 장비를 찾아.. score 계산.
for( int i = 0; i <= pShm->client_max_index; i++ )
{
pClient = &(pShm->client[i]);
// slot 할당되어 있고.. data 가 유효하고..
// write 가능 상태
// system 상태 정보가 정상인 경우...( system 정보가 늦게 수신되므로.. 이를 반영 )
// service 상태 정보가 expire 시간보다 오래되지 않은 최근 업데이트된 FHS 인 경우..
// disk 최대 사용율이 평균값 미만
// disk busy 하지 않고.. 남은 유효 용량 역시 충분한 경우
if( pClient->use == 1
&& pClient->valid == 1
&& pClient->service.service_stat == SERVICE_STAT_OK
&& pClient->system.update_time != 0
&& pClient->service.update_time_clock_sec >= expireTime
&& pClient->system.storage_max_usage < (int)uStorageMaxUsage
&& pClient->system.disk_max_busy <= dTargetFhsMaxDiskBusyLimit
&& pClient->system.storage_avail >= COPY_TARGET_DISK_MIN_AVAILABLE_LIMIT
)
{
// 임시 객체 초기화.
memset( &stFhsScore, 0x00, sizeof( struct FhsScore ) );
// hostname 저장.
strncpy( stFhsScore.hostname, pClient->hostname, HOST_NAME_LENGTH );
// write score 계산 처리.
// - storage_max_usage 항목과
// - disk_max_busy * 전달받은 가중치 값의 합.
stFhsScore.score = (double)(pClient->system.storage_max_usage)
+ ((pClient->system.disk_max_busy) * COPY_TARGET_DISK_MAX_BUSY_WEIGHT);
// vector 에 결과 저장
vecFhsRank.push_back( stFhsScore );
// count
nFhsCount += 1;
}
}
// copy write 가능 장비가 존재하면
if( nFhsCount > 0 )
{
if( nFhsCount > 1 )
{
// 가장 점수가 낮아 이상적인 장비 순서로 정렬
std::sort( vecFhsRank.begin(), vecFhsRank.end(), FhsScoreSortASC );
}
// lock 을 걸고...
// m_listCopyTargetFhs 정보 및 m_timeLastRefreshCopyTargetFhs 정보 업데이트.
std::vector<struct FhsScore>::iterator it;
std::string szRefresList;
// 기존 list 에 저장된 정보 clear
pthread_mutex_lock( &m_mutexCopyTargetFhs );
m_listCopyTargetFhs.clear();
for( it = vecFhsRank.begin(); it != vecFhsRank.end(); ++it )
{
// 정렬된 순서대로 list 에 push 처리
m_listCopyTargetFhs.push_back( it->hostname );
szRefresList.append( it->hostname );
szRefresList.append( " " );
_LOG( LDBG, "[SHM INF] copy target fhs list push_back.[%s].", it->hostname );
}
// refresh time 정보 업데이트
clock_gettime( CLOCK_MONOTONIC, &m_timeLastRefreshCopyTargetFhs );
pthread_mutex_unlock( &m_mutexCopyTargetFhs );
_LOG( LINF, "[SHM INF] copy target fhs list refreshed. usage avg limit[%u %%]. [%d][%s]"
, uStorageMaxUsage, nFhsCount, szRefresList.c_str() );
return true;
}
else
{
// Copy 수신 가능 FHS 가 없는 경우...
// - 관련 내역 로깅
_LOG( LWAR, "[SHM INF] copy target fhs not exist. usage avg limit[%u %%], busy limit[%.1f %%]"
, uStorageMaxUsage, dTargetFhsMaxDiskBusyLimit );
return false;
}
}
bool CShmInfoThread::RefreshRebalanceFhsList( const RcInfo * const pShm, unsigned int uStorageMinUsage )
{
// FHS 의 시스템 정보 업데이트가 오래된 경우..
// - rc_mond 에서 지정된 시간( 20 sec ) 를 초과한 경우.. expire 처리하지만...
// - 오류가 발생할 수 있고... FHS 상태가 이상할 경우.. 해당 장비는 선택하지 않는 것이 좋으므로...
// - 업데이트가 비교적 최근에 발생한 FHS 정보만을 사용토록 한다.
// - csagentd 는 4(service), 10(system) sec 마다 정보 전송...
// - 따라서.. 8 sec 초과된 정보는 사용하지 않도록 한다.
// - local time 은 시간 동기화 영향 받으므로... update_time_clock_sec 항목을 사용하여 판단한다.
time_t expireTime;
struct timespec currentClock;
memset( &currentClock, 0x00, sizeof( struct timespec ) );
clock_gettime( CLOCK_MONOTONIC, &currentClock );
expireTime = currentClock.tv_sec - 8;
const struct ClientInfo * pClient = NULL;
struct FhsScore stFhsScore;
std::vector<struct FhsScore> vecFhsRank;
int nFhsCount = 0;
vecFhsRank.clear();
// rebalance 대상 장비를 찾아.. score 계산.
for( int i = 0; i <= pShm->client_max_index; i++ )
{
pClient = &(pShm->client[i]);
// slot 할당되어 있고.. data 가 유효하고..
// read only 상태인 경우..
// system 상태 정보가 정상인 경우...( system 정보가 늦게 수신되므로.. 이를 반영 )
// service 상태 정보가 expire 시간보다 오래되지 않은 최근 업데이트된 FHS 인 경우..
// disk 최대 사용율이 전달받은 값 이상이고
// disk 최대 사용량이 REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT(%) 이상인 장비
// disk busy 가 REBALANCE_TARGET_DISK_MAX_BUSY_LIMIT (%) 이하인 장비.
if( pClient->use == 1
&& pClient->valid == 1
&& ( pClient->service.service_stat == SERVICE_STAT_RONLY || pClient->service.service_stat == SERVICE_STAT_OK )
&& pClient->system.update_time != 0
&& pClient->service.update_time_clock_sec >= expireTime
&& pClient->system.storage_max_usage >= (int)uStorageMinUsage
&& pClient->system.storage_max_usage >= REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT
&& pClient->system.disk_max_busy <= REBALANCE_TARGET_DISK_MAX_BUSY_LIMIT )
{
// 임시 객체 초기화.
memset( &stFhsScore, 0x00, sizeof( struct FhsScore ) );
// hostname 저장.
strncpy( stFhsScore.hostname, pClient->hostname, HOST_NAME_LENGTH );
// score 계산 처리.
// - storage_max_usage 항목에서 disk_max_busy 값을 빼서 점수 계산
stFhsScore.score = (double)(pClient->system.storage_max_usage)
- ((pClient->system.disk_max_busy) * REBALANCE_TARGET_DISK_MAX_BUSY_WEIGHT);
// vector 에 결과 저장
vecFhsRank.push_back( stFhsScore );
// result count 증가.
nFhsCount += 1;
}
}
// Rebalance 대상 장비가 존재하면
if( nFhsCount > 0 )
{
if( nFhsCount > 1 )
{
// 가장 점수가 높은 순으로 정렬
std::sort( vecFhsRank.begin(), vecFhsRank.end(), FhsScoreSortDESC );
}
std::string szRefresList;
// lock 을 걸고...
// m_listCopyTargetFhs 정보 및 m_timeLastRefreshCopyTargetFhs 정보 업데이트.
std::vector<struct FhsScore>::iterator it;
// 기존 list 에 저장된 정보 clear
pthread_mutex_lock( &m_mutexRebalanceFhs );
m_listRebalanceFhs.clear();
for( it = vecFhsRank.begin(); it != vecFhsRank.end(); ++it )
{
// 정렬된 순서대로 list 에 push 처리
m_listRebalanceFhs.push_back( it->hostname );
szRefresList.append( it->hostname );
szRefresList.append( " " );
_LOG( LDBG, "[SHM INF] rebalance fhs list push_back.[%s]", it->hostname );
}
// refresh time 정보 업데이트
clock_gettime( CLOCK_MONOTONIC, &m_timeLastRefreshRebalanceFhs );
pthread_mutex_unlock( &m_mutexRebalanceFhs );
_LOG( LINF, "[SHM INF] rebalance fhs list refreshed. usage limit[%u %%]. [%d][%s]"
, (uStorageMinUsage > REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT ? uStorageMinUsage : REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT)
, nFhsCount, szRefresList.c_str() );
return true;
}
else
{
// Rebalance 처리 대상 FHS 가 없는 경우...
// - 관련 내역 로깅
_LOG( LINF, "[SHM INF] rebalance fhs not exist with usage limit [%u %%], busy limit [%.2f %%]"
, (uStorageMinUsage > REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT ? uStorageMinUsage : REBALANCE_TARGET_DISK_MIN_USAGE_LIMIT)
, REBALANCE_TARGET_DISK_MAX_BUSY_LIMIT );
return false;
}
}