#include "StorageInfo.h" #include "Logger.h" #include #include #include #include #include #include #include #include #include // 생성자 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& 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; }