267 lines
7.7 KiB
C++
267 lines
7.7 KiB
C++
#include "StorageInfo.h"
|
|
|
|
#include "Logger.h"
|
|
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <stdlib.h>
|
|
#include <sys/param.h>
|
|
#include <sys/ucred.h>
|
|
#include <sys/mount.h>
|
|
#include <math.h>
|
|
|
|
|
|
// 생성자
|
|
CStorageInfo::CStorageInfo()
|
|
{
|
|
// 멤버변수 초기화
|
|
m_vecStorageInfo.clear();
|
|
}
|
|
|
|
// 소멸자
|
|
CStorageInfo::~CStorageInfo()
|
|
{
|
|
m_vecStorageInfo.clear();
|
|
}
|
|
|
|
|
|
// 전달받은 경로로부터.. 상위 Path 정보를 추출하여 전달한다.
|
|
// 오류 발생시 [out] 값인 strUpperPath 가 empty 된다.
|
|
void CStorageInfo::GetUpperPath( const std::string & strSourcePath, std::string & strUpperPath )
|
|
{
|
|
// 인자로 전달되는 strSourcePath 끝에.. '/' 가 이미 제거되었다고 판단하고 작업을 수행한다.
|
|
std::string::size_type pos = strSourcePath.rfind( '/' );
|
|
if( pos == std::string::npos )
|
|
{
|
|
// 찾지 못한 경우...
|
|
// out 값을 empty 처리시킨다.
|
|
LOG( LNOT, "upper path not found. source[%s]", strSourcePath.c_str() );
|
|
strUpperPath.clear();
|
|
|
|
return;
|
|
}
|
|
|
|
// 찾은 경우..
|
|
strUpperPath = strSourcePath.substr( 0, pos );
|
|
|
|
// 추출된 경로가... 최상위 '/' 인 경우.. 유효하지 않으므로 오류로 처리한다.
|
|
if( strcmp( strUpperPath.c_str(), "/" ) == 0 )
|
|
{
|
|
LOG( LNOT, "upper path not vaild that root path. [%s]", strUpperPath.c_str() );
|
|
strUpperPath.clear();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// 초기화 함수
|
|
// - szRoot : Content 저장 최상위 경로 정보.
|
|
bool CStorageInfo::Init( const char * szRoot )
|
|
{
|
|
// 전달받은 최상위 경로 정보에 대한 Check
|
|
if( szRoot == NULL || strlen( szRoot ) <= 0 )
|
|
{
|
|
LOG( LERR, "storage root path not valid.");
|
|
return false;
|
|
}
|
|
|
|
// 추출된 정보 저장을 위한 임시변수
|
|
int iMountCount = 0;
|
|
struct statfs * pMountBuf = NULL;
|
|
std::vector< struct stStorageInfo > vecStorageAll;
|
|
std::vector< struct stStorageInfo >::iterator it;
|
|
struct stStorageInfo stStorage;
|
|
|
|
// 추출 정보 저장 및 멤버 변수 초기화
|
|
vecStorageAll.clear();
|
|
m_vecStorageInfo.clear();
|
|
|
|
// Mount 정보 추출
|
|
// - MNT_WAIT flag 사용시 정확한 정보를 추출, 하지만 block 발생 가능
|
|
// - 따라서 항상 정확한 정보를 추출할 필요는 없으며.. block 이 발생하지 않도록
|
|
// - MNT_NOWAIT flag 사용한다.
|
|
iMountCount = getmntinfo( &pMountBuf, MNT_NOWAIT );
|
|
if( iMountCount == 0 )
|
|
{
|
|
// 정보 추출 실패시 오류 내역 로깅
|
|
int errorNum = errno;
|
|
LOG( LERR, "Storage info init error. getmntinfo() fail[%d]. [%d][%s]"
|
|
, iMountCount, errorNum, strerror( errorNum ) );
|
|
return false;
|
|
}
|
|
|
|
// 추출된 mount 관련 모든 정보를 임시 변수에 저장
|
|
for( int i = 0; i < iMountCount; i++ )
|
|
{
|
|
stStorage.strName = pMountBuf[i].f_mntonname;
|
|
stStorage.strFsTypeName = pMountBuf[i].f_fstypename;
|
|
stStorage.ulUsedByte = ( pMountBuf[i].f_blocks - pMountBuf[i].f_bfree ) * pMountBuf[i].f_bsize;
|
|
stStorage.ulAvailableByte = pMountBuf[i].f_bavail * pMountBuf[i].f_bsize;
|
|
stStorage.usage = 0;
|
|
|
|
vecStorageAll.push_back( stStorage );
|
|
}
|
|
|
|
// 전달받은 mount 최상위 경로와 동일한 명칭의 mount 가 존재하는 검사
|
|
// - 이럴 경우는 거의 없는데.. 혹시나 해서 기능 탑재함.
|
|
for( it = vecStorageAll.begin(); it < vecStorageAll.end(); it++ )
|
|
{
|
|
if( strcmp( szRoot, it->strName.c_str() ) == 0 )
|
|
{
|
|
m_vecStorageInfo.push_back( *it );
|
|
}
|
|
}
|
|
|
|
// 전달받은 최상위 mount 정보와 동일한 명칭의 mount 가 존재하지 않는 경우..
|
|
// - sub path 부분을 제외한 후 다시 장비 Mount 정보와 비교한다.
|
|
// - 장비 mount 정보를 찾을 때까지 본 비교를 반복하여 수행한다.
|
|
if( m_vecStorageInfo.empty() == true )
|
|
{
|
|
std::string strPreviousPath = szRoot;
|
|
std::string strCurrentPath = szRoot;
|
|
|
|
do
|
|
{
|
|
// 수정된 경로 정보만을 가지고 부분 비교를 수행....
|
|
for( it = vecStorageAll.begin(); it < vecStorageAll.end(); it++ )
|
|
{
|
|
// 부분 비교 처리
|
|
if( strncmp( strCurrentPath.c_str(), it->strName.c_str(), strlen( strCurrentPath.c_str() ) ) == 0 )
|
|
{
|
|
m_vecStorageInfo.push_back( *it );
|
|
}
|
|
}
|
|
|
|
// 위에서 정보 추출이 실패한 경우..상위 Path 정보를 추출한다. ( /user2/dav_storage, /stg/node0/aa/bb 등으로 설정된 경우를 위해 )
|
|
if( m_vecStorageInfo.empty() == true )
|
|
{
|
|
GetUpperPath( strPreviousPath, strCurrentPath );
|
|
if( strCurrentPath.empty() == true )
|
|
{
|
|
// 상위 path 가 더이상 유효하지 않은 경우.
|
|
break;
|
|
}
|
|
|
|
strPreviousPath = strCurrentPath;
|
|
}
|
|
|
|
} while( m_vecStorageInfo.empty() == true );
|
|
}
|
|
|
|
// 임시 vector 에 저장된 내용 초기화
|
|
vecStorageAll.clear();
|
|
|
|
// 최종
|
|
if( m_vecStorageInfo.empty() == true )
|
|
{
|
|
LOG( LERR, "Storage info init error. root path[%s] not found in system mount.", szRoot );
|
|
return false;
|
|
}
|
|
|
|
// 추출 성공시
|
|
// - Storage 사용률 정보 계산해서 저장해 놓는다.
|
|
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
|
|
{
|
|
if( it->ulAvailableByte + it->ulUsedByte == 0 )
|
|
it->usage = 100;
|
|
else
|
|
{
|
|
// 사용률은 정수로 구하며... 나머지가 존재할 경우... 올림 처리한다.
|
|
it->usage = ( int ) ceil( ( double ) it->ulUsedByte / ( it->ulUsedByte + it->ulAvailableByte ) * 100.0 );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// 멤버 vector 에 저장된 경로의 Total Size, Total availsize, Max usage 정보를 반환.
|
|
bool CStorageInfo::GetStorageSizeInfo( uint64_t & ulFhsTotal, uint64_t & ulFhsAvailable, int & iMaxUsage )
|
|
{
|
|
// storage 정보가 비어 있는 경우
|
|
if( m_vecStorageInfo.empty() == true )
|
|
return false;
|
|
|
|
// output 인자 초기화.
|
|
ulFhsTotal = 0;
|
|
ulFhsAvailable = 0;
|
|
iMaxUsage = 0;
|
|
|
|
// total : 각 mount 의 used + available size 합계.
|
|
// available : 각 mount 의 합계.
|
|
// 최대 storage 사용률 정보 추출
|
|
|
|
std::vector< struct stStorageInfo >::iterator it;
|
|
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
|
|
{
|
|
// 전체 용량, 사용 가능 용량 합산
|
|
ulFhsTotal = ulFhsTotal + it->ulUsedByte + it->ulAvailableByte;
|
|
ulFhsAvailable = ulFhsAvailable + it->ulAvailableByte;
|
|
|
|
// 최대 사용률 정보 추출
|
|
if( it->usage > iMaxUsage )
|
|
{
|
|
iMaxUsage = it->usage;
|
|
}
|
|
|
|
// 2018-02-06 NEW huibong Storage 사용률이 90% 초과하는 경우 해당 Storage 의 정보를 로깅 처리한다.(#31701)
|
|
if( it->usage > 90 )
|
|
{
|
|
_LOG( LINF, "[Storage Info] storage usage: %s %3d %%, used[%14ju], avail[%14ju]."
|
|
, it->strName.c_str(), it->usage, it->ulUsedByte, it->ulAvailableByte );
|
|
}
|
|
else
|
|
{
|
|
_LOG( LDBG, "%s used[%14ju] avail[%14ju] usage[%3d %%]"
|
|
, it->strName.c_str(), it->ulUsedByte, it->ulAvailableByte, it->usage );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// 멤버 vector 에 저장된 mount 경로명 정보를 반환
|
|
bool CStorageInfo::GetStoragePath( std::vector<std::string>& vecPath )
|
|
{
|
|
// storage 정보가 비어 있는 경우
|
|
if( m_vecStorageInfo.empty() == true )
|
|
return false;
|
|
|
|
// output 인자 초기화.
|
|
vecPath.clear();
|
|
|
|
std::vector< struct stStorageInfo >::iterator it;
|
|
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
|
|
{
|
|
vecPath.push_back( it->strName );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// 멤버 vector 에 저장된 storage 정보 중에 ZFS file system 정보 존재하는지 Check
|
|
bool CStorageInfo::IsExistZFS()
|
|
{
|
|
// storage 정보가 비어 있는 경우 - ZFS file system 없는 것으로 처리
|
|
if( m_vecStorageInfo.empty() == true )
|
|
return false;
|
|
|
|
std::vector< struct stStorageInfo >::iterator it;
|
|
for( it = m_vecStorageInfo.begin(); it < m_vecStorageInfo.end(); it++ )
|
|
{
|
|
if( strcasecmp( "zfs", it->strFsTypeName.c_str() ) == 0 )
|
|
{
|
|
// zfs filesystem 이 존재하는 경우...
|
|
// - 나머지는 check 할 필요 없이 그냥 true 반환.
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// zfs filesystem 이 없는 경우
|
|
return false;
|
|
}
|