This commit is contained in:
biosvos
2026-08-07 17:38:18 +09:00
commit 873193a243
9613 changed files with 2755992 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
/***************************************************************************
Database Class
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2010 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <sstream>
#include "Database.h"
#include "Logger.h"
DataBase::~DataBase()
{
if(m_PGconn != NULL) {
PgCloseDB();
}
}
PGconn *DataBase::PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout)
{
ostringstream conninfo;
conninfo << "host=" << strHost << " port=" << Port << " dbname=" << strDBName <<
" user=" << strAcct << " password=" << strPasswd << " connect_timeout=" << timeout
<< " application_name=" << PROG_NAME;
#ifdef _USE_LIBPQ_KEEPALIVE
// This option is supported by at least 9.1.2. and Currently supports Linux systems.
conninfo <<" keepalives=1";
#endif // _USE_LIBPQ_KEEPALIVE
//m_PGconn = PQsetdbLogin(strHost.c_str(), szPort, NULL, NULL, strDBName.c_str(), strAcct.c_str(), strPasswd.c_str());
m_PGconn = PQconnectdb(conninfo.str().c_str());
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
return NULL;
}
return m_PGconn;
}
PGconn *DataBase::PgOpenDB(const char *pszDBName)
{
m_PGconn = PQsetdb(NULL, NULL, NULL, NULL, pszDBName);
if(PQstatus(m_PGconn) == CONNECTION_BAD) {
return NULL;
}
return m_PGconn;
}
void DataBase::PgCloseDB()
{
if(m_PGconn != NULL)
{
PQfinish(m_PGconn);
m_PGconn = NULL;
}
}
int DataBase::PgResult(CFLAG flag)
{
int fRet = 0;
int Result;
Result = PQresultStatus(m_pRes);
switch(Result) {
case PGRES_EMPTY_QUERY :
fRet = -1;
break;
case PGRES_BAD_RESPONSE :
fRet = -2;
break;
case PGRES_NONFATAL_ERROR :
fRet = -3;
break;
case PGRES_FATAL_ERROR :
fRet = -4;
break;
case PGRES_TUPLES_OK :
fRet = 1;
break;
case PGRES_COMMAND_OK :
fRet = 2;
break;
}
if(fRet < 0) {
m_ErrorMessage = PQresultErrorMessage(m_pRes);
}
m_ResultCode = Result;
if(flag == CLEAR && m_pRes) {
PQclear(m_pRes);
m_pRes = NULL;
}
return fRet;
}
string &DataBase::GetErrorMessage()
{
return m_ErrorMessage;
}
int DataBase::GetCmdTuples()
{
//fprintf(stderr, "DataBase::GetCmdTuples PQcmdTuples %s\n", PQcmdTuples(m_pRes));
return (int)atoi(PQcmdTuples(m_pRes));
}
int DataBase::GetNoTuples()
{
return PQntuples(m_pRes);
}
int DataBase::GetNoFields()
{
return PQnfields(m_pRes);
}
PGresult *DataBase::GetRes()
{
return m_pRes;
}
void DataBase::PgClear()
{
if(m_pRes)
{
PQclear(m_pRes);
m_pRes = NULL;
}
}
char *DataBase::GetValue(int tuple, int field)
{
return PQgetvalue(m_pRes, tuple, field);
}
int DataBase::PgDoExec(const char *pszQuery)
{
return this->PgDoExec(pszQuery, NOT_CLEAR);
}
int DataBase::PgDoExec(string &strQuery)
{
return this->PgDoExec(strQuery.c_str(), NOT_CLEAR);
}
int DataBase::PgDoExec(const char *pszQuery, CFLAG flag)
{
if(m_PGconn == NULL) return -1;
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
m_pRes = PQexec(m_PGconn, pszQuery);
int r = PgResult(flag);
return r;
}
int DataBase::PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag)
{
if(m_PGconn == NULL) return -1;
if(PQstatus(m_PGconn) != CONNECTION_OK) return -2;
m_pRes = PQexecParams(m_PGconn, pszQuery, nParamCnt, NULL, paramValues, NULL, NULL, 0);
int r = PgResult(flag);
return r;
}
int DataBase::PgEscapeString(char *to, const char *from, size_t length)
{
int retval = 0;
//PQescapeStringConn(m_PGconn, to, from, length, &retval);
PQescapeString(to, from, length);
return retval;
}
+56
View File
@@ -0,0 +1,56 @@
/***************************************************************************
Database Class
-----------------------------------------
begin : 2010/03/11
copyright : (C) 2010 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 1.0
CopyRight(C) 2010 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __DATABASE_H__
#define __DATABASE_H__
#include <iostream>
#include <string>
#include "libpq-fe.h"
#define MaxSizeOfDBQuery 1024*9
using namespace std;
class DataBase
{
public:
enum CFLAG { CLEAR = 1, NOT_CLEAR };
DataBase() { m_PGconn = NULL; m_pRes = NULL;}
~DataBase();
PGconn *PgOpenDB(string &strHost, int Port, string &strDBName, string &strAcct, string &strPasswd, int timeout = 10);
PGconn *PgOpenDB(const char *pszDBName);
void PgCloseDB();
int PgResult(CFLAG flag);
PGconn *GetPgConn(){ return m_PGconn;}
PGresult *GetRes();
void SetRes(PGresult * v) {m_pRes = v;}
int GetCmdTuples();
int GetNoTuples();
int GetNoFields();
int GetResultCode() { return m_ResultCode; }
char *GetValue(int tuple, int field);
void PgClear();
int PgDoExec(string &strQuery);
int PgDoExec(const char *pszQuery);
int PgDoExec(const char *pszQuery, CFLAG flag);
int PgDoExecParams(char *pszQuery, int nParamCnt, const char * const *paramValues ,CFLAG flag = NOT_CLEAR);
int PgEscapeString(char *to, const char *from, size_t length);
string &GetErrorMessage();
private:
int m_ResultCode;
PGconn *m_PGconn;
PGresult *m_pRes;
string m_ErrorMessage;
};
#endif // ~__DATABASE_H__
+64
View File
@@ -0,0 +1,64 @@
/***************************************************************************
ftsd control interface ( File Replication & Cache & Move & Delete Control) Header ( FtsdProtocol.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.R0811
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __FTSD_PROTOCOL_H__
#define __FTSD_PROTOCOL_H__
struct FileTransferPacketHeader {
char stx; // Packet 유효성 관리 코드
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
char command[4]; // Command Code ( 4 Byte) : 0th control-ftsd, 1th ftsd-ftsd 사용.
char result[4]; // Result Code ( 4 Byte )
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
};
// Packet Header stx 코드
#define HEADER_STX_CODE 0x02
// Packet Header type 구분코드
#define HEADER_TYPE_REQUEST 0x00
#define HEADER_TYPE_RESPONSE 0x01
// Packet command 공통.
#define COMMON_ALIVE_CHECK 0x7F
// Packet command : control 프로세스 <-> ftsd 통신 ( Command 첫번째 Byte 만 사용 )
#define NOT_CONTROL_COMMAND 0x00 // Control 이 전송한 요청이 아닌 경우.
#define CONTROL_FILE_REPLICATION 0x01 // Content 복제 생성 요청
#define CONTROL_FILE_CACHE 0x02 // Content 에 대해 Cache 폴더로 복제 요청
#define CONTROL_FILE_CHECK 0x03 // Content 에 대한 존재 여부, Size 확인 및 Hash 추출 요청
#define CONTROL_FILE_UNLINK 0x04 // Content 에 대한 unlink 처리 요청
// Packet Result : type이 Reponse 인 경우에만 세팅됨.( 첫번째 Byte 만 사용시 )
#define HEADER_RESULT_SUCCESS 0x00
#define HEADER_RESULT_ERROR 0x01
// 기타 정보
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
// unlink 요청시 Mode 설정 정보
#define UNLINK_MODE_NORMAL 0 // 해당 Content 가 존재하고 size 값이 정확한 경우에만 삭제, 나머지는 오류
#define UNLINK_MODE_FORCE 1 // 해당 Content 가 존재하지 않거나.. Size 값이 틀려도 강제로 삭제 처리.. 오류로 처리되는 상황은 통신, 시스템 오류 발생시.
#endif /* __FTSD_PROTOCOL_H__ */
File diff suppressed because it is too large Load Diff
+263
View File
@@ -0,0 +1,263 @@
/***************************************************************************
ftsd control interface ( File Replication & Cache & Move & Delete Control) Header ( FtsdSocketControl.h )
-----------------------------------------
begin : 2010/03/09
copyright : (C) 2005 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.2.0.R0811
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __FTSD_SOCKET_CONTROL_H__
#define __FTSD_SOCKET_CONTROL_H__
#include "BaseSocket.h"
#include "FtsdProtocol.h"
#include <iostream>
#include <vector>
#include <map>
///< BYTE 타입 정의
#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef unsigned char BYTE;
#endif // _BYTE_DEFINED
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // SocketControl 에서 사용할 임시버퍼 크기.
class CFtsdSocketControl : public CBaseSocket
{
private:
/// @brief Packet Header 변수
struct FileTransferPacketHeader m_packetHeader;
/// @brief m_packetHeader 구조체의 크기를 저장하기 위한 상수
const int m_nPacketHeaderLen;
/// @brief Packet Header 에 저장된 Data 부분의 길이 정보값.
unsigned int m_nPacketDataLen;
/// @brief Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
public:
/// @brief 생성자.
CFtsdSocketControl();
/// @brief 소멸자.
~CFtsdSocketControl();
/// @brief 전달받은 Target 으로 Socket 접속을 수행
/// @param szTarget [in] 접속 대상 Host name 또는 IP
/// @param nPort [in] 접속 Port
/// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool ConnectTarget( const std::string& szTarget, int nPort );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 File Replication 명령 전송.
/// @param szFileName [in] 복제할 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] 복제할 원본 Source 파일의 크기.
/// @param szTargetTranId [in] RC 간 복제 처리시 변경할 대상 Tran ID 정보 값.
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
///< RC-RC 간 처리시에는 사용하지 않도록 false 로 지정할 것.
/// @param vecTargetFhs [in] 복제 대상 Target FHS Host Name 정보
/// @return Replication 복제 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
bool SendFileReplicationRequest(const std::string& szFileName, unsigned long long nFileSize, const std::string& szTargetTranId, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
/// @brief File Replication 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Replication 이 정상적으로 수행되었는지 여부 \n
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
///< Replication 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
///< Replication 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
///
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 로부터
///< Replication 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 복제 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 로 부터 Data 을 수신하였으나 File Replication 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileReplicationResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, std::map< std::string, std::string>& mapSuccessFhs, std::map< std::string, std::string>& mapFailFhs );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 File Cache 명령 전송.
/// @param szFileName [in] Cache 처리할 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] Cache 처리할 원본 Source 파일의 크기.
/// @param nFileHashCheckLevel [in] File 에 대한 Hash Check Level 정보 ( conf 파일에 지정됨)
/// @param bUseInternalIp [in] 내부망을 이용하여 파일 송수신을 수행할지 여부 \n
///< 해당값을 true 로 지정시 ftsd 상에서 내부망을 우선 사용하여 파일 복제 시도
///< 만약 내부망 사용 불가시 자동으로 외부망 사용.
/// @param vecTargetFhs [in] Cache 대상 Target FHS Host Name 정보
/// @return Cache 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileCacheRequest(const std::string& szFileName, unsigned long long nFileSize, int nFileHashCheckLevel, bool bUseInternalIp, std::vector< std::string >& vecTargetFhs);
/// @brief File Cache 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Cache 처리가 정상적으로 수행되었는지 여부 \n
///< trnsfer 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< mapSuccessFhs, mapFailFhs 상에 관련 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param mapSuccessFhs [out] bSuccess == true 인 경우 \n
///< Cache 처리에 성공한 FHS 및 저장된 File 이름 정보를 저장
/// @param mapFailFhs [out] bSuccess == true 인 경우 \n
///< Cache 처리에 실패한 FHS Host Name 및 발생된 오류메시지 정보를 저장.
///
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 로부터
///< Cache 에 대한 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Cache 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 로 부터 Data 을 수신하였으나 File Cache 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileCacheResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, std::map< std::string, std::string>& mapSuccessFhs, std::map< std::string, std::string>& mapFailFhs );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Content Check 명령 전송.
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param bHashCheck [in] Hash 값을 추출할지 여부
/// @param nHashCheckSize [in] Hash 값을 추출할 경우 Size 설정값 ( MByte 단위 )\n
///< 0 : Content 에 대한 전체 Hash 값을 추출함.
///< 숫자 : Content 의 앞 부분부터 지정된 크기 (MByte ) 까지 Hash 값을 추출
/// @return Check 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileCheckRequest(const std::string& szFileName, bool bHashCheck, unsigned long long nHashCheckSize );
/// @brief File Check 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File Check 처리가 정상적으로 수행되었는지 여부 \n
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 \n
///< nFileSize, szHashValue 상에 결과 정보가 저장됨.
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @param nFileSize [out] bSuccess == true 인 경우 요청한 Content 에 대한 file size 정보를 저장. ( Byte 단위 )
/// @param szHashValue [out] bSuccess == true 이고... Hash 값 추출을 요청한 경우 추출된 Hash 값 정보를 저장.
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Check 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Check 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileCheckResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage, unsigned long long& nFileSize, std::string& szHashValue );
/// @brief 대상과 연결된 Socket 을 통해 ftsd 로 Unlink 명령 전송.
/// @param szFileName [in] 원본 Source 파일명 (/stg/node0/186/abcde..)
/// @param nFileSize [in] 원본 파일의 크기 ( Byte 단위 )
/// @param bForceUnlink [in] 강제 삭제 처리 여부 ( Defalult false )
/// false : 일반모드 - 해당 파일이 존재하고 Size 값이 동일할 경우에만 삭제처리.. 나머지는 오류로 처리.
/// true : 강제모드 - 해당 파일이 존재하지 않거나.. Size 가 틀려도 강제로 삭제 처리.. 오류는 통신, 시스템 오류 발생시에만
/// @return Unlink 요청 메시지 전송 성공시 true, 실패시 false 반환.
bool SendFileUnlinkRequest(const std::string& szFileName, unsigned long long nFileSize, bool bForceUnlink = false );
/// @brief File Unlink 요청에 대한 처리 결과를 ftsd 로 부터 수신한다.
/// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )\n
///< 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
/// @param bSuccess [out] File unlink 처리가 정상적으로 수행되었는지 여부 \n
///< ftsd 상에서 오류가 발생한 경우 이 값은 false 가 되며 \n
///< szErrorMessage 변수상에 오류내용이 저장됨. \n
///< 정상적으로 처리된 경우 true 가 저장되며 따로 수신하는 Data 는 없음. \n
/// @param szErrorMessage [out] bSuccess == false 인 경우 발생된 오류메시지 정보를 저장
/// @return -1 : Socket 통신 관련 오류 발생하여 ftsd 와 연결이 끊어진 경우 \n
///< => ftsd 와 연결이 끝어진것으로 판단하고 오류처리한다. \n
///<
///< 0 : 입력변수인 nTimeout 에 지정된 시간안에 ftsd 으로부터 처리 결과 정보를 수신하지 못한 경우. \n
///< 이 기능은 본 함수 호출시 Blocking 발생을 막기 위한 기능으로서 \n
///< 이 값이 반환된 경우 추가 다른 작업을 진행한 후 본 함수를 다시 호출하여 \n
///< 응답을 대기할 수 있다. \n
///<
///< 1 : 파일 Unlink 처리에 대한 응답을 수신한 경우, Output 인자인 bSuccess 를 확인하여 처리 결과 확인
///<
///< 2 : ftsd 으로 부터 Data 을 수신하였으나 File Unlink 요청에 대한 응답이 아닌 경우 \n
///< 해당 정보는 본 클래스의 멤버변수 상에 내부적으로 저장된다. ( 단 Alive Packet 은 아님) \n
///< 본 결과가 수신된 경우 무시 처리하고 계속 응답을 대기하면 된다.
int GetFileUnlinkResult( int nTimeout, bool& bSuccess, std::string& szErrorMessage );
/// @brief 연결된 Socket 통신을 이용하여 내부적으로 정의된 Alive Check 패킷 전송 \n
///< => 해당 패킷에 대한 처리는 내부적으로 처리되어 결과값을 확인할 필요는 없다.
/// @return Socket 연결 해제 또는 전송 관련 오류 발생시 false, 전송 성공시에는 true 반환.
bool SendAliveCheck(void);
/// @brief Packet Header 정보를 Log 파일에 Logging 처리 ( Debug 처리를 위한 함수)
void PrintHeaderToLog(void);
protected:
/// @brief Packet Header 부분의 수신 처리를 위한 함수. Alive Check 요청 패킷은 자동으로 무시처리함.
/// @param timeout [in] 대기시간.
/// @retrun 성공시 true, 오류 발생및 실패시 fasle 반환.
bool GetPacketHeader(int timeout = DEFAULT_DATA_RECEIVE_TIMEOUT);
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
/// @param size [in] read 할 데이터 크기
/// @param value [out] 읽은 데이터를 저장할 string 변수
/// @return On success return true, otherwise return false.
bool GetPacketData( unsigned int& size, std::string& value );
/// @brief socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
/// @param size [in] read 할 데이터 크기
/// @return On success return true, otherwise return false.
bool GetPacketData( unsigned int size );
/// @brief pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
/// @brief pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
unsigned long long GetDataToUInt64( BYTE * pValue );
};
#endif /* __FTSD_SOCKET_CONTROL_H__ */
+84
View File
@@ -0,0 +1,84 @@
#****************************************************************************
# Makefile for RC Contents Move Tool
# -----------------------------------------
#
# begin : 2012/05/13
# copyright : (C) 2011 SolutionBox Inc.
# author : Service 1 Team
# email : svc1@solbox.com
# version : 3.1.0
#
# CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
# Redistribution and use in source and binary forms, with or with out
# modification, are not permitted in outside of SolutionBox Inc.
#*****************************************************************************
# Program info
PROG_NAME = rc_cmove
REVISION = 1446
BUILD_DATE = `date +%Y%m%d%H%M%S`
PROG_VERSION = 3.5.0.$(REVISION)-$(BUILD_DATE)
DEFAULT_CONFIG_FILE = /user/service/etc/rcts.conf
INSTALL_BIN = /user/service/bin
# Compiler info
CC = /usr/bin/g++
CFLAGS = -Wall -O3 -g -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS -Wno-unused -Wno-non-virtual-dtor -Wno-deprecated
LFLAGS = -lpthread -lcrypt
# DEBUG or RELEASE Mode select
ifeq ($(DEBUG), yes)
PROG_VERSION = 3.1.0.$(REVISION)D-$(BUILD_DATE)
CFLAGS = -Wall -O0 -g -Wreturn-type -Wunused -Wuninitialized\
-Wparentheses -Wshadow -Wpointer-arith -Woverloaded-virtual\
-fno-rtti -D_THREAD_SAFE -D_REENTRANT -D_PTHREADS -Wno-unused -Wno-non-virtual-dtor
DFLAGS = -D_DEBUG -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -D_USE_POSIX_LOCK
else
DFLAGS = -DPROG_NAME=\"$(PROG_NAME)\" -DPROG_VERSION=\"$(PROG_VERSION)\" -DDEFAULT_CONFIG_FILE=\"$(DEFAULT_CONFIG_FILE)\" -D_USE_POSIX_LOCK
endif
# Application Enviroment
APP = $(PROG_NAME)
DIR_LIB = -L../lib
DIR_INCLUDE = -I./. -I../lib -I/user/db/pgsql/include
LIBS = ../lib/libInterCommon.a /user/db/pgsql/lib/libpq.a
OBJ = Database.o comonusefn.o dbconnpool.o parameter.o \
RcSyncdClientSocket.o RcSyncdRequest.o \
FtsdSocketControl.o synchronization.o validation.o \
workpool.o jobmanager.o monitoring.o main.o
############################
all:$(APP)
sync
%.o: %.cpp
$(CC) $(CFLAGS) -o $@ -c $^ $(DFLAGS) $(DIR_INCLUDE)
$(PROG_NAME): $(OBJ)
$(CC) $(LFLAGS) -o $@ $^ $(DFLAGS) $(DIR_LIB) $(LIBS)
clean:
-rm -f *.o core.* *.out *.log
-rm -f $(APP)
sync
install : $(APP)
-cp $(APP) $(INSTALL_BIN)/$(APP)
sync
# End of Makefile
+320
View File
@@ -0,0 +1,320 @@
#include "RcSyncdClientSocket.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
// 생성자.
CRcSyncdClientSocket::CRcSyncdClientSocket()
: CBaseSocket( SOCKET_NOT_VALID )
, m_nPacketHeaderLen ( sizeof(m_packetHeader))
, m_nPacketDataLen( 0 )
{
}
// 소멸자
CRcSyncdClientSocket::~CRcSyncdClientSocket()
{
// 소멸자 Socket 명시적 Close 처리.
Close();
}
// 전달받은 Target 으로 Socket 접속을 수행
// @param szTarget [in] 접속 대상 Host name 또는 IP
// @param nPort [in] 접속 Port
// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool CRcSyncdClientSocket::ConnectTarget( const std::string& szTarget, int nPort )
{
return Connect( szTarget, nPort );
}
// rc_syncd 로 sync 명령 전달.
// - CReqMasterData class 멤버변수 수정시 본 함수 수정 필요함.
bool CRcSyncdClientSocket::SendSyncRequest( CReqMasterData& request )
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct RcSyncdPacketHeader stHeader;
memset( &stHeader, 0x00, sizeof( struct RcSyncdPacketHeader ) );
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = CLIENT_COMMAND_SYNC;
// Data 부분의 길이를 계산한다.
unsigned int nTemp = 0;
nTemp = 4; // sync_type
nTemp += ( 4 + request.start_time.size() ); // start_time
nTemp += ( 4 + request.end_time.size() ); // end_time
nTemp += ( 4 + request.one_service.size() ); // one_service
stHeader.data_length = htonl( nTemp );
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
{
LOG( LERR, "request[CLIENT_COMMAND_SYNC] send fail to rc_syncd. " );
return false;
}
else
{
// Data 부분 전송
// 1. sync_type
nTemp = htonl( request.sync_type );
WriteN( &nTemp, 4 );
// 2. start_time
SendString( request.start_time );
// 3. end_time
SendString( request.end_time );
// 4. one_service
SendString( request.one_service );
}
LOG( LDBG, "request[CLIENT_COMMAND_SYNC] send OK. type[%d] time[%s]~[%s] svc[%s]"
, request.sync_type, request.start_time.c_str(), request.end_time.c_str()
, (request.one_service.empty() == true ? "ALL" : request.one_service.c_str()) );
return true;
}
// rc_syncd 로 부터 sync 요청에 대한 결과 수신.
int CRcSyncdClientSocket::GetSyncResult( int nTimeout, bool& bSuccess, std::string& strMessage )
{
if( IsValidSocket() == false )
return -1;
int nRead;
bool isAlivePacket;
do
{
isAlivePacket = false;
// Socket 으로 부터 Packet Header 부분 수신.
// 수신된 정보는 멤버변수에 저장처리.
nRead = ReadNTimeout( &m_packetHeader, m_nPacketHeaderLen, nTimeout );
// nRead 0: Socket Closed
// -1: error
// -2: Timeout 이므로
if( nRead == -2 )
return 0; // Timeout 반환.
else if( nRead == 0 || nRead == -1 )
return -1; // Socket Close 또는 오류 발생시
// STX code 검사.
if( m_packetHeader.stx != HEADER_STX_CODE )
{
LOG( LERR, "Not valid stx code." );
return -1;
}
// Data Length 부분 값을 멤버 변수에 저장처리.
m_nPacketDataLen = ntohl( m_packetHeader.data_length );
// Alive Check Packet 인 경우 해당 패킷은 무시처리 후 다시 수신 처리한다.
if( m_packetHeader.type == HEADER_TYPE_REQUEST
&& m_packetHeader.command[0] == COMMON_ALIVE_CHECK
&& m_nPacketDataLen == 0 )
{
isAlivePacket = true;
}
} while( isAlivePacket == true );
// Alive Packet 이 아닌 경우 해당 Packet 에 대한 응답패킷인지 검사.
if( m_packetHeader.type != HEADER_TYPE_RESPONSE
|| m_packetHeader.command[0] != CLIENT_COMMAND_SYNC )
{
// 다른 패킷이 들어온 경우
// ** 정석대로라면 그냥 냅둬어 수신부에서 처리해야 하지만
// 현재 수신 처리부가 없어 당장 문제가 생길수 있으므로
// 데이터 부분까지 수신하여 임시버퍼에 저장처리 해 놓는다.
GetPacketData( m_nPacketDataLen );
return 2;
}
// Sync 요청에 대한 응답패킷인 경우.
// 1. 성공, 실패 여부 판단.
if( m_packetHeader.result[0] != HEADER_RESULT_SUCCESS )
bSuccess = false;
else
bSuccess = true;
// 2. Data 부분에 대한 처리
// - Message 부분이 존재할 수 있으므로..
// 성공/실패 구분 없이 모두 Data 부분 수신 처리한다.
if( m_nPacketDataLen > 0 )
{
if( GetPacketData( m_nPacketDataLen, strMessage ) == false )
{
LOG( LERR, "data body receive failed." );
return -1;
}
}
return 1;
}
// Alive Check 를 위한 패킷 전송 => 해당 패킷에 대한 응답은 필요없으므로 수신시 자동 무시처리됨.
// @return 전송 성공시 true, 실패시 false 반환.
bool CRcSyncdClientSocket::SendAliveCheck()
{
if( IsValidSocket() == false )
return false;
// 정보 요청을 위한 Packet Header 생성.
struct RcSyncdPacketHeader stHeader;
memset( &stHeader, 0x00, sizeof( struct RcSyncdPacketHeader ) );
stHeader.stx = HEADER_STX_CODE;
stHeader.type = HEADER_TYPE_REQUEST;
stHeader.command[0] = COMMON_ALIVE_CHECK;
// Packet Header 정보 전송
if( WriteN( &stHeader, m_nPacketHeaderLen ) != m_nPacketHeaderLen )
return false;
return true;
}
// Packet Header 정보를 Log 파일에 Logging 처리
void CRcSyncdClientSocket::PrintHeaderToLog()
{
_LOG( LINF, "------------------------------------" );
_LOG( LINF, "stx [%02x]", m_packetHeader.stx );
_LOG( LINF, "type [%02x]", m_packetHeader.type );
_LOG( LINF, "command [%02x][%02x][%02x][%02x]", m_packetHeader.command[0], m_packetHeader.command[1], m_packetHeader.command[2], m_packetHeader.command[3] );
_LOG( LINF, "result [%02x][%02x][%02x][%02x]", m_packetHeader.result[0], m_packetHeader.result[1], m_packetHeader.result[2], m_packetHeader.result[3] );
_LOG( LINF, "data_length [%u]", m_nPacketDataLen );
_LOG( LINF, "extend_code [%02x][%02x]", m_packetHeader.extend_code[0], m_packetHeader.extend_code[1] );
_LOG( LINF, "------------------------------------" );
}
//////////////////////////////////////////////////////////////////////////////////
// Packet 정보 중 String 정보를 전송하기 위한 함수.
bool CRcSyncdClientSocket::SendString( const std::string& strData )
{
if( IsValidSocket() == false )
return false;
// 크기값을 저장하기 위한 임시 변수.
unsigned int nSize = 0;
// String Data 전송
nSize = htonl( strData.size() );
WriteN( &nSize, 4 );
if( strData.size() > 0 )
WriteN( strData.c_str(), strData.size() );
return true;
}
// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
// @param size [in] read 할 데이터 크기
// @param value [out] 읽은 데이터를 저장할 string 변수
// @return On success return true, otherwise return false.
bool CRcSyncdClientSocket::GetPacketData( unsigned int& size, std::string& value )
{
// 1. 수신할 크기가 임시버퍼보다 큰 경우 새로운 버퍼를 생성한다.
BYTE * pBuffer = NULL;
bool bNewBufferCreated = false;
if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
{
pBuffer = new BYTE[size]; // 신규 메모리 할당.
bNewBufferCreated = true;
}
else
pBuffer = m_tempBuffer;
// 2. 데이터 수신 처리.
int nRead = ReadNTimeout( pBuffer, size );
// 오류 발생시
if( nRead <= 0 )
{
// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
if( bNewBufferCreated == true )
delete[] pBuffer;
return false;
}
// 3. 수신 데이터 저장 처리 - 기존 데이터 뒤에 붙여 준다=> 이게 사용하기 편함.
value.append( (char *)pBuffer, size );
// 신규로 생성된 버퍼인 경우 메모리 해제 처리.
if( bNewBufferCreated == true )
delete[] pBuffer;
return true;
}
// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
// @param size [in] read 할 데이터 크기
// @return On success return true, otherwise return false.
bool CRcSyncdClientSocket::GetPacketData( unsigned int size )
{
// 1. 수신할 크기가 임시버퍼보다 큰 경우 오류 반환.
if( size > DEFAULT_SOCKET_TEMP_BUFFER_SIZE )
return false;
// 2. 데이터 수신 처리.
int nRead = ReadNTimeout( m_tempBuffer, size );
// 오류 발생시
if( nRead <= 0 )
return false;
// 3. 정상인 경우는 ReadNTimeout 함수가 무조건 요청 크기만큼 read 처리하므로 정상수신임.
return true;
}
// 전달받은 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
unsigned int CRcSyncdClientSocket::GetDataToUInt( BYTE * pValue, bool bConvertEndian )
{
BYTE tempBuffer[4];
unsigned int result;
memcpy(tempBuffer, pValue, 4);
unsigned int * pInt = (unsigned int *)tempBuffer;
// Endian 변환처리.
if( bConvertEndian == true )
{
result = ntohl( *pInt );
}
else
result = *pInt;
return result;
}
// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
unsigned long long CRcSyncdClientSocket::GetDataToUInt64( BYTE * pValue )
{
unsigned long long * pResult;
BYTE tempBuffer[8];
memcpy(tempBuffer, pValue, 8);
pResult = (unsigned long long *)tempBuffer;
return *pResult;
}
+132
View File
@@ -0,0 +1,132 @@
/***************************************************************************
client 에서 rc_syncd 와의 통신을 수행하기 위한 class
-----------------------------------------
begin : 2014/09/15
copyright : (C) 2005 Solbox Inc.
author : Storage Dev Team
email : storage.sd@solbox.com
version : 3.4
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __RC_SYNCD_CLIENT_SOCKET_H__
#define __RC_SYNCD_CLIENT_SOCKET_H__
#include "BaseSocket.h"
#include "RcSyncdProtocol.h"
#include "RcSyncdRequestData.h"
#include <string>
///< BYTE 타입 정의
#ifndef _BYTE_DEFINED
#define _BYTE_DEFINED
typedef unsigned char BYTE;
#endif // _BYTE_DEFINED
#define DEFAULT_SOCKET_TEMP_BUFFER_SIZE 1024 // Socket 관련 data 송수신시 사용할 임시버퍼 크기.
// CRcSyncdClientSocket
// 내부 또는 외부 모듈에서 rc_syncd 와 통신 수행시...
// 함수 수준의 단순 Interface 지원 목적을 위한 통신 관련 처리 class
class CRcSyncdClientSocket : public CBaseSocket
{
public:
// 생성자
CRcSyncdClientSocket();
// 소멸자
~CRcSyncdClientSocket();
// 전달받은 Target 으로 Socket 접속을 수행
// @param szTarget [in] 접속 대상 Host name 또는 IP
// @param nPort [in] 접속 Port
// @return 접속 성공시 true, 실패시 false 반환. ( 오류 내역은 로깅처리됨.)
bool ConnectTarget( const std::string& szTarget, int nPort );
// rc_syncd 로 sync 명령 전달.
// - CReqMasterData class 멤버변수 수정시 본 함수 수정 필요함.
// @param request [in] 요청 정보 저장 객체
// @return true 요청 성공시
// fasle 유효하지 않은 인자값 또는 전송 실패시
bool SendSyncRequest( CReqMasterData& request );
// rc_syncd 로 부터 sync 요청에 대한 결과 수신.
// @param nTimeout [in] 함수 호출에 대한 Blocking 을 방지하기 위한 Timeout 설정값. 단위( second )
// 지정된 시간동안 응답을 수신하지 못한 경우 0 을 반환.
// @param bSuccess [out] 성공 여부
// @param strMessage [out] rc_syncd 로부터 처리 관련 수신된 메시지
// @return
// -1 : rc_syncd 와 통신이 끊어진 경우.
// 0 : rc_syncd 로 부터 응답을 아직 수신하지 못한 경우..
// - 함수 blocking 방지 목적
// => AliveCheck 등의 작업 후 다시 응답 대기하면 된다.
// 1 : Sync 요청에 대한 응답을 수신한 경우
// 2 : Sync 요청에 대한 응답이 아닌 경우..
// => 무시 처리하고 계속 응답을 대기하면 된다.
int GetSyncResult( int nTimeout, bool& bSuccess, std::string& strMessage );
// Alive Check 를 위한 패킷 전송 => 해당 패킷에 대한 응답은 필요없으므로 수신시 자동 무시처리됨.
// @return 전송 성공시 true, 실패시 false 반환.
bool SendAliveCheck( void );
// Packet Header 정보를 Log 파일에 Logging 처리
// - 통신 오류 발생시 로깅을 통한 디버깅 지원 목적
void PrintHeaderToLog( void );
private:
// Packet Header 변수
struct RcSyncdPacketHeader m_packetHeader;
// m_packetHeader 구조체의 크기를 저장하기 위한 상수
const int m_nPacketHeaderLen;
// Packet Header 에 저장된 Data 부분의 길이 정보값.
unsigned int m_nPacketDataLen;
// Packet Data 부분의 수신처리시 임시로 사용할 버퍼.
BYTE m_tempBuffer[DEFAULT_SOCKET_TEMP_BUFFER_SIZE];
protected:
// Packet 정보 중 String 정보를 전송하기 위한 함수.
bool SendString( const std::string& strData );
// socket 에서 지정된 크기만큼의 데이터를 읽어 출력변수에 저장처리.
// @param size [in] read 할 데이터 크기
// @param value [out] 읽은 데이터를 저장할 string 변수
// @return On success return true, otherwise return false.
bool GetPacketData( unsigned int& size, std::string& value );
// socket 에서 지정된 크기만큼의 데이터를 읽어 내부 임시버퍼인 m_tempBuffer 에 저장처리.
// @param size [in] read 할 데이터 크기
// @return On success return true, otherwise return false.
bool GetPacketData( unsigned int size );
// pValue 에 저장된 데이터를 unsigned int 형으로 변환처리 및 Endian 변환
unsigned int GetDataToUInt( BYTE * pValue, bool bConvertEndian = true );
// pValue 에 저장된 데이터를 unsigned long long (64Byte) 형으로 변환처리.
unsigned long long GetDataToUInt64( BYTE * pValue );
};
#endif /* __RC_SYNCD_CLIENT_SOCKET_H__ */
+67
View File
@@ -0,0 +1,67 @@
/***************************************************************************
rc_syncd 통신 관련 protocol header
-----------------------------------------
begin : 2014/09/04
copyright : (C) 2005 Solbox Inc.
author : Storage Dev Team
email : storage.sd@solbox.com
version : 3.4
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __RC_SYNCD_PROTOCOL_H__
#define __RC_SYNCD_PROTOCOL_H__
// rc_syncd 에서 사용할 통신 Header 구조체
// - 계산상 크기는 16Byte 이지만...
// - 통신상 sizeof() : 20Byte ( 64Bit OS )
struct RcSyncdPacketHeader {
char stx; // Packet 유효성 관리 코드
char type; // Request or Response 여부 ( 0x00: Request, 0x01: Response )
char command[4]; // Command Code ( 4 Byte) : 0th client-rc_syncd, 1th rc_syncd - rc_syncd 간 사용.
char result[4]; // Result Code ( 4 Byte )
unsigned int data_length; // Packet Data 부분의 길이값 ( Network Byte Order 사용)
char extend_code[2]; // 확장 및 Padding bits ( 2 Byte )
};
// Packet Header stx 코드
#define HEADER_STX_CODE 0x03
// Packet Header type 구분코드
#define HEADER_TYPE_REQUEST 0x00
#define HEADER_TYPE_RESPONSE 0x01
// Packet command 공통.
#define COMMON_ALIVE_CHECK 0x7F
// Packet command
// client <-> rc_syncd 통신 (command 0th byte 만 사용)
#define NOT_CLIENT_COMMAND 0x00 // Client 에서 전송한 요청이 아닌 경우.
#define CLIENT_COMMAND_SYNC 0x01 // Client 에서 동기화 수행 요청
// Packet command
// rc_syncd <-> rc_syncd 간의 내부 통신 (command 1st byte 만 사용)
#define PROCESS_CONTENT_LIST 0x01 // Content 정보 목록 요청 => RCDB 에서 Content 정보 추출 후 전달
#define PROCESS_CONTENT_SYNC 0x02 // 동기화 수행 요청 (동기화 대상 목록 전달) => 동기화 수행 후 결과 전달.
// Packet Result
// => type이 Response 인 경우에만 세팅됨.( 0th Byte 만 사용시 )
#define HEADER_RESULT_SUCCESS 0x00
#define HEADER_RESULT_ERROR 0x01
// 기타 정보
#define LENGTH_FIELD_SIZE 4 // 가변데이터 형식 사용시 Length 필드의 메모리 크기 (unsigned int)
#endif /* __RC_SYNCD_PROTOCOL_H__ */
+123
View File
@@ -0,0 +1,123 @@
#include "RcSyncdRequest.h"
#include "Logger.h"
#include "RcSyncdClientSocket.h" // rc_syncd 와 통신을 처리할 client socket 객체 생성 및 접속
#include <iostream>
#define RC_SYNCD_HOST "127.0.0.1" // rc_syncd host
#define RC_SYNCD_PORT 14002 // OP_PORT = 14002
CRcSyncdRequest::CRcSyncdRequest()
{
}
CRcSyncdRequest::~CRcSyncdRequest()
{
}
void CRcSyncdRequest::SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime)
{
SendSyncRequest(nSyncType, strStartTime, strEndTime, "");
}
void CRcSyncdRequest::SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime, const std::string& strService)
{
bool bResultSuccess = false; // 처리 결과의 성공/실패 여부를 저장하기 위한 변수.
std::string strMessage; // 수신 메시지 저장 변수.
int nResult = 0;
int nTimeout = 5; // 5sec에 한번씩 Alive Check하기 위함
// 요청 데이타 생성
CReqMasterData request;
request.sync_type = (SYNC_TYPE::SYNC_TYPE)nSyncType;
request.start_time = strStartTime;
request.end_time = strEndTime;
request.one_service = strService;
// local rc_syncd와 통신을 처리할 client socket 객체 생성 및 접속
CRcSyncdClientSocket client;
if (client.ConnectTarget(RC_SYNCD_HOST, RC_SYNCD_PORT) == false)
{
// local rc_syncd 으로 접속 실패시
_LOG(LERR, "sync connect fail. [%s][%d]", RC_SYNCD_HOST, RC_SYNCD_PORT);
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
<< "Sync Server connect fail. [" << RC_SYNCD_HOST << "][" << RC_SYNCD_PORT << "]" << std::endl;
return ;
}
// rc_syncd로 sync 요청 전달
if( client.SendSyncRequest( request ) == false )
{
// 전송 실패시
_LOG( LERR, "Sync request send fail");
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
<< "Sync request send fail" << std::endl;
return ;
}
// 루프를 돌면서 요청에 대한 응답을 대기
while(1)
{
// nTimeout 에 지정된 시간동안 응답대기
nResult = client.GetSyncResult( nTimeout, bResultSuccess, strMessage);
if( nResult == -1 )
{
// Socket 통신 관련 오류 또는 접속 종료가 발생한 경우.
// 해당 내역 로깅 및 루프 종료
_LOG( LERR, "Response wait fail by socket" );
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
<< "Response wait fail by socket" << std::endl;
break;
}
else if( nResult == 0 )
{
// 지정된 시간 동안 응답대기 중 처리 결과 정보가 아직 수신되지 않은 경우 => Alive Check 패킷 한번 쏘고 다시 Loop 로
if( client.SendAliveCheck() == false )
{
// Alive 전송 실패시 => Socket 종료 및 오류가 발생한 경우임.
_LOG( LERR, "Response wait fail by socket2");
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
<< "Response wait fail by socket2" << std::endl;
break;
}
LOG( LDBG, "Response wait");
// 정상적인 경우 다시 응답대기.
continue;
}
else if( nResult == 1 )
{
// 요청에 대한 처리결과 정보가 수신된 경우.
// 해당 정보 로깅처리.
if( bResultSuccess == true )
{
// 요청에 대한 처리가 정상적으로 처리된 경우
_LOG( LINF, "Sync result SUCCESS [%s]", strMessage.c_str() );
std::cout << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LINF\"] "
<< "Sync result SUCCESS [" << strMessage << "]" << std::endl;
}
else
{
// 오류 발생시
_LOG( LERR, "Sync result ERROR [%s]", strMessage.c_str() );
std::cerr << "[PID:" << getpid() << "-" << pthread_self() << "] [\"LERR\"] "
<<"Sync result ERROR[[" << strMessage << "]" << std::endl;
}
break; // 응답을 받았으니 응답 대기 루프 종료
}
else
{
// Replication 요청에 대한 응답패킷이 아닌 경우.
// 해당 패킷은 무시하고 다시 Loop 로
continue;
}
}
sleep(1);
client.Close();
}
+32
View File
@@ -0,0 +1,32 @@
/****************************************************************************
Synchronization Class Header
-----------------------------------------
begin : 2014/09/17
copyright : (C) 2005 Solbox Inc.
author : Storage Dev Team
email : storage.sd@solbox.com
version : 3.4
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
*****************************************************************************/
#ifndef __RCSYNCDREQUEST_H__
#define __RCSYNCDREQUEST_H__
#include "RcSyncdRequestData.h"
class CRcSyncdRequest
{
public:
CRcSyncdRequest();
~CRcSyncdRequest();
void SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime);
void SendSyncRequest(int nSyncType, const std::string& strStartTime, const std::string& strEndTime, const std::string& strService);
private:
};
#endif /* __RCSYNCDREQUEST_H__ */
+93
View File
@@ -0,0 +1,93 @@
/***************************************************************************
rc_syncd Request Data Header ( RcSyncdRequestData.h )
- used : rc_cmove, rc_syncd(Scheduler)
-----------------------------------------
begin : 2014/09/02
copyright : (C) 2005 Solbox Inc.
author : Storage Dev Team
email : storage.sd@solbox.com
version : 3.4
CopyRight(C) 2005 Solbox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of Solbox Inc.
***************************************************************************/
#ifndef __RC_SYNCD_REQUEST_DATA_H__
#define __RC_SYNCD_REQUEST_DATA_H__
#include <list>
#include <string>
using namespace std;
namespace SYNC_TYPE
{
enum SYNC_TYPE
{
NORMAL = 0, // 동기화 요청(O), 모든 데이터 (복제, 캐쉬 제외)
NORMA_N_ONLY = 1, // 동기화 요청(O), deleted_yn = N
CHK_ONLY = 3, // 동기화 요청(X), 모든 데이터 (복제, 캐쉬 제외)
CHK_ONLY_N_ONLY = 4 // 동기화 요청(X), deleted_yn = N
};
}
// Requeset Data
/// base Data
class CReqServiceData
{
public:
CReqServiceData(){};
~CReqServiceData(){};
public:
SYNC_TYPE::SYNC_TYPE sync_type;
string start_time;
string end_time;
};
// admin(scheduler) => rc_syncd(Master)
class CReqMasterData : public CReqServiceData
{
public:
CReqMasterData(){};
~CReqMasterData(){};
public:
// one_service 값이 없을 수도 있음
// Scheduler : 해당 정보를 보내지 않음(RCDB 작업 회피를 위함)
// 운영자(rc_cmove) : 특정 고객만 수행 시킬 수 있으므로 해당 값은 유동적임
string one_service;
};
// rc_syncd(Master) => rc_syncd(slave)
class CReqSlaveData : public CReqServiceData
{
public:
CReqSlaveData(){};
~CReqSlaveData(){};
public:
string master;
string slave;
};
// rc_syncd(Master) => rc_syncd(slave)
class CReqSyncData : public CReqServiceData
{
public:
CReqSyncData(){};
~CReqSyncData(){};
public:
string master;
string slave;
};
#endif /* __RC_SYNCD_REQUEST_DATA_H__ */
+190
View File
@@ -0,0 +1,190 @@
#include "rc_cmove.h"
#include "Logger.h"
void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty /*= false*/)
{
const string strEmpty("");
string::size_type cutAt;
while( (cutAt = str.find_first_of(delim)) != str.npos )
{
if(cutAt > 0)
{
results.push_back(str.substr(0,cutAt));
}
else
{
if(bUseEmpty && cutAt == 0)
results.push_back(strEmpty);
}
str = str.substr(cutAt+1);
}
//if(str.length() > 0)
{
results.push_back(str);
}
}
int StringCount(string str, string delim)
{
int nCount = 0;
string::size_type cutAt;
while((cutAt = str.find_first_of(delim)) != str.npos)
{
if(cutAt > 0)
{
nCount++;
}
str = str.substr(cutAt+1);
}
if(str.length() > 0)
nCount++;
return nCount;
}
#define USEC_PER_SEC (1000000LL)
long long longtime_now()
{
struct timeval tv;
if( gettimeofday(&tv, NULL) == 0 )
{
// 성공시 micro-second 단위의 값을 반환
return tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
}
else
{
// 실패시 -1 값을 반환.
return -1;
}
}
string strtime_now()
{
time_t rawtime;
struct tm * timeinfo;
char buffer [16] = {0};
time ( &rawtime );
timeinfo = localtime ( &rawtime );
if ( strftime (buffer,sizeof buffer, "%Y%m%d%H%M%S",timeinfo) <= 0 )
return "";
return string(buffer);
}
time_t str2time_t(string strtime)
{
struct tm tm = {0};
if( strtime == "0" )
return 0;
if ( strptime (strtime.c_str(), "%Y%m%d%H%M%S", &tm) == NULL )
return -1;
return mktime(&tm);
}
long long str2longtime(string strtime)
{
return str2time_t(strtime) * USEC_PER_SEC;
}
long GetFileSize(const char* path)
{
long size = -1;
int flag = -1;
struct stat buf;
flag = stat(path, &buf);
if(flag == -1)
{
cerr << "file not found : " << path << endl;
return -1;
}
size = buf.st_size;
#ifdef _DEBUG
if(size == 0)
cout << "file size zero : " << path << endl;
#endif // _DEBUG
return size;
}
string getCommand(string cmd)
{
string data;
FILE *stream;
int MAX_BUFFER = 256;
char buffer[MAX_BUFFER];
cmd.append(" 2>&1");
LOG(LDEV1, "[POPNE] OPEN %s ", cmd.c_str());
stream = popen(cmd.c_str(), "r");
if (!stream)
{
LOG(LERR, "[POPNE] popen error. [%s] ", cmd.c_str());
return "";
}
LOG(LDEV1, "[POPNE] READ %s ", cmd.c_str());
memset(buffer,0,MAX_BUFFER);
while(fgets(buffer, MAX_BUFFER, stream))
{
LOG(LDEV1, "[POPNE] READING.. %s|%s ", cmd.c_str(), buffer);
data.append(buffer);
memset(buffer,0, MAX_BUFFER);
}
LOG(LDEV1, "[POPNE] READ END %s ", cmd.c_str());
if (ferror(stream))
{
// Handle error.
LOG(LERR, "[POPNE] Handle error. [%s] ", cmd.c_str());
return "";
}
pclose(stream);
return data;
}
string StringReplace(const string& source, const string search, const string replacement)
{
string r = source;
string::size_type pos = 0;
while ( (pos = r.find(search, pos)) != string::npos )
{
r.replace( pos, search.size(), replacement );
pos = pos + replacement.size();
}
return r;
}
void solusleep(unsigned long usec)
{
// usleep 사용시 multi thread 환경에서 block 발생 가능성이 존재
// 이에 nanosleep 함수를 사용토록 수정 처리함.
struct timespec sleep;
if (usec >= 1000000)
{
sleep.tv_sec = (int)(usec / 1000000);
sleep.tv_nsec = (usec - ((long)sleep.tv_sec * 1000000)) * 1000;
}
else
{
sleep.tv_sec = 0;
sleep.tv_nsec = usec * 1000;
}
nanosleep(&sleep, NULL);
}
+527
View File
@@ -0,0 +1,527 @@
/***************************************************************************
Database Connection Pool
-----------------------------------------
begin : 2012/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "rc_cmove.h"
#include "dbconnpool.h"
#include "Database.h"
#include "Logger.h"
#define GET_SLEEP 1000 // microsecond
masterdbpool *masterdbpool::m_inst = NULL;
slavedbpool *slavedbpool::m_inst = NULL;
conndbpool::conndbpool(databaseinfo info)
: m_dbinfo(info), m_exitpool(false), m_lastset(NULL), m_alivetime(-1), m_tabletype(-1)
{
pthread_mutex_init(&m_mutex, NULL);
pthread_mutex_init(&m_alivemutex, NULL);
pthread_cond_init(&m_alivecond, NULL);
}
conndbpool::~conndbpool()
{
pthread_mutex_destroy(&m_mutex);
pthread_mutex_destroy(&m_alivemutex);
pthread_cond_destroy(&m_alivecond);
}
int conndbpool::CreatePool( int poolcnt /* = 4 */ )
{
// keep alive thread
int nRet = pthread_create(&m_keepalive, 0, conndbpool::KeepPoolAlive, this);
if( nRet )
{
cerr << "Thread create failed.: errno: " << errno << endl;
return -1;
}
// pool
for(int i=0 ; i < poolcnt ; i++)
{
DataBase * tmp = new DataBase();
if( tmp->PgOpenDB( m_dbinfo.m_hostaddr, m_dbinfo.m_port, m_dbinfo.m_dbname, m_dbinfo.m_user, m_dbinfo.m_pw ) == NULL )
{
#ifdef _DEBUG
cerr << "Database connect error : " << tmp->GetErrorMessage() << endl;
#endif // _DEBUG
delete tmp;
continue;
}
// 2014.06.06 dadamin
// Pool 생성 시 현재 생성된 DB의 형상을 체크한다.
if (m_tabletype < 0)
{
if (SetTargetTableType(tmp) == false)
{
delete tmp;
break;
}
}
m_poolmap.insert(make_pair(tmp, conndbpool::POOL_FREE));
}
if (m_poolmap.size() == 0)
{
// alive thread end
m_exitpool = true;
pthread_cond_signal(&m_alivecond);
pthread_join(m_keepalive, NULL);
m_exitpool = false;
return -1;
}
return m_poolmap.size();
}
int conndbpool::DestroyPool()
{
m_exitpool = true;
map<DataBase*, short>::iterator iter;
pthread_mutex_lock(&m_mutex);
while(m_poolmap.size() > 0 )
{
iter = m_poolmap.begin();
if(iter->second == conndbpool::POOL_FREE || iter->second == conndbpool::POOL_ERR)
{
DataBase *data = static_cast<DataBase *>(iter->first);
delete (DataBase *) data;
m_poolmap.erase(iter);
}
else
sleep(1);
}
pthread_mutex_unlock(&m_mutex);
//
pthread_cond_signal(&m_alivecond);
pthread_join(m_keepalive, NULL);
/*
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
{
if(iter->second == conndbpool::POOL_FREE)
{
DataBase *data = static_cast<DataBase *>(iter->first);
delete (DataBase *) data;
m_poolmap.f
m_poolmap.erase(iter);
}
}
*/
return m_poolmap.size();
}
DataBase * conndbpool::GetConnFromPool(int timeout)
{
ostringstream msg;
DataBase * r = NULL;
int64_t usetime = 0;
int64_t out = timeout*1000*1000;
time_t t = time(NULL);
pthread_mutex_lock(&m_mutex);
map<DataBase*, short>::iterator iter = m_poolmap.begin();
if(m_lastset)
{
iter = m_poolmap.find(m_lastset);
if( iter != m_poolmap.end() )
{
++iter;
}
}
do
{
if( m_poolmap.empty() )
{
msg << "DB Pool empty.";
LOGACERR(LERR, msg);
break;
}
if( iter == m_poolmap.end() )
{
iter = m_poolmap.begin();
}
for( ; !m_poolmap.empty()&& iter != m_poolmap.end(); )
{
if(iter->second == conndbpool::POOL_FREE)
{
iter->second = conndbpool::POOL_USE;
r = iter->first;
m_lastset = r;
break;
}
else if (iter->second == conndbpool::POOL_ERR)
{
DataBase * d = iter->first;
m_poolmap.erase(iter++);
if(d == m_lastset)
m_lastset = NULL;
delete d;
}
else
iter++;
}
if( r == NULL)
{
solusleep(GET_SLEEP);
if( usetime > 10*1000*1000)
{
msg << "GetConnFromPool have waited longer than 10 seconds.";
LOGACOUT(LDBG, msg);
}
if( out > 0 )
{
usetime += GET_SLEEP;
if(usetime > out)
{
msg << "GetConnFromPool Timeout." << usetime << "," << out <<
"," << time(NULL) -t;
LOGACERR(LERR, msg);
break;
}
}
}
} while (r == NULL);
pthread_mutex_unlock(&m_mutex);
return r;
}
void conndbpool::ReleaseConnToPool( DataBase * t, bool success )
{
//pthread_mutex_lock(&m_mutex);
map<DataBase*, short>::iterator iter = m_poolmap.find(t);
if( iter != m_poolmap.end() )
{
if(iter->second==conndbpool::POOL_USE)
{
if (success)
{
iter->second=conndbpool::POOL_FREE;
}
else
{
ostringstream msg;
iter->second=conndbpool::POOL_ERR;
msg << "DB Pool used failed.";
LOGACERR(LERR, msg);
}
}
}
//pthread_mutex_unlock(&m_mutex);
}
bool conndbpool::IsTimeoutAlive()
{
bool r = false;
pthread_mutex_lock(&m_alivemutex);
struct timespec to;
if(m_alivetime > 0 )
to.tv_sec = time(NULL) + m_alivetime;
else
to.tv_sec = time(NULL) + 5;
to.tv_nsec = 0;
int err = pthread_cond_timedwait(&m_alivecond, &m_alivemutex, &to);
if (err == ETIMEDOUT)
{
if( m_alivetime > 0 )
r = true;
}
else if ( err == 0 )
{
#ifdef _DEBUG
cout << "Set Keep alive Timeout : " << m_alivetime << endl;
#endif //_DEBUG
r = false;
}
else
{
/* nothing */
}
pthread_mutex_unlock(&m_alivemutex);
return r;
}
bool conndbpool::SendAliveMsg()
{
ostringstream msg;
ostringstream sql;
pthread_mutex_lock(&m_mutex);
map<DataBase*, short>::iterator iter = m_poolmap.begin();
map<DataBase*, short>::iterator enditer = m_poolmap.end();
sql << "SELECT sp_user_seq, sp_svc_tran_id FROM t_sms_sp_svc_product LIMIT 1";
while(iter != enditer)
{
DataBase * d = iter->first;
if(iter->second == conndbpool::POOL_FREE)
{
iter->second = conndbpool::POOL_USE;
d->PgDoExec( const_cast<char*> (sql.str().c_str()) );
if( d->PgResult(DataBase::CLEAR) < 0 )
{
msg << "Send alive : message failed : " << iter->first->GetErrorMessage();
LOGACERR(LERR, msg);
iter->second=conndbpool::POOL_ERR;
iter++;
//m_poolmap.erase(iter++);
//delete d;
}
else
{
iter->second = conndbpool::POOL_FREE;
msg << "Send alive : message success.";
_LOGACOUT(LDBG, msg);
++iter;
}
}
else if (iter->second == conndbpool::POOL_ERR)
{
msg << "Send alive : Error Pool remove.";
_LOGACOUT(LDBG, msg);
m_poolmap.erase(iter++);
delete d;
}
else
++iter;
}
pthread_mutex_unlock(&m_mutex);
return true;
}
void* conndbpool::KeepPoolAlive( void* pdata )
{
conndbpool* pObject = reinterpret_cast<conndbpool *>(pdata);
ostringstream msg;
while( pObject->IsExit() == false )
{
bool b = pObject->IsTimeoutAlive();
msg << "KeepPoolAlive Timeout - run : " << b;
_LOGACOUT(LDEV2, msg);
if( pObject->IsExit() == false && b )
{
// send keep alive message
pObject->SendAliveMsg();
}
}
return 0;
}
int conndbpool::SetKeepAliveTimeout(int sec)
{
m_alivetime = sec;
pthread_cond_signal(&m_alivecond);
return m_alivetime;
}
int conndbpool::GetFreePoolCnt()
{
int r = 0;
map<DataBase*, short>::iterator iter;
// pthread_mutex_lock(&m_mutex);
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
{
if(iter->second == conndbpool::POOL_FREE)
{
r++;
}
}
// pthread_mutex_unlock(&m_mutex);
return r;
}
// 2014.06.06 dadamin
// 현재 DB 형상 체크
bool conndbpool::SetTargetTableType(DataBase * d)
{
ostringstream msg;
if (d == NULL)
return false;
d->PgDoExec("SELECT * FROM pg_tables WHERE schemaname = 'public' AND tablename = 't_dav_resource'");
if (d->PgResult(DataBase::NOT_CLEAR) < 0)
{
d->PgClear();
msg << "SetTargetTableType failed : " << d->GetErrorMessage();
LOGACERR(LERR, msg);
return false;
}
if (d->GetNoTuples() > 0)
{
m_tabletype = 0;
}
else
{
m_tabletype = 1;
}
d->PgClear();
msg << "Set Target Table Type : " << m_tabletype;
LOGACOUT(LDBG, msg);
return true;
}
// 작업할 메타 테이블명
string conndbpool::GetMetaTableName(const char * tranid)
{
string r;
switch (m_tabletype)
{
case 1:
r = "t_meta_";
r += tranid;
break;
case 0:
default:
r = "t_dav_resource";
break;
}
LOG(LDBG, "Working Table Name %s", r.c_str());
return r;
}
void conndbpool::printstatus(string prefixed)
{
int f = 0, u = 0;
map<DataBase*, short>::iterator iter;
if(m_exitpool == true ) return;
// pthread_mutex_lock(&m_mutex);
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
{
if(iter->second == conndbpool::POOL_FREE)
{
f++;
}
else
{
u++;
}
}
ostringstream msg;
if( prefixed.empty() == false )
msg << "["<< prefixed <<"]";
msg <<"DB connection Pool - " <<"total : " << m_poolmap.size() << "(" << u <<
"/" << f << ")";
_LOGACOUT(LINF, msg);
}
// master db pool
masterdbpool::masterdbpool(databaseinfo info)
: conndbpool(info)
{
}
masterdbpool::~masterdbpool()
{
}
void masterdbpool::init(databaseinfo info)
{
if( masterdbpool::m_inst == NULL )
{
masterdbpool::m_inst = new masterdbpool(info);
}
}
masterdbpool* masterdbpool::getInstance()
{
return masterdbpool::m_inst;
}
int masterdbpool::release()
{
int r = -1;
if( masterdbpool::m_inst != NULL )
{
r = masterdbpool::m_inst->DestroyPool();
delete masterdbpool::m_inst;
masterdbpool::m_inst = NULL;
}
return r;
}
// slave db pool
slavedbpool::slavedbpool(databaseinfo info)
: conndbpool(info)
{
}
slavedbpool::~slavedbpool()
{
}
void slavedbpool::init(databaseinfo info)
{
if( slavedbpool::m_inst == NULL )
{
slavedbpool::m_inst = new slavedbpool(info);
}
}
slavedbpool* slavedbpool::getInstance()
{
return slavedbpool::m_inst;
}
int slavedbpool::release()
{
int r = -1;
if(slavedbpool::m_inst != NULL )
{
r = slavedbpool::m_inst->DestroyPool();
delete slavedbpool::m_inst;
slavedbpool::m_inst = NULL;
}
return r;
}
+108
View File
@@ -0,0 +1,108 @@
/***************************************************************************
Database Connection Pool
-----------------------------------------
begin : 2012/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __DATABASE_CONNECTION_POOL__
#define __DATABASE_CONNECTION_POOL__
class DataBase;
class conndbpool
{
public:
enum POOL_STATUSE
{
POOL_ERR = -1,
POOL_FREE = 0,
POOL_USE = 1
};
public:
conndbpool(databaseinfo info);
virtual ~conndbpool();
int CreatePool( int poolcnt = 4 );
int DestroyPool();
DataBase* GetConnFromPool(int timeout = 10);
void ReleaseConnToPool(DataBase * t, bool success = true);
int SetKeepAliveTimeout(int sec);
void printstatus(string prefixed = "");
int GetFreePoolCnt();
bool IsExit() { return m_exitpool; }
bool IsTimeoutAlive();
bool SendAliveMsg();
void SetDatabaseInfo(databaseinfo info) { m_dbinfo = info; }
databaseinfo GetDatabaseInfo() { return m_dbinfo; }
size_t GetPoolSize() { return m_poolmap.size(); }
// 2014.06.06 dadamin
// 현재 DB 형상 체크
bool SetTargetTableType(DataBase * d);
// 작업할 메타 테이블명
string GetMetaTableName(const char * tranid);
// display_name 컬럼 사용 유무
bool UseDisplayname() { return (m_tabletype == 1); }
private:
static void* KeepPoolAlive(void*);
private:
databaseinfo m_dbinfo;
map<DataBase*, short> m_poolmap;
pthread_mutex_t m_mutex;
bool m_exitpool;
DataBase* m_lastset;
int m_alivetime;
pthread_t m_keepalive;
pthread_cond_t m_alivecond;
pthread_mutex_t m_alivemutex;
// 2014.06.04 dadamin
// -1: unset, 0: t_dav_resource, 1: t_meat_[sp_svc_tran_id]
int m_tabletype;
};
class masterdbpool : public conndbpool
{
public:
static void init(databaseinfo info);
static masterdbpool* getInstance();
static int release();
private:
masterdbpool(databaseinfo info);
~masterdbpool();
private:
static masterdbpool* m_inst;
};
class slavedbpool : public conndbpool
{
public:
static void init(databaseinfo info);
static slavedbpool* getInstance();
static int release();
private:
slavedbpool(databaseinfo info);
~slavedbpool();
private:
static slavedbpool* m_inst;
};
#endif // __DATABASE_CONNECTION_POOL__
+349
View File
@@ -0,0 +1,349 @@
/***************************************************************************
Job Manager
-----------------------------------------
begin : 2012/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "rc_cmove.h"
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fstream>
#include "jobmanager.h"
#include "parameter.h"
#include "workpool.h"
#include "Logger.h"
#include "dbconnpool.h"
#define WORK_WAIT 1000000 // microsecond
static int worknotifyfn(void *object , short success)
{ jobmanager* manager = reinterpret_cast<jobmanager *>(object);
ostringstream msg;
msg << "Called worknotifyfn :" << success;
_LOGACOUT(LDEV2, msg);
return manager->worknotify(success);
}
jobmanager::jobmanager(JOB_TYPE::JOB_TYPE type, const char* syncpath)
: m_type(type),m_exit(false)
{
m_tmppath.m_syncpath = syncpath;
pthread_mutex_init(&m_notifymutex, NULL);
}
jobmanager::~jobmanager()
{
pthread_mutex_destroy(&m_notifymutex);
}
int jobmanager::run()
{
int nRet = pthread_create(&m_hthread, 0, jobmanager::WorkFn, this);
if( nRet )
{
ostringstream msg;
msg << "Thread create failed.[" << errno << "]";
LOGACERR(LERR, msg);
return -1;
}
return 0;
}
bool jobmanager::gettargethostlist(string path, vector<string> &vechost)
{
ostringstream msg;
if(path.size() > 0 )
{
ifstream hostfile;
hostfile.open(path.c_str());
if( hostfile.is_open() == false )
{
msg << "Target Host file open error.[" << path << "]";
LOGACERR(LERR, msg);
return false;
}
string line;
while (!hostfile.eof() )
{
getline (hostfile,line);
if(line.empty() == true || line == "\r")
{
#ifdef _DEBUG
cout << "host data read : empty or linefeed" << line << endl;
#endif // _DEBUG
continue;
}
// check IP addres
struct in_addr laddr;
int status = inet_aton(line.c_str(), &laddr);
if(status != 0)
{
msg << "Target Host Not DNS Name.['" << line << "' IN " << path << "]";
LOGACERR(LERR, msg);
continue;
}
vechost.push_back(line);
}
hostfile.close();
if( vechost.size() == 0 )
{
msg << "Target Host file Empty.[" << path << "]";
LOGACERR(LERR, msg);
return false;
}
}
return true;
}
bool jobmanager::runsync()
{
ostringstream msg;
ifstream syncfile;
msg << "Job - Synchronize working...";
_LOGACOUT(LINF, msg);
// target host list
vector<string> hostlist;
if( gettargethostlist(parameter::getInstance()->gettargetlistpath(), hostlist) == false)
{
return false;
}
// get sync file line
m_status.m_diff = getfileline(m_tmppath.m_syncpath.c_str());
syncfile.open(m_tmppath.m_syncpath.c_str());
if( syncfile.is_open() == false )
{
msg << "Sync data file open error.[" << m_tmppath.m_syncpath <<"]";
LOGACERR(LERR, msg);
return false;
}
string line;
while (!syncfile.eof() )
{
getline (syncfile,line);
if(line.empty() == true || line == "\r")
{
#ifdef _DEBUG
cout << "Sync data read : empty or linefeed" << line << endl;
#endif // _DEBUG
if(!syncfile.eof())
{
++m_status.m_launcherfail;
msg << "File Data Empty. or carriage return." << line;
LOGACERR(LERR, msg);
}
continue;
}
if(m_exit)
{
msg << "Work force to end.";
LOGACERR(LNOT, msg);
break;
}
#ifdef _DEBUG
cout << "Sync data read : " << line << endl;
#endif // _DEBUG
work *w = workpool::getInstance()->GetWorkPool();
if(w != NULL )
{
++m_status.m_work;
w->setenablesync("1111");
w->setnetworkmode(parameter::getInstance()->getnetworkmode());
if( hostlist.size() > 0 )
w->settargethost(hostlist);
w->run(m_type,line,worknotifyfn, this);
}
else
{
++m_status.m_launcherfail;
msg << "Get Work Pool error :" << line;
LOGACERR(LERR, msg);
}
}
// 마지막 라인에 캐리지 리턴 없는 경우 파일을 실제 읽었을 때보다
// 한라인 작은 수를 wc -l 에서 출력되어 작업이 완료되지 않는 것을
// 막기 위해서 work가 diff 값보다 클 때 diff 값을 work 값으로 보정
if (m_status.m_diff < m_status.m_work)
m_status.m_diff = m_status.m_work;
syncfile.close();
msg << "Job - Synchronize working End";
_LOGACOUT(LINF, msg);
return true;
}
void jobmanager::cleandata()
{
/*
// delete temp file
#ifndef _DEBUG
unlink(m_tmppath.m_msrcpath.c_str());
unlink(m_tmppath.m_ssrcpath.c_str());
unlink(m_tmppath.m_diffpath.c_str());
unlink(m_tmppath.m_syncpath.c_str());
#endif // _DEBUG
// delete memory
while( m_srcdata.size() > 0 )
{
vector<CSourceData*>::iterator iter = m_srcdata.begin();
m_srcdata.erase(iter);
delete static_cast<CSourceData *>(*iter);
}
*/
}
void jobmanager::cleanup( void* pdata )
{
jobmanager* pObject = reinterpret_cast<jobmanager *>(pdata);
#ifdef _DEBUG
cout << "Job cleanup thread:" << pthread_self() << endl;
#endif // _DEBUG
pObject->cleandata();
}
void* jobmanager::WorkFn( void* pdata )
{
jobmanager* pObject = reinterpret_cast<jobmanager *>(pdata);
ostringstream msg;
msg << "Job Manager thread start [" << "???" << "]";
_LOGACOUT(LDEV2, msg);
pthread_cleanup_push(jobmanager::cleanup, pdata);
bool running = true;
while(running)
{
// sync
pObject->runsync();
// waiting
pObject->waiting();
running = false;
}
msg << "Job Manager thread end[" << "???" << "]";
_LOGACOUT(LDEV2, msg);
pthread_cleanup_pop(1);
return 0;
}
int jobmanager::worknotify(short success)
{
ostringstream msg;
pthread_mutex_lock(&m_notifymutex);
msg << "work notify :" << success;
_LOGACOUT(LDEV2, msg);
if (success == 0)
++m_status.m_success;
else
++m_status.m_error;
if(success != 0)
{
if( masterdbpool::getInstance()->GetPoolSize() == 0 )
{
msg << "Master DB Pool empty. And Work force to end.";
LOGACERR(LDEV1, msg);
m_exit = true;
}
}
pthread_mutex_unlock(&m_notifymutex);
return 0;
}
int64_t jobmanager::getfileline(const char* path)
{
int64_t r = 0;
ostringstream cmd, msg;
cmd << "cat " << path << " | wc -l";
string lines = getCommand(cmd.str());
//msg << "file lines : CMD - " << cmd.str() << " => " << lines;
//_LOGACOUT(LDBG,msg);
r = atoll(lines.c_str());
msg << "file lines : " << path << " => " << r;
_LOGACOUT(LDBG,msg);
return r;
}
bool jobmanager::waiting()
{
bool r = true;
ostringstream msg;
do
{
if (m_status.m_diff ==
(m_status.m_error + m_status.m_success + m_status.m_launcherfail) )
{
msg << "work end of waiting";
_LOGACOUT(LDEV2, msg);
printstatus();
break;
}
if( (m_exit) &&(m_status.m_work == (m_status.m_error + m_status.m_success)) )
{
msg << "Work force to end.";
LOGACERR(LNOT, msg);
break;
}
#ifdef _DEBUG
msg << "work of waiting.........";
_LOGACOUT(LDBG, msg);
printstatus();
#endif // _DEBUG
solusleep(WORK_WAIT);
}while(true);
return r;
}
void jobmanager::printstatus(string prefixed)
{
ostringstream msg;
if( prefixed.empty() == false )
msg << "[" << prefixed << "]";
msg << "Job Manager(" << "???" << "=>" << "!!!" <<
") total : " << m_status.m_diff << "(R" << m_status.m_work << "/F" <<
m_status.m_launcherfail <<"), result :S" << m_status.m_success << "/E" << m_status.m_error;
_LOGACOUT(LINF, msg);
}
+84
View File
@@ -0,0 +1,84 @@
/***************************************************************************
Job Manager
-----------------------------------------
begin : 2012/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __JOBMANAGER_H__
#define __JOBMANAGER_H__
class CSourceData;
class jobmanager
{
public:
jobmanager(JOB_TYPE::JOB_TYPE type, const char* syncpath);
~jobmanager();
int run();
bool runsync();
pthread_t getjobhandle() {return m_hthread;}
void setexit(bool v) { m_exit = v; }
bool isexit() { return m_exit; }
void setsyncfilename(const char* path) {m_tmppath.m_syncpath = path; }
string getsyncfilenmae() { return m_tmppath.m_syncpath; }
int worknotify(short success);
void printstatus(string prefixed = "");
private:
static void* WorkFn(void* pdata);
static void cleanup(void* pdata);
void cleandata();
bool gettargethostlist(string path, vector<string> &vechost);
bool waiting();
int64_t getfileline(const char* path);
private:
//*
class tmpdataspath
{
public:
string m_syncpath;
};
class jobstatus
{
public:
jobstatus()
: m_diff(0), m_work(0), m_launcherfail(0), m_success(0),m_error(0) {}
public:
int64_t m_diff;
int64_t m_work;
int64_t m_launcherfail;
int64_t m_success;
int64_t m_error;
};
JOB_TYPE::JOB_TYPE m_type;
tmpdataspath m_tmppath;
jobstatus m_status;
bool m_exit;
pthread_t m_hthread;
vector<CSourceData*> m_srcdata;
pthread_mutex_t m_notifymutex;
};
#endif // __JOBMANAGER_H__
+293
View File
@@ -0,0 +1,293 @@
#include "rc_cmove.h"
#include "Logger.h"
#include "parameter.h"
#include "dbconnpool.h"
#include "workpool.h"
#include "jobmanager.h"
#include "monitoring.h"
#include "RcSyncdRequest.h"
#ifdef _DEBUG
#define DBPOOL_KEEPALIVE_TIMEOUT 10 // 10 sec
#else // !_DEBUG
#define DBPOOL_KEEPALIVE_TIMEOUT 300 // 30 min
#endif // _DEBUG
static bool _bexit = false;
static void SigTermMain( int nSignalNumber )
{
ostringstream msg;
if( _bexit == true )
return;
_bexit= true;
// Signal Number 에 따른 로깅처리.
if( nSignalNumber == SIGTERM )
{
msg << "Main Process exit job start by user signal [SIGTERM]";
}
else
{
msg << "Main Process exit job start by user signal ["<< nSignalNumber <<"]";
}
// Process 종료관련 작업 추가
LOGACERR(LWAR, msg);
// waitpid
while(waitpid(-1, NULL, WNOHANG) > 0);
//g_pLog = NULL;
solusleep(500000);
// end
monitoring::getInstance()->release();
exit( EXIT_SUCCESS );
}
// signal
static void SetSignalMain()
{
sigset_t set;
struct sigaction act;
sigfillset( &set );
sigprocmask( SIG_SETMASK, &set, NULL );
memset( &act, 0x00, sizeof(act) );
sigfillset( &act.sa_mask );
/* 무시할 신호 목록 */
act.sa_handler = SIG_IGN;
sigaction( SIGPIPE, &act, NULL); /* 파이프 디스크립터 오류 발생시 Process가 죽는 것은 방지하기 위하여 설정 */
sigaction( SIGHUP , &act, NULL); /* Process를 기동시킨 관리자의 로그아웃시 발생 시그널 */
sigaction( SIGQUIT, &act, NULL); /* 키보드에 의한 Abort 신호 처리 => ? */
// Child Process 종료에 대한 처리기 설정.
//act.sa_handler = sigchld_hdl;
//sigaction( SIGCHLD, &act, NULL);
/* 각종 에러나 사용자의 종료 신호 처리 */
act.sa_handler = SigTermMain;
sigaction( SIGTERM, &act, NULL); /* kill -TERM 에 의한 프로세스 종료시 */
sigaction( SIGINT, &act, NULL); /* ^C 키를 누른 경우 받는 신호 => kill -TERM 과 동일한 처리함 */
sigemptyset(&set); /* 신호 처리기 처리 설정 위한 블록 해제 */
sigprocmask(SIG_SETMASK, &set, NULL);
}
// mode sync
void chksync()
{
ostringstream msg;
msg << "Mode Sync Check...";
_LOGACOUT(LINF, msg);
string service = parameter::getInstance()->getservice();
string sdate = parameter::getInstance()->getsyncstart();
string edate = parameter::getInstance()->getsyncend();
if (sdate.empty() || edate.empty())
{
msg << "Empty date.(-p start_date:end_date) " << service;
_LOGACERR(LERR, msg);
return;
}
msg << "START SYNC CHECK: " << service;
_LOGACOUT(LINF, msg);
if (sdate.compare(edate) > 0)
{
msg << "Start time is greater than End time.";
_LOGACERR(LERR, msg);
}
else
{
SYNC_TYPE::SYNC_TYPE synct = SYNC_TYPE::CHK_ONLY_N_ONLY;
if (parameter::getInstance()->includdel())
synct = SYNC_TYPE::CHK_ONLY;
// sync 요청 처리
// scheduler -> rc_syncd (local host)
// 성공 실패 여부는 objRcSyncdRequest 객체 내부에서 로깅 처리 함.
CRcSyncdRequest objRcSyncdRequest;
if (service.empty())
{
objRcSyncdRequest.SendSyncRequest(synct, sdate, edate);
}
else
{
objRcSyncdRequest.SendSyncRequest(synct, sdate, edate, service);
}
}
msg << "END SYNC CHECK: " << service;
_LOGACOUT(LINF, msg);
}
// mode copy and move
void copyamove(JOB_TYPE::JOB_TYPE type)
{
ostringstream msg;
string mode = (type == JOB_TYPE::COPY ? MODE_COPY : MODE_MOVE);
// create DB connection
masterdbpool::init(parameter::getInstance()->getdbinfo(parameter::MASTER));
if (masterdbpool::getInstance()->CreatePool(
parameter::getInstance()->getdbpoolcnt(parameter::MASTER)) <= 0)
{
msg << "database connection pool created fail(Master).";
LOGACERR(LERR, msg);
return ;
}
masterdbpool::getInstance()->SetKeepAliveTimeout(DBPOOL_KEEPALIVE_TIMEOUT);
// create work pool
if (workpool::getInstance()->CreatePool(parameter::getInstance()->getworkpoolcnt()) != 0)
{
cerr << "work pool created fail." << endl;
return ;
}
msg << "RCDB : ";
msg << (masterdbpool::getInstance()->UseDisplayname() ? "NEW" : "OLD");
msg << " Type.";
_LOGACOUT(LINF, msg);
msg << "Mode " << mode << "...";
_LOGACOUT(LINF, msg);
string syncfilepath = parameter::getInstance()->getsyncpath();
if (syncfilepath.empty())
{
msg << "Not found sync file. and re-run -f [sync file]" << syncfilepath;
_LOGACERR(LERR, msg);
return;
}
msg << "START : sync path = " << syncfilepath;
_LOGACOUT(LINF, msg);
vector<jobmanager *> jobs;
jobmanager *newjob = new jobmanager(type, syncfilepath.c_str());
if (newjob->run() == 0)
{
jobs.push_back(newjob);
}
else
{
delete newjob;
}
if (jobs.size() == 0)
{
msg << "sync job empty.";
_LOGACERR(LERR, msg);
}
// set monitoring
monitoring::getInstance()->setjobs(&jobs);
// wait job end
int rc;
while (jobs.size() > 0)
{
jobmanager *job = static_cast<jobmanager *> (*jobs.begin());
#ifdef _DEBUG
cout << "Wait Job...." << endl;
#endif // _DEBUG
rc = pthread_join(job->getjobhandle(), NULL);
if (rc == 0)
{
monitoring::getInstance()->monlock();
job->setexit(true);
jobs.erase(jobs.begin());
delete job;
job = NULL;
if (jobs.empty())
monitoring::getInstance()->setexit();
monitoring::getInstance()->monunlock();
}
}
msg << "END : sync file = " << syncfilepath;
if (type == JOB_TYPE::COPY)
{
unlink(syncfilepath.c_str());
}
_LOGACOUT(LINF, msg);
}
// main function
int main( int argc, char * argv[] )
{
ostringstream msg;
// setting signal
SetSignalMain();
// argument to data
if( parameter::getInstance()->argvtoparam(argc, argv) == false )
return EXIT_FAILURE;
// load config
if( parameter::getInstance()->loadconf() == false )
return EXIT_FAILURE;
// log init
if( CLogger::Init( PROG_NAME, parameter::getInstance()->getlogpath(),
parameter::getInstance()->getloglevel() ) == false )
{
cerr << "Logger init failed." << endl;
return EXIT_FAILURE;
}
// monitoring init
if( monitoring::getInstance()->init() == false)
{
cerr << "monitoring created fail." << endl;
}
// work
bool runfail = false;
string mode = parameter::getInstance()->getsyncmode();
if (mode.compare(MODE_SYNC) == 0)
{
chksync();
}
else if (mode.compare(MODE_COPY) == 0)
{
copyamove(JOB_TYPE::COPY);
}
else if (mode.compare(MODE_MOVE) == 0)
{
copyamove(JOB_TYPE::MOVE);
}
else
{
runfail = true;
msg << "This mode is not supported.[-m " << mode << "]";
_LOGACOUT(LERR, msg);
}
// end
if (workpool::getInstance())
workpool::getInstance()->release();
if (masterdbpool::getInstance())
masterdbpool::getInstance()->release();
if (monitoring::getInstance())
monitoring::getInstance()->release();
parameter::getInstance()->release();
CLogger::Exit();
return (runfail ? EXIT_FAILURE: EXIT_SUCCESS);
}
+144
View File
@@ -0,0 +1,144 @@
/***************************************************************************
Monitoring
-----------------------------------------
begin : 2015/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "rc_cmove.h"
#include "monitoring.h"
#include "dbconnpool.h"
#include "workpool.h"
#include "jobmanager.h"
#include "Logger.h"
#define MONITORING_SLEEP (1000*1000) // microsecond
monitoring *monitoring::m_inst = NULL;
monitoring::monitoring()
: m_exit(false), m_pjobs(NULL)
{
pthread_mutex_init(&m_mutex, NULL);
}
monitoring::~monitoring()
{
pthread_mutex_destroy(&m_mutex);
}
void* monitoring::monitoringfn( void* pdata )
{
monitoring* pObject = reinterpret_cast<monitoring *>(pdata);
ostringstream msg;
//pthread_detach(pthread_self());
msg << "monitoring::monitoringfn Start";
_LOGACOUT(LDEV2, msg);
while( pObject->m_exit == false )
{
msg << "monitoring::monitoringfn";
_LOGACOUT(LDBG, msg);
// pool status
if (masterdbpool::getInstance())
masterdbpool::getInstance()->printstatus("monitoring");
//slavedbpool::getInstance()->printstatus("monitoring(Slave)");
if (workpool::getInstance())
workpool::getInstance()->printstatus("monitoring");
if( CLogger::GetInstance()->GetLogLevel() >= LDEV1 )
workpool::getInstance()->printstatusex("monitoring-DEBUG");
// job status
if (pObject->m_exit == false)
{
pObject->printjobstatus("monitoring");
solusleep(MONITORING_SLEEP);
}
}
msg << "monitoring::monitoringfn End";
_LOGACOUT(LDEV2, msg);
return 0;
}
bool monitoring::init()
{
// Monitoring thread
int nRet = pthread_create(&m_thread, 0, monitoring::monitoringfn, this);
if( nRet )
{
cerr << "Thread create failed.: errno: " << errno << endl;
return false;
}
sleep(0);
return true;
}
void monitoring::destory()
{
m_exit = true;
pthread_join(m_thread, NULL);
}
monitoring* monitoring::getInstance()
{
if(monitoring::m_inst == NULL)
{
monitoring::m_inst = new monitoring();
}
return monitoring::m_inst;
}
void monitoring::release()
{
if( monitoring::m_inst != NULL)
{
monitoring::m_inst->destory();
delete monitoring::m_inst;
monitoring::m_inst = NULL;
}
}
void monitoring::printjobstatus(string prefixed)
{
if (m_exit) return;
ostringstream msg;
if( m_pjobs == NULL )
{
msg << "monitoring - Work has not been set yet.";
_LOGACOUT(LDBG, msg);
return;
}
monlock();
vector<jobmanager *>::iterator it;
if (m_pjobs->size())
{
for (it = m_pjobs->begin(); it < m_pjobs->end(); it++)
{
if (m_exit == false && it != m_pjobs->end())
{
if ((*it)->isexit() == false)
(*it)->printstatus(prefixed);
}
}
}
monunlock();
}
+52
View File
@@ -0,0 +1,52 @@
/***************************************************************************
Monitoring
-----------------------------------------
begin : 2012/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __MONITORING__
#define __MONITORING__
class jobmanager;
class monitoring
{
public:
static monitoring* getInstance();
static void release();
bool init();
void destory();
void setjobs(vector<jobmanager *> *p) { m_pjobs = p; }
void setexit() { m_exit = true; }
void monlock() { pthread_mutex_lock(&m_mutex); }
void monunlock() { pthread_mutex_unlock(&m_mutex); }
private:
monitoring();
virtual ~monitoring();
void printjobstatus(string prefixed = "");
static void* monitoringfn(void * pdata);
private:
static monitoring* m_inst;
pthread_t m_thread;
bool m_exit;
vector<jobmanager *> *m_pjobs;
pthread_mutex_t m_mutex;
};
#endif // __MONITORING__
+385
View File
@@ -0,0 +1,385 @@
/***************************************************************************
Parameter
-----------------------------------------
begin : 2015/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "rc_cmove.h"
#include "parameter.h"
#include "Config.h"
#define REPORT_NAME "report"
#define MAX_DB_POOL 10
#define DEFAULT_FHS_MOUNT "/stg/node0,/stg/node1,/stg/node2"
parameter *parameter::inst = NULL;
parameter::parameter()
:m_confpath(DEFAULT_CONFIG_FILE), m_networkmode(1), m_includedel(false)
{
}
parameter::~parameter()
{
}
parameter* parameter::getInstance()
{
if( parameter::inst == NULL )
{
parameter::inst = new parameter;
}
return parameter::inst;
}
void parameter::release()
{
if( parameter::inst != NULL )
{
delete parameter::inst;
parameter::inst = NULL;
}
}
void parameter::printusage()
{
cerr << "usage: " << PROG_NAME << " [-v] [-m mode] ([-f path] [-t path] ";
cerr << "([-n mode])) ([-p starttime:endtime] [-d] [-s service sequence])";
cerr << endl;
}
bool parameter::argvtoparam( int argc, char * const argv[] )
{
int o;
if( argc == 1 )
{
cerr << "Invalid input arguments." << endl;
return false;
}
while ((o = getopt(argc, argv, "vf:n:t:c:m:p:s:d")) >= 0)
{
switch (o)
{
case 'v': // version info
cerr << "[info] " << PROG_NAME << " Version : " << PROG_VERSION << endl;
exit(EXIT_SUCCESS);
break;
// use common
case 'm':// mode
m_mode = optarg;
break;
case 'c': // config path
m_confpath = optarg;
break;
// use move & use copy
case 'f': // transfer list path
{
if (issyncmode())
{
cerr << "'-f' Available copy or move mode.";
cerr << endl;
return false;
}
m_synclistpath = optarg;
}
break;
case 't': // host list path
{
if (issyncmode())
{
cerr << "'-t' Available copy or move mode.";
cerr << endl;
return false;
}
m_targetlistpath = optarg;
}
break;
// use move
case 'n': // network mode
{
if (ismovemode() == false)
{
cerr << "'-n' Available only move mode.";
cerr << endl;
return false;
}
m_networkmode = atoi(optarg);
}
break;
//use sync
case 'p':
{
if (issyncmode() == false)
{
cerr << "'-p' Available only sync mode.";
cerr << endl;
return false;
}
string t = optarg;
StringSplit(t, ":", m_synctime);
if (m_synctime.size() != 2)
{
cerr << "The request does not fit the format. [-p starttime:endtime]";
cerr << endl;
return false;
}
}
break;
case 's':
{
if (issyncmode() == false)
{
cerr << "'-s' Available only sync mode.";
cerr << endl;
return false;
}
m_service = optarg;
}
break;
case 'd':
{
if (issyncmode() == false)
{
cerr << "'-d' Available only sync mode.";
cerr << endl;
return false;
}
m_includedel = true;
}
break;
default: // unknown
#ifdef _DEBUG
cout << "unknown arguments." << endl;
#endif // _DEBUG
printusage();
return false;
break;
}
}
if (m_mode.empty())
{
printusage();
return false;
}
return true;
}
bool parameter::loadconf()
{
#ifdef _DEBUG
cout << "conf :" << m_confpath << endl;
#endif // _DEBUG
Config conf;
// Config File open
if( conf.Open(m_confpath) == false )
{
return false;
}
string szValue;
// log path
if( getconfdata( conf, "DEFAULT_LOG_DIR" ,szValue, true ) == false )
return false;
m_logpath = szValue;
m_logreport = m_logpath + "/" + REPORT_NAME;
// log level
if( getconfdata( conf, "LOG_LEVEL" ,szValue, true ) == false )
return false;
m_loglevel = atoi(szValue.c_str());
// work pool
if( getconfdata( conf, "WORK_POOL" ,szValue, false ) == false )
return false;
m_workpoolcnt = atoi(szValue.c_str());
// skip keyword
getconfdata(conf, "SKIP_KEYWORD", m_skipkey, true, false);
//if( getconfdata(conf, "SKIP_KEYWORD", m_skipkey, false) == false )
// return false;
databaseinfo m;
// RCDB Information
// master
if( getconfdbinof(conf, parameter::MASTER, m) == false )
return false;
m_dbinfo.push_back(m);
// DB Connection pool
int pool = 0;
getconfdata(conf, "DB_POOL", szValue, false);
pool = atoi(szValue.c_str());
m_dbpoolcnt.push_back(pool);
if( 1 > m_dbpoolcnt[0] || m_dbpoolcnt[0] > MAX_DB_POOL )
m_dbpoolcnt[0] = 4;
// FHS_STORAGE_MOUNT
if (getconfdata(conf, "FHS_STORAGE_MOUNT", m_fhsmount, true, false) == false)
{
StringSplit(DEFAULT_FHS_MOUNT, ",", m_fhsmount);
}
return true;
}
bool parameter::getconfdbinof(Config &conf,int dbinfotype, databaseinfo &data)
{
bool bcommon = true;
string szValue, szkey, szextkey;
switch(dbinfotype)
{
case parameter::MASTER:
szextkey = "";
bcommon = true;
break;
case parameter::SLAVE_FIRST:
szextkey = "_SLAVE_FIRST";
bcommon = false;
break;
case parameter::SLAVE_SECOND:
szextkey = "_SLAVE_SECOND";
bcommon = false;
break;
default:
return false;
break;
}
// db host
szValue.clear();
szkey = "RCDB_IP"+ szextkey;
if( getconfdata( conf, szkey, szValue, bcommon) == false )
{
return false;
}
data.m_hostaddr = szValue;
// db port
szValue.clear();
szkey = "RCDB_PORT"+ szextkey;
if( getconfdata( conf, szkey, szValue, bcommon) == false )
{
return false;
}
data.m_port = atoi(szValue.c_str());
// db database name
szValue.clear();
szkey = "RCDB_DB_NAME"+ szextkey;
if( getconfdata( conf, szkey, szValue, bcommon) == false )
{
return false;
}
data.m_dbname = szValue;
// db user
szValue.clear();
szkey = "RCDB_ACCT"+ szextkey;
if( getconfdata( conf, szkey, szValue, bcommon) == false )
{
return false;
}
data.m_user = szValue;
// db password
szValue.clear();
szkey = "RCDB_ACCT_PW"+ szextkey;
if( getconfdata( conf, szkey, szValue, bcommon) == false )
{
return false;
}
data.m_pw = szValue;
return true;
}
bool parameter::getconfdata(Config &conf, const string& key, string& value, bool bcommon /* = false */, bool returnerr /*= true*/)
{
value.clear();
string prefix = "[error]";
if (returnerr == false)
prefix = "[warning]";
if( conf.GetConfig( PROG_NAME, key, value ) == false )
{
if(bcommon == false)
{
cerr << prefix << " Config info get failed. [" << PROG_NAME << "]->" << key << endl;
return false;
}
else
{
if( conf.GetConfig( "COMMON", key, value ) == false )
{
cerr << prefix << " Config info get failed. [COMMON]->" << key << endl;
return false;
}
}
}
return true;
}
bool parameter::getconfdata(Config &conf, const string& key, vector< string >& value, bool bcommon /*= false */, bool returnerr /*= true*/)
{
value.clear();
string prefix = "[error]";
if (returnerr == false)
prefix = "[warning]";
if( conf.GetConfig( PROG_NAME, key, value ) == false )
{
if(bcommon == false)
{
cerr << prefix << " Config info get failed. [" << PROG_NAME << "]->" << key << endl;
return false;
}
else
{
if( conf.GetConfig( "COMMON", key, value ) == false )
{
cerr << prefix << " Config info get failed. [COMMON]->" << key << endl;
return false;
}
}
}
return true;
}
void parameter::print_loginfo()
{
cout << "Log Path : " << m_logpath << "/"<< PROG_NAME << "/" << endl;
cout << "Log Level : " << m_loglevel <<endl;
}
void parameter::print_dbinfo()
{
databaseinfo m = getdbinfo(parameter::MASTER);
cout << "Master DB : " << m.m_hostaddr << "," << m.m_port << "," <<
m.m_dbname << "," << m.m_user << "," << m.m_pw <<endl ;
}
+96
View File
@@ -0,0 +1,96 @@
/***************************************************************************
Parameter
-----------------------------------------
begin : 2015/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __PARAMETER_H__
#define __PARAMETER_H__
class Config;
class parameter
{
public:
enum DBINF0_TYPE {
MASTER = 0,
SLAVE_FIRST = 1,
SLAVE_SECOND = 2
};
private:
static parameter *inst;
string m_confpath;
// use common
string m_mode;
string m_synclistpath;
string m_targetlistpath;
// use move mode
int m_networkmode;
// use sync mode
vector<string> m_synctime;
string m_service;
bool m_includedel;
// config
string m_logpath;
int m_loglevel;
int m_workpoolcnt;
vector<int> m_dbpoolcnt;
vector<databaseinfo> m_dbinfo;
vector<string> m_skipkey;
vector<string> m_fhsmount;
string m_logreport;
public:
static parameter* getInstance();
static void release();
bool argvtoparam( int argc, char * const argv[] );
bool loadconf();
void print_loginfo();
void print_dbinfo();
databaseinfo getdbinfo( int dbinfotype ) { return m_dbinfo[dbinfotype]; }
int getdbpoolcnt( int dbinfotype ) { return m_dbpoolcnt[dbinfotype]; }
int getskipkeycnt() { return m_skipkey.size(); }
string getskipkey(int i) { return m_skipkey[i]; }
string getlogpath() { return m_logpath; }
string getreportpath() { return m_logreport; }
string getsyncpath() { return m_synclistpath; }
string gettargetlistpath() { return m_targetlistpath; }
int getnetworkmode() { return m_networkmode; }
int getloglevel() { return m_loglevel; }
int getworkpoolcnt() { return m_workpoolcnt; }
string getsyncmode() { return m_mode; }
string getsyncstart() { return m_synctime.empty() ? "" : m_synctime[0]; }
string getsyncend() { return m_synctime.empty() ? "" : m_synctime[1]; }
string getservice() { return m_service; }
bool includdel() { return m_includedel; }
bool issyncmode() { return (m_mode.compare(MODE_SYNC) == 0); }
bool ismovemode() { return (m_mode.compare(MODE_MOVE) == 0); }
bool iscopymode() { return (m_mode.compare(MODE_COPY) == 0); }
vector<string>& getfhsmount() { return m_fhsmount; }
private:
parameter();
~parameter();
bool getconfdbinof(Config &conf,int dbinfotype, databaseinfo &data);
bool getconfdata(Config &conf, const string& key, string& value, bool bcommon = false, bool returnerr = true);
bool getconfdata(Config &conf, const string& key, vector< string >& value, bool bcommon = false, bool returnerr = true);
void printusage();
};
#endif // __PARAMETER_H__
+222
View File
@@ -0,0 +1,222 @@
/***************************************************************************
RC Contents Move Tool
-----------------------------------------
begin : 2012/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __SERVICE_SYNC_H__
#define __SERVICE_SYNC_H__
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <unistd.h>
#include <iostream>
#include <vector>
#include <map>
#include <sstream>
#include <cctype>
using namespace std;
// -m type
#define MODE_SYNC "sync"
#define MODE_COPY "copy"
#define MODE_MOVE "move"
// sync file flag
#define FLAG_SYNC "SYNC"
#define FLAG_NSYNC "NSYNC"
#define FLAG_DEL "DEL"
#define FLAG_COPY "COPY"
#define FLAG_MOVE "MOVE"
#define FLAG_RECHK "RECHK"
// resource_type
#define TYPE_FILE "0"
#define TYPE_DIR "1"
#define SPACES " \t\r\n"
class databaseinfo
{
public:
databaseinfo() {}
~databaseinfo() {}
public:
string m_hostaddr;
int m_port;
string m_dbname;
string m_user;
string m_pw;
};
// sync file formate file
// flag|uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|host_name|creation_date|get_content_type|src_uri|slave_tran_id
class SYNCFILE_FIELD
{
public:
// SYNCFILE_FIELD::flag
// - SYCN : 동기화 필요
// - NSYCN: 논리적 동기화 필요
// - DEL : 삭제 필요
// - COPY : 복사된 파일임
// - MOVE : 이동된 파일임
// - RECHK: 다시 검증
enum FIELD
{
flag = 0, uri, filename_hash, resource_type, get_content_length,
file_lastmodified, deleted_yn, host_name, creation_date, get_content_type,
src_uri, slave_tran_id, uri_ignore_case,
MAX_FILED
};
};
class CURRENT_FIELD
{
public:
enum FIELD
{
uri = 0, filename_hash, resource_type, get_content_length, get_lastmodified,
file_lastmodified, deleted_yn, host_name, creation_date, get_content_type,
MAX_FILED
};
};
namespace JOB_TYPE
{
enum JOB_TYPE
{
UNSET = 0,
COPY = 1,
MOVE = 2
};
};
typedef vector< vector<string> > CSyncData;
#ifdef __cplusplus
extern "C" {
#endif
// Split string function
// bUseEmpty값이 true면 delimiter의 갯수에 따라 results.size()의 숫자도 맞추기 위한 옵션
void StringSplit(string str, string delim, vector<string> &results, bool bUseEmpty = false);
// delim 의 갯수를 리턴한다.
int StringCount(string str, string delim);
// microsecond now time
long long longtime_now();
// string now time
string strtime_now();
// string to time_t
time_t str2time_t(string strtime);
// string to microsecond
long long str2longtime(string strtime);
// 파일의 크기를 가져온다. 파일이 없을 경우 -1 리턴
long GetFileSize(const char* path);
// command 명령어 실행 화면 출력 결과를 string으로 리턴
string getCommand(string cmd);
// trim string right
inline string trim_right(const string & s, const string & t = SPACES)
{
string d (s);
string::size_type i (d.find_last_not_of (t));
if (i == string::npos)
return "";
else
return d.erase(d.find_last_not_of (t) + 1) ;
}
// trim string left
inline string trim_left(const string & s, const string & t = SPACES)
{
string d (s);
return d.erase(0, s.find_first_not_of (t)) ;
}
// trim string left and right
inline string trim(const string & s, const string & t = SPACES)
{
string d (s);
return trim_left(trim_right (d, t), t) ;
}
string StringReplace(const string& source, const string search, const string replacement);
void solusleep(unsigned long usec);
#ifdef __cplusplus
}
#endif
#ifdef _DEBUG
#define COUT(level, levelkey, msg) \
cout << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
#define CERR(level, levelkey, msg) \
cerr << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
#else // _DEBUG
#define COUT(level, levelkey, msg) \
if(level < LDBG) \
cout << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
#define CERR(level, levelkey, msg) \
if(level < LDBG) \
cerr << "[PID:"<< getpid() <<"-" << pthread_self() <<"] ["<< #levelkey << "] " << msg.str() << endl;
#endif // _DEBUG
#define _LOGACOUT(level, msg) \
_LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
COUT(level, #level,msg);\
msg.str("");
#define LOGACOUT(level, msg) \
LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
COUT(level, #level, msg);\
msg.str("");
#define _LOGACERR(level, msg) \
_LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
CERR(level, #level, msg);\
msg.str("");
#define LOGACERR(level, msg) \
LOG(level,"[PID:%d-%d] %s", getpid(), pthread_self(), msg.str().c_str());\
CERR(level, #level, msg);\
msg.str("");
// dummy
#define REPORT_SUCCESS(format, ...)
#define REPORT_FAIL(format, ...)
#define REPORT_WARNING(format, ...)
#define REPORT_NOTICE(format, ...)
#endif // __SERVICE_SYNC_H__
+248
View File
@@ -0,0 +1,248 @@
#! /bin/sh
if [ $# -lt 1 ]
then
echo "Usage: $0 [FHS Domain name] ([sp_svc_tran_id] [repair])"
exit 1
fi
FHS_HOST=$1
REPAIR=$3
if [ "$2" = "repair" ]; then
REPAIR=$2
else
SP_SVC_TRAN_ID=$2
fi
FHSNAME=$FHS_HOST.data
rm -f $FHSNAME 2>&1 > /dev/null
PSQL="/user/service/bin/psql"
RCDB=`grep "^RCDB_IP" /user/service/etc/rcts.conf | grep -v "\_SLAVE" | cut -d = -f 2`
PORT=6543
RCDBNAME="localdb"
RCDBUSER="syshost"
PSQLRUN="$PSQL -h $RCDB -p $PORT -U $RCDBUSER -A -t -c"
META="t_dav_resource"
GET_URICOMM=uri
## check RCDB Type
SQL="SELECT COUNT(tablename) FROM pg_tables WHERE schemaname = 'public' AND tablename = '$META'"
OLDRCDB=`$PSQLRUN "$SQL" $RCDBNAME`
echo "#### Meta Type : $OLDRCDB"
## Get Service
SQL="SELECT sp_svc_tran_id, uri_ignore_case, replication_count FROM t_sms_sp_svc_product"
if [ -n "$SP_SVC_TRAN_ID" ]; then
SQL="SELECT sp_svc_tran_id, uri_ignore_case, replication_count FROM t_sms_sp_svc_product WHERE sp_svc_tran_id = $SP_SVC_TRAN_ID"
fi
SVC_LIST=`$PSQLRUN "$SQL" $RCDBNAME`
for v in $SVC_LIST
do
tran_id=`echo $v | cut -d '|' -f 1`
uri_ignore_case=`echo $v | cut -d '|' -f 2`
replication_count=`echo $v | cut -d '|' -f 3`
echo -n " ##### $tran_id, $uri_ignore_case "
if [ "$OLDRCDB" = "0" ]; then
META="t_meta_$tran_id"
GET_URICOMM="display_name"
fi
echo -n "$META "
## Get Data
if [ "$REPAIR" = "repair" ]; then
### uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|is_cache|host_name|creation_date|get_content_type|src_uri|slave tran_id|uri_ignore_case|replication_count
SQL="SELECT uri,filename_hash,resource_type,get_content_length,file_lastmodified,deleted_yn,is_cache,host_name,creation_date,get_content_type,'',sp_svc_tran_id, '$uri_ignore_case', '$replication_count' FROM $META"
else
### flag|uri|filename_hash|resource_type|get_content_length|file_lastmodified|deleted_yn|host_name|creation_date|get_content_type|src_uri|slave tran_id|uri_ignore_case
SQL="SELECT 'MOVE',$GET_URICOMM,filename_hash,resource_type,get_content_length,file_lastmodified,deleted_yn,host_name,creation_date,get_content_type,'',sp_svc_tran_id, '$uri_ignore_case' FROM $META"
fi
SQLGET="$SQL WHERE uri like '/$tran_id/%' AND deleted_yn = 'N' AND host_name = '$FHS_HOST'"
#echo "######### $SQLGET"
$PSQLRUN "$SQLGET" $RCDBNAME >> $FHSNAME
echo "...[OK]"
done
if [ "$REPAIR" = "repair" ]; then
echo "... MODE : repair "
while read line
do
same=();
same_host=();
same_uri_attr_cache=();
same_uri_cache_n=();
same_uri_cache_r=();
same_attr_cache=();
attr_cache_y=();
other_uri_cache_n=();
other_uri_cache_r=();
check=();
#echo $line
uri=`echo $line | cut -d '|' -f 1`
filename_hash=`echo $line | cut -d '|' -f 2`
filename_hash_in=`echo $filename_hash | sed -e 's|/stg/node0/||g' | sed -e 's|/stg/node1/||g' | sed -e 's|/stg/node2/||g' | sed -e 's|/user2/dav_storage/||g'`
filename_hashs="'/stg/node0/$filename_hash_in','/stg/node1/$filename_hash_in','/stg/node2/$filename_hash_in','/user2/dav_storage/$filename_hash_in','/stg/node0/cache/$filename_hash_in','/stg/node1/cache/$filename_hash_in','/stg/node2/cache/$filename_hash_in','/user2/dav_storage/cache/$filename_hash_in'"
resource_type=`echo $line | cut -d '|' -f 3`
get_content_length=`echo $line | cut -d '|' -f 4`
is_cache=`echo $line | cut -d '|' -f 7`
host_name=`echo $line | cut -d '|' -f 8`
tran_id=`echo $line | cut -d '|' -f 12`
replication_count=`echo $line | cut -d '|' -f 14`
## dir skip
if [ $resource_type -eq 1 ]; then
continue
fi
if [ "$OLDRCDB" = "0" ]; then
META="t_meta_$tran_id"
fi
#echo "....... $tran_id, $replication_count, $META, $host_name, $uri, $filename_hash($filename_hash_in), $resource_type, $is_cache"
## cache file delete
if [ "$is_cache" = "Y" ]; then
SQLSET="UPDATE $META SET deleted_yn = 'Y' "
SQL="SQLSET WHERE filename_hash = '$filename_hash' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'Y' AND host_name = '$host_name' ;"
$PSQLRUN "$SQL" $RCDBNAME
if [ $? -eq 0 ]; then
echo ".......... $uri, $filename_hash [DEL]"
else
echo ".......... $uri, $filename_hash [DEL] FAILED"
break
fi
continue
fi
SQL="SELECT uri,filename_hash,resource_type,get_content_length,file_lastmodified,deleted_yn,is_cache,host_name FROM $META"
SQLGET="$SQL WHERE filename_hash in ($filename_hashs) AND deleted_yn = 'N' AND resource_type = 0 AND get_content_length = $get_content_length ;"
#echo "......... $SQLGET"
data=`$PSQLRUN "$SQLGET" $RCDBNAME`
for v in $data
do
#echo ".......... $v"
if [ `echo $v | grep "$uri" | grep "$host_name" | grep -c "|N|$is_cache|" ` -gt 0 ] ; then
#echo "............. $v [same]"
same[${#same[@]}]=$v
elif [ `echo $v | grep -c "$host_name" ` -gt 0 ] ; then
#echo "............. $v [same_host]"
same_host[${#same_host[@]}]=$v
elif [ `echo $v | grep "$uri" | grep -c "|N|$is_cache|" ` -gt 0 ] ; then
#echo "............. $v [same_uri_attr_cache]"
same_uri_attr_cache[${#same_uri_attr_cache[@]}]=$v
elif [ `echo $v | grep "$uri" | grep -c "|N|N|" ` -gt 0 ] ; then
#echo "............. $v [same_uri_cache_n]"
same_uri_cache_n[${#same_uri_cache_n[@]}]=$v
elif [ `echo $v | grep "$uri" | grep -c "|N|R|" ` -gt 0 ] ; then
#echo "............. $v [same_uri_cache_r]"
same_uri_cache_r[${#same_uri_cache_r[@]}]=$v
elif [ `echo $v | grep -c "|N|$is_cache|" ` -gt 0 ] ; then
#echo "............. $v [same_attr_cache]"
same_attr_cache[${#same_attr_cache[@]}]=$v
elif [ `echo $v | grep -c "|N|Y|" ` -gt 0 ] ; then
#echo "............. $v [same_attr_cache]"
attr_cache_y[${#attr_cache_y[@]}]=$v
elif [ `echo $v | grep -c "|N|N|" ` -gt 0 ] ; then
#echo "............. $v [outher_uri_cache_n]"
other_uri_cache_n[${#other_uri_cache_n[@]}]=$v
elif [ `echo $v | grep -c "|N|R|" ` -gt 0 ] ; then
#echo "............. $v [other_uri_cache_r]"
other_uri_cache_r[${#other_uri_cache_r[@]}]=$v
else
echo "............. [$line] => [$v] [check]"
check[${#check[@]}]=$v
exit 1
fi
done
#echo -n "............"
##echo -n " $line"
#echo -n " [same : ${#same[@]}, same_host :${#same_host[@]}"
#echo -n ", same_uri_attr_cache: ${#same_uri_attr_cache[@]}"
#echo -n ", same_uri_cache_n: ${#same_uri_cache_n[@]}"
#echo -n ", same_uri_cache_r: ${#same_uri_cache_r[@]}"
#echo -n ", same_attr_cache : ${#same_attr_cache[@]}"
#echo -n ", attr_cache_y: ${#attr_cache_y[@]}"
#echo -n ", other_uri_cache_n: ${#other_uri_cache_n[@]}"
#echo -n ", other_uri_cache_r: ${#other_uri_cache_r[@]}"
#echo ", check : ${#check[@]}]"
if [ ${#same[@]} -eq 0 ]; then
echo ".......... $uri, $filename_hash, $host_name [Not Found]"
continue
fi
filename_hash2=""
host_name2=""
SQLSET=""
SQL2=""
if [ ${#same_attr_cache[@]} -gt 0 ]; then
echo "########### same_attr_cache: ${#same_attr_cache[@]} : ${same_attr_cache[0]}"
filename_hash2=`echo ${same_attr_cache[0]} | cut -d '|' -f 2`
host_name2=`echo ${same_attr_cache[0]} | cut -d '|' -f 8`
SQLSET="UPDATE $META SET filename_hash = '$filename_hash2', host_name = '$host_name2'"
SQL2="$SQLSET WHERE filename_hash = '$filename_hash' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = '$is_cache' AND host_name = '$host_name' ;"
elif [ ${#attr_cache_y[@]} -gt 0 ] ; then
echo "########### attr_cache_y: ${#attr_cache_y[@]} : ${attr_cache_y[0]}"
filename_hash2=`echo ${attr_cache_y[0]} | cut -d '|' -f 2`
host_name2=`echo ${attr_cache_y[0]} | cut -d '|' -f 8`
SQLSET="UPDATE $META SET deleted_yn = 'Y'"
SQL2="$SQLSET WHERE filename_hash = '$filename_hash2' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'Y' AND host_name = '$host_name2' ;"
else
case "$is_cache" in
"N")
#echo ".......... $line ['N' case]"
if [ ${#same_uri_cache_r[@]} -gt $replication_count ]; then
#echo "########### same_uri_cache_r: ${#same_uri_cache_r[@]} : ${same_uri_cache_r[0]}"
filename_hash2=`echo ${same_uri_cache_r[0]} | cut -d '|' -f 2`
host_name2=`echo ${same_uri_cache_r[0]} | cut -d '|' -f 8`
SQLSET="UPDATE $META SET deleted_yn = 'Y'"
SQL2="$SQLSET WHERE filename_hash = '$filename_hash2' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'R' AND host_name = '$host_name2' ;"
elif [ ${#other_uri_cache_r[@]} -gt $replication_count ] ; then
#echo "########### other_uri_cache_r: ${#other_uri_cache_r[@]} : ${other_uri_cache_r[0]}"
filename_hash2=`echo ${other_uri_cache_r[0]} | cut -d '|' -f 2`
host_name2=`echo ${other_uri_cache_r[0]} | cut -d '|' -f 8`
SQLSET="UPDATE $META SET deleted_yn = 'Y'"
SQL2="$SQLSET WHERE filename_hash = '$filename_hash2' AND deleted_yn = 'N' AND resource_type = 0 AND is_cache = 'R' AND host_name = '$host_name2' ;"
fi
;;
#"R")
# echo ".......... $line ['R' case]"
#;;
*)
echo "$line [Unknown error]"
exit 1
;;
esac
fi
if [ -n "$SQL2" ]; then
#echo "............ repair SQL : [$SQL2] "
$PSQLRUN "$SQL2" $RCDBNAME
if [ $? -eq 0 ]; then
echo ".......... $uri, $filename_hash [OK]"
else
echo ".......... $uri, $filename_hash [UPDATE] FAILED"
fi
else
echo ".......... $uri, $filename_hash [rc_cmove]"
fi
done < $FHSNAME
rm -f $FHSNAME
echo "... MODE : repair [Done]"
fi
File diff suppressed because it is too large Load Diff
+78
View File
@@ -0,0 +1,78 @@
/***************************************************************************
Synchronization
-----------------------------------------
begin : 2012/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __SYNCHRONIZATION_H__
#define __SYNCHRONIZATION_H__
class DataBase;
class CSynchronization
{
public:
CSynchronization(JOB_TYPE::JOB_TYPE type, vector<string>& syncdata);
~CSynchronization();
// 실행
int Execute();
void SetTragetHost(vector<string> &src);
inline void SetEnable(const char* szOn) { m_enable = szOn; }
inline void SetNetworkMode(int mode) { m_networkmode = mode; }
inline void SetFHSMount(vector<string> &mount) { m_fhsmount = mount; }
protected:
// TOP FHS 정보를 가져온다. (가져온후 random으로 1개를 추출하여 return 함)
bool GetTargetFHS(string & targethost);
// copy(move)에 source 정보 찾기
bool GetSource(string & srchost, string & srchash);
// 동일한 파일 가지고 있는 host 추출
bool GetHostHasFile(string & srchosts);
// ftsd를 이용한 파일전송
bool ReqFileTrans(string & strsrc, vector<string>& vecdest);
// kind of sync
int Deleted();
int Syned();
int NSyned();
int Copy();
int Move();
int MoveTypeCopy();
int MoveTypeMove();
int Rechk();
// change value
string ChgFilenamehash();
string MakeFilenameorg();
// Database
DataBase* GetDB(string & tblname, bool & usedisplay);
void FreeDB(DataBase *db, bool success = true);
private:
string m_enable;
int m_networkmode;
vector<string> m_fhsmount;
vector<string> m_vecTargetFHS; // target TOP FHS
JOB_TYPE::JOB_TYPE m_type;
vector<string> m_syncdata;
bool m_exit;
};
#endif // __SYNCHRONIZATION_H__
+891
View File
@@ -0,0 +1,891 @@
/***************************************************************************
Validation
-----------------------------------------
begin : 2012/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "rc_cmove.h"
#include "parameter.h"
#include "validation.h"
#include "Database.h"
#include "dbconnpool.h"
#include "Logger.h"
#include "ReportLog.h"
#define RECHK_TIMEOUT (24*60*60 * 1000000LL) // 1 day
static int64_t convert(string &s)
{
if (s.size() == 0)
return 0;
int64_t v = 0;
size_t i = 0;
char sign = (s[0] == '-' || s[0] == '+') ? (++i, s[0]) : '+';
for (; i < s.size(); ++i)
{
if (s[i] < '0' || s[i] > '9')
return 0;
v = v * 10 + s[i] - '0';
}
return sign == '-' ? -v : v;
}
CValidation::CValidation(JOB_TYPE::JOB_TYPE type, vector<string> & input)
: m_type(type), m_syncdata(input), m_first(true)
{
}
CValidation::~CValidation()
{
}
DataBase* CValidation::GetDB(string & tblname, bool & usedisplay)
{
ostringstream msg;
string s = m_syncdata[SYNCFILE_FIELD::slave_tran_id];
if (s.empty())
{
msg << "Service information empty.";
LOGACERR(LERR, msg);
return NULL;
}
DataBase* db = masterdbpool::getInstance()->GetConnFromPool();
tblname = masterdbpool::getInstance()->GetMetaTableName(s.c_str());
usedisplay = masterdbpool::getInstance()->UseDisplayname();
if (db == NULL)
{
msg << "DB POOL doesn't assign a database..";
LOGACERR(LERR, msg);
return NULL;
}
return db;
}
void CValidation::FreeDB(DataBase *db, bool success/* = true*/)
{
if (db)
{
masterdbpool::getInstance()->ReleaseConnToPool(db, success);
db = NULL;
}
}
vector<string> CValidation::Current2Sync(string sflag, vector<string>& curr)
{
vector<string> r(SYNCFILE_FIELD::MAX_FILED);
r[SYNCFILE_FIELD::flag] = sflag;
r[SYNCFILE_FIELD::uri] = curr[CURRENT_FIELD::uri];
r[SYNCFILE_FIELD::filename_hash] = curr[CURRENT_FIELD::filename_hash];
r[SYNCFILE_FIELD::resource_type] = curr[CURRENT_FIELD::resource_type];
r[SYNCFILE_FIELD::file_lastmodified] = curr[CURRENT_FIELD::file_lastmodified];
r[SYNCFILE_FIELD::deleted_yn] = curr[CURRENT_FIELD::deleted_yn];
r[SYNCFILE_FIELD::host_name] = curr[CURRENT_FIELD::host_name];
r[SYNCFILE_FIELD::creation_date] = curr[CURRENT_FIELD::creation_date];
r[SYNCFILE_FIELD::get_content_length] = curr[CURRENT_FIELD::get_content_length];
r[SYNCFILE_FIELD::get_content_type] = curr[CURRENT_FIELD::get_content_type];
r[SYNCFILE_FIELD::src_uri] = m_syncdata[SYNCFILE_FIELD::src_uri];
r[SYNCFILE_FIELD::slave_tran_id] = m_syncdata[SYNCFILE_FIELD::slave_tran_id];
r[SYNCFILE_FIELD::uri_ignore_case] = m_syncdata[SYNCFILE_FIELD::uri_ignore_case];
return r;
}
string CValidation::GetFullFilenamehash()
{
string r;
ostringstream msg;
if (m_syncdata[SYNCFILE_FIELD::resource_type] != TYPE_FILE)
{
msg << "[" << m_syncdata[SYNCFILE_FIELD::uri] << "] isn't file.";
LOGACOUT(LDBG, msg);
return r;
}
if (m_type == JOB_TYPE::COPY)
{
//m_syncdata[SYNCFILE_FIELD::filename_hash]
unsigned found = m_syncdata[SYNCFILE_FIELD::filename_hash].find_last_of("/");
string hash = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] +
m_syncdata[SYNCFILE_FIELD::filename_hash].substr(found);
if (m_fhsmount.size())
{
for (vector<string>::size_type i = 0; i < m_fhsmount.size(); ++i)
{
if (i > 0)
r += ",";
r += m_fhsmount[i] + hash;
}
}
else
{
msg << "FHS mount empty.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LWAR, msg);
r = m_syncdata[SYNCFILE_FIELD::filename_hash];
}
}
else
{
r = m_syncdata[SYNCFILE_FIELD::filename_hash];
}
r = StringReplace(r, "{", "\\{");
r = StringReplace(r, "}", "\\}");
r = "{" + r + "}";
msg << "Useing SQL filename_hash : " << m_syncdata[SYNCFILE_FIELD::filename_hash]
<< " => " << r;
LOGACOUT(LDBG, msg);
return r;
}
bool CValidation::GetCurrent(DataBase *db, string& tblname, bool useDisyplay /* = true */)
{
ostringstream sql,msg;
int index = 1;
sql << "SELECT ";
if (useDisyplay)
sql << "display_name, ";
else
sql << "uri, ";
sql << "filename_hash, resource_type, get_content_length, get_lastmodified, ";
sql << "file_lastmodified, deleted_yn, host_name, creation_date, get_content_type ";
sql << "FROM " << tblname << " ";
sql << "WHERE ";
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
{
index = 1;
sql << "filename_hash = ANY ($1) ";
}
else
{
index = 2;
sql << "depth = $1 ";
sql << "AND ";
if (useDisyplay && m_syncdata[SYNCFILE_FIELD::uri_ignore_case] == "Y")
sql << "uri = lower($2) ";
else
sql << "uri = $2 ";
}
if (m_type == JOB_TYPE::MOVE)
{
sql << "AND ";
sql << "host_name = $" << ++index << " ";
}
else
{
sql << "AND ";
sql << "is_cache = 'N' ";
}
sql << "AND ";
sql << "deleted_yn = 'N' ";
ostringstream t;
string struri = m_syncdata[SYNCFILE_FIELD::uri];
string strdepth;
string strhash = GetFullFilenamehash();
// depth 값 구하기. path : /tran_id/filename ( tran_id 제거된 count )
int nDEPTH = StringCount(struri, "/") - 1;
t << nDEPTH;
strdepth = t.str(); t.str("");
const char *paramValues[5];
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
{
index = 1;
paramValues[0] = strhash.c_str();
msg << " RCDB GetCurrent value : " << paramValues[0] << ",";
}
else
{
index = 2;
paramValues[0] = strdepth.c_str();
paramValues[1] = struri.c_str();
msg << paramValues[0] << "," << paramValues[1] << ",";
}
if (m_type == JOB_TYPE::MOVE)
{
paramValues[index++] = m_syncdata[SYNCFILE_FIELD::host_name].c_str();
msg << paramValues[index - 1] << ",INDEX (" << index << ")";
}
LOGACOUT(LDBG, msg);
msg << "SQL - " << sql.str();
LOGACOUT(LDBG, msg);
// Query 실행
db->PgDoExecParams((char*)sql.str().c_str(), index, paramValues);
// Query 결과를 가져온다.
int nResult = db->PgResult(DataBase::NOT_CLEAR);
if (nResult < 0)
{
msg << "RCDB GetCurrent failed : [" << db->GetErrorMessage() << "]";
LOGACERR(LERR, msg);
return false;
}
for (int i = 0; i < db->GetNoTuples(); ++i)
{
vector<string> vectcurr(CURRENT_FIELD::MAX_FILED);
vectcurr[CURRENT_FIELD::uri] = db->GetValue(i, CURRENT_FIELD::uri);
if (m_syncdata[SYNCFILE_FIELD::resource_type] == "0")
vectcurr[CURRENT_FIELD::filename_hash] = db->GetValue(i, CURRENT_FIELD::filename_hash);
vectcurr[CURRENT_FIELD::host_name] = db->GetValue(i, CURRENT_FIELD::host_name);
vectcurr[CURRENT_FIELD::resource_type] = db->GetValue(i, CURRENT_FIELD::resource_type);
vectcurr[CURRENT_FIELD::creation_date] = db->GetValue(i, CURRENT_FIELD::creation_date);
vectcurr[CURRENT_FIELD::get_content_length] = db->GetValue(i, CURRENT_FIELD::get_content_length);
vectcurr[CURRENT_FIELD::get_content_type] = db->GetValue(i, CURRENT_FIELD::get_content_type);
vectcurr[CURRENT_FIELD::get_lastmodified] = db->GetValue(i, CURRENT_FIELD::get_lastmodified);
vectcurr[CURRENT_FIELD::deleted_yn] = db->GetValue(i, CURRENT_FIELD::deleted_yn);
vectcurr[CURRENT_FIELD::file_lastmodified] = db->GetValue(i, CURRENT_FIELD::file_lastmodified);
m_current.insert(CCurretMap::value_type(vectcurr[CURRENT_FIELD::uri], vectcurr));
}
db->PgClear();
return true;
}
vector<string> CValidation::MakeFind()
{
vector<string> r;
string strtran = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id];
if (m_first && m_type == JOB_TYPE::COPY)
{
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
{
// 마스터 망에서 파일 수정일(get_lastmodified)이 해당 파일보다 작은 것이 없을 경우 src_uri 보내지 않음
if (m_syncdata[SYNCFILE_FIELD::src_uri].size())
{
string srcuri = strtran + m_syncdata[SYNCFILE_FIELD::src_uri];
r.push_back(srcuri);
}
}
}
string input = m_syncdata[SYNCFILE_FIELD::uri];
r.push_back(input);
return r;
}
int CValidation::IsAllow()
{
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_RECHK)
{
return 1;
}
int r = -1;
switch (m_type)
{
case JOB_TYPE::COPY:
{
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY
|| m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
r = 0;
}
break;
case JOB_TYPE::MOVE:
{
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
r = 0;
}
break;
default:
r = -2;
break;
}
return r;
}
void CValidation::FindZero(string & input, CSyncData & outSync)
{
ostringstream msg;
msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> FIND ZERO";
LOGACOUT(LDBG, msg);
string synctranid = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id];
string src = synctranid + m_syncdata[SYNCFILE_FIELD::src_uri];
// 다른 uri로 파일 존재하므로 검출된 데이터에 대해서 RECHK flag 설정
if (m_type == JOB_TYPE::COPY && m_first && m_current.size())
{
// RECHK
for (CCurretMap::iterator it = m_current.begin(); it != m_current.end(); ++it)
{
vector<string> newsync = Current2Sync(FLAG_RECHK, it->second);
if (input == newsync[SYNCFILE_FIELD::uri])
continue;
// input : destination
if (src == newsync[SYNCFILE_FIELD::uri])
continue;
// input : source
if (src == input)
continue;
if (m_syncdata[SYNCFILE_FIELD::src_uri].empty())
{
if (m_syncdata[SYNCFILE_FIELD::get_content_length] == newsync[SYNCFILE_FIELD::get_content_length])
{
string newsrc = newsync[SYNCFILE_FIELD::uri];
m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
}
}
//int64_t d = convert(it->second[CURRENT_FIELD::get_lastmodified]);
//if (longtime_now() - d > RECHK_TIMEOUT)
{
outSync.push_back(newsync);
msg << "Set RECHK....[" << newsync[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LDBG, msg);
}
}
}
// check
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
{
msg << "Does not process a request to delete a file because it does not exist currently. [" << input << "]";
LOGACOUT(LINF, msg);
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
{
// 해당 파일과 동일한 파일 존재 확인
if (m_first)
{
for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
{
if ((*it)[SYNCFILE_FIELD::flag] == FLAG_RECHK)
{
if ((*it)[SYNCFILE_FIELD::get_content_length] == m_syncdata[SYNCFILE_FIELD::get_content_length])
{
string newsrc = (*it)[SYNCFILE_FIELD::uri];
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_COPY;
m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
break;
}
}
}
}
outSync.push_back(m_syncdata);
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
{
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
{
msg << "Because the file does not exist, "
<< "change the physical synchronization from the logical synchronization. ["
<< input << "]";
LOGACOUT(LINF, msg);
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
}
if (m_syncdata[SYNCFILE_FIELD::resource_type] == TYPE_DIR)
{
msg << "Create DIR. [" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LDBG, msg);
m_syncdata[SYNCFILE_FIELD::host_name] = "";
}
outSync.push_back(m_syncdata);
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY )
{
if (input == src)
{
vector<string> newsync = m_syncdata;
newsync[SYNCFILE_FIELD::flag] = FLAG_SYNC;
newsync[SYNCFILE_FIELD::uri] = src;
outSync.push_back(newsync);
}
else
{
if (m_syncdata[SYNCFILE_FIELD::src_uri].empty())
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
outSync.push_back(m_syncdata);
}
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
{
if (m_type == JOB_TYPE::MOVE)
{
msg << "Because the file does not exist, can not be transferred. [" << input << "]";
LOGACOUT(LINF, msg);
}
else
{
if (input == src)
{
// Nothing
msg << "The source file does not exist, Nothing... [" << input << "]";
LOGACOUT(LDBG, msg);
}
else
{
if (m_first)
{
bool findsrc = false;
for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
{
if ((*it)[SYNCFILE_FIELD::flag] == FLAG_RECHK)
{
if ((*it)[SYNCFILE_FIELD::uri] == src)
{
findsrc = true;
outSync.erase(it);
break;
}
// 해당 소스와 동일한 uri 존재하지 하지 않지만 동일한 파일로 다른 uri 존재할 수 있으므로
// 해당 파일을 소스 파일로 하는 copy 본 생성함
// 소스로 선정된 파일은 RECHK 옵션에 의해서 재처리됨
if ((*it)[SYNCFILE_FIELD::get_content_length] == m_syncdata[SYNCFILE_FIELD::get_content_length])
{
findsrc = true;
string newsrc = (*it)[SYNCFILE_FIELD::uri];
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_COPY;
m_syncdata[SYNCFILE_FIELD::host_name] = (*it)[SYNCFILE_FIELD::host_name];
m_syncdata[SYNCFILE_FIELD::src_uri] = newsrc.substr(synctranid.size());
break;
}
}
}
// 소스 존재 하지 않을 경우 SYNC로 변경
if (findsrc == false)
{
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
}
outSync.push_back(m_syncdata);
}
else
{
outSync.push_back(m_syncdata);
}
}
}
}
else
{
msg << "Unknown flag.[" << m_syncdata[SYNCFILE_FIELD::flag] << ":";
msg << input;
msg << "]";
LOGACERR(LERR, msg);
return;
}
}
void CValidation::FindOne(vector<string> f, CSyncData & outSync)
{
ostringstream msg;
string input = f[CURRENT_FIELD::uri];
string src = "/" + m_syncdata[SYNCFILE_FIELD::slave_tran_id] + m_syncdata[SYNCFILE_FIELD::src_uri];
msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> FIND IT";
LOGACOUT(LDBG, msg);
// 다른 uri로 파일 존재하므로 검출된 데이터에 대해서 RECHK flag 설정
if (m_type == JOB_TYPE::COPY && m_first && m_current.size() > 1)
{
// RECHK
for (CCurretMap::iterator it = m_current.begin(); it != m_current.end(); ++it)
{
vector<string> newsync = Current2Sync(FLAG_RECHK, it->second);
if (input == newsync[SYNCFILE_FIELD::uri])
continue;
// input : destination
if (src == newsync[SYNCFILE_FIELD::uri])
continue;
// input : source
if (src == input)
continue;
//int64_t d = convert(it->second[CURRENT_FIELD::get_lastmodified]);
//if (longtime_now() - d > RECHK_TIMEOUT)
{
outSync.push_back(newsync);
msg << "Set RECHK(1)....[" << newsync[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LDBG, msg);
}
}
}
bool in2sync = false;
// check
if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_DEL)
{
in2sync = true;
if (m_first && m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
{
msg << "uri same but size different. change flag(RECHK).[" << input << "]";
LOGACOUT(LDBG, msg);
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_RECHK;
}
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_SYNC)
{
in2sync = true;
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
{
if (m_first)
{
msg << "uri same but size different. new syncdata(DEL) create.[" << input << "]";
LOGACOUT(LINF, msg);
vector<string> newsync = Current2Sync(FLAG_DEL, f);
outSync.push_back(newsync);
}
}
else if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
{
if (m_first)
{
msg << "uri same but file_lastmodified different. new syncdata(NSYNC) create.[" << input << "]";
LOGACOUT(LINF, msg);
vector<string> newsync = Current2Sync(FLAG_NSYNC, f);
newsync[SYNCFILE_FIELD::file_lastmodified] = m_syncdata[SYNCFILE_FIELD::file_lastmodified];
outSync.push_back(newsync);
}
}
else
{
in2sync = false;
msg << "Information all same. not synchronized.[" << input << "]";
LOGACOUT(LDBG, msg);
}
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_NSYNC)
{
if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
{
in2sync = true;
if (f[CURRENT_FIELD::resource_type] == TYPE_DIR)
m_syncdata[SYNCFILE_FIELD::host_name] = f[CURRENT_FIELD::host_name];
}
if (f[CURRENT_FIELD::resource_type] == TYPE_FILE)
{
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
{
if (m_first)
{
msg << "uri same but size(or file_lastmodified) different. new syncdata(DEL) create.["
<< input << "]";
LOGACOUT(LINF, msg);
vector<string> newsync = Current2Sync(FLAG_DEL, f);
outSync.push_back(newsync);
}
else
{
msg << "Change flag NSYNC to SYNC. [" << input << "]";
LOGACOUT(LDBG, msg);
m_syncdata[SYNCFILE_FIELD::flag] = FLAG_SYNC;
}
}
}
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_COPY)
{
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
{
if (m_first)
{
msg << "uri same but size different. new syncdata(DEL) create.["
<< input << "]";
LOGACOUT(LINF, msg);
vector<string> newsync = Current2Sync(FLAG_DEL, f);
outSync.push_back(newsync);
if (input == src)
{
msg << "uri same but size different. new syncdata(SYNC) create.["
<< input << "]";
LOGACOUT(LINF, msg);
newsync = Current2Sync(FLAG_SYNC, f);
outSync.push_back(newsync);
}
else
in2sync = true;
}
else
in2sync = true;
}
else if (m_syncdata[SYNCFILE_FIELD::file_lastmodified] != f[CURRENT_FIELD::file_lastmodified])
{
if (m_first)
{
if (input != src)
{
vector<string> newsync = Current2Sync(FLAG_NSYNC, f);
newsync[SYNCFILE_FIELD::file_lastmodified] = m_syncdata[SYNCFILE_FIELD::file_lastmodified];
outSync.push_back(newsync);
}
}
}
else
{
// nothing
}
}
else if (m_syncdata[SYNCFILE_FIELD::flag] == FLAG_MOVE)
{
if (m_type == JOB_TYPE::MOVE)
{
in2sync = true;
}
else
{
if (m_syncdata[SYNCFILE_FIELD::get_content_length] != f[CURRENT_FIELD::get_content_length])
{
if (m_first)
{
msg << "uri same but size different. new syncdata(DEL) create.["
<< input << "]";
LOGACOUT(LINF, msg);
vector<string> newsync = Current2Sync(FLAG_DEL, f);
outSync.push_back(newsync);
}
if (input != src)
{
msg << "uri same but size different. new syncdata(SYNC) create.["
<< input << "]";
LOGACOUT(LINF, msg);
vector<string> newsync = Current2Sync(FLAG_SYNC, f);
outSync.push_back(newsync);
}
}
else
{
if (input == src)
{
vector<string> newsync = Current2Sync(FLAG_RECHK, f);
outSync.push_back(newsync);
}
else
{
for (CSyncData::iterator it = outSync.begin(); it != outSync.end(); ++it)
{
if ((*it)[SYNCFILE_FIELD::uri] == src )
{
// 소스 존재하고 복사된 파일도 존재하면 소스 삭제 처리
(*it)[SYNCFILE_FIELD::flag] = FLAG_DEL;
break;
}
}
}
}
}
}
else
{
msg << "Unknown flag.[" << m_syncdata[SYNCFILE_FIELD::flag] << ":";
msg << input;
msg << "]";
LOGACERR(LERR, msg);
return;
}
// input to sync data
if (in2sync)
{
outSync.push_back(m_syncdata);
}
}
void CValidation::FindOver(pair<CCurretMap::iterator, CCurretMap::iterator> &f, CSyncData & outSync)
{
ostringstream msg;
//f.first
CCurretMap::iterator vf = f.first;
string input = (*vf).second[CURRENT_FIELD::uri];
msg << "FALG::" << m_syncdata[SYNCFILE_FIELD::flag] << "-" << input << " ==> DUPLICATE";
LOGACOUT(LDBG, msg);
CReportLog rlog;
if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
{
rlog.Write("NOT", "[%s] [The duplicate files.[uri :%s]]", PROG_NAME, input.c_str());
}
}
bool CValidation::CompareData(DataBase *db, string& tblname,
vector<string> & vecFind, CSyncData & outSync)
{
bool r = true;
ostringstream msg;
msg << "FIND vector Size : " << vecFind.size();
LOGACOUT(LDBG, msg);
while (vecFind.size())
{
string input = vecFind.front();
msg << "FIND input : " << input;
LOGACOUT(LDEV1, msg);
pair<CCurretMap::iterator, CCurretMap::iterator> f = m_current.equal_range(input);
CCurretMap::const_iterator ff = f.first;
if (f.first == m_current.end())
{
// find zero
FindZero(input, outSync);
}
else if (++ff == f.second)
{
// find one
CCurretMap::iterator v = f.first;
FindOne((*v).second, outSync);
}
else
{
// find one over
FindOver(f, outSync);
return false;
}
vecFind.erase(vecFind.begin());
}
return r;
}
int CValidation::CheckData(bool first, CSyncData & outSync)
{
DataBase* db = NULL;
string tblname;
bool usedisp = true;
ostringstream msg;
m_first = first;
// check allow
switch (IsAllow())
{
case 0: // Allow
msg << "ALLOW Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LDEV2, msg);
break;
case 1: // SKIP
msg << "SIKP Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LDBG, msg);
outSync.push_back(m_syncdata);
return 0;
break;
default: // Deny
msg << "DENY Validation.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LERR, msg);
return -10;
break;
}
// Get DB
db = GetDB(tblname, usedisp);
if (db == NULL)
return -1;
int r = 0;
do
{
// Get Current
if (GetCurrent(db, tblname, usedisp) == false)
{
r = -2;
break;
}
// Make Find URI
vector<string> vecfind = MakeFind();
if (vecfind.empty())
{
r = -3;
msg << "Not Found 'FIND URI'.[" << m_syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LERR, msg);
break;
}
// compare
if (CompareData(db, tblname, vecfind, outSync) == false)
{
r = -4;
break;
}
} while (false);
// Free DB
FreeDB(db, (r != -2));
return r;
}
+84
View File
@@ -0,0 +1,84 @@
/***************************************************************************
Validation
-----------------------------------------
begin : 2012/05/14
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __VALIDATION_H__
#define __VALIDATION_H__
#include <vector>
# if __GNUC__ >= 3
# include <ext/hash_map>
using namespace __gnu_cxx;
# else
# include <hash_map>
# endif
struct hash_key2
{
size_t operator() (const string &k) const
{
return __stl_hash_string(k.c_str());
}
};
struct compare_key2
{
bool operator () (const string s1, const string &s2) const
{
return s1 == s2;
}
};
typedef hash_multimap<string, vector<string>, hash_key2, compare_key2> CCurretMap;
class DataBase;
class CValidation
{
public:
CValidation(JOB_TYPE::JOB_TYPE type, vector<string> & input);
~CValidation();
int CheckData(bool first, CSyncData & outSync);
void SetFHSMount(vector<string>& fhs) { m_fhsmount = fhs; }
private:
bool CompareData(DataBase *db, string& tblname,
vector<string> & vecFind, CSyncData & outSync);
int IsAllow();
vector<string> MakeFind();
void FindZero(string & inuri, CSyncData & outSync);
void FindOne(vector<string> f, CSyncData & outSync);
void FindOver(pair<CCurretMap::iterator, CCurretMap::iterator> &f, CSyncData & outSync);
bool GetCurrent(DataBase *db, string& tblname, bool useDisyplay = true);
vector<string> Current2Sync(string sflag, vector<string>& curr);
string GetFullFilenamehash();
void FreeDB(DataBase *db, bool success = true);
DataBase* GetDB(string& tblname, bool & usedisplay);
JOB_TYPE::JOB_TYPE m_type;
vector<string> m_syncdata;
vector<string> m_fhsmount;
CCurretMap m_current;
bool m_first;
};
#endif // __VALIDATION_H__
+710
View File
@@ -0,0 +1,710 @@
/***************************************************************************
Work Pool
-----------------------------------------
begin : 2012/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "rc_cmove.h"
#include "workpool.h"
#include "validation.h"
#include "synchronization.h"
#include "parameter.h"
#include "Logger.h"
#include "ReportLog.h"
#include <fcntl.h> /* For O_* constants */
#include <sys/stat.h> /* For mode constants */
#ifdef _USE_POSIX_SEMAPHORES
#include <semaphore.h>
#elif defined(_USE_POSIX_LOCK)
#ifndef O_CLOEXEC
// kernel 2.6.23 부터 지원
#define O_CLOEXEC 0
#endif // !O_CLOEXEC
#endif // _USE_POSIX_SEMAPHORES
#define SLEEP_TIME 1000 //microsecond
workpool *workpool::m_inst = NULL;
// work
work::work()
: m_step(-5), m_exit(false), m_enablesync("0000"), m_networkmode(false)
{
m_nofi = NULL;
pthread_mutex_init(&m_workmutex, NULL);
pthread_cond_init(&m_workcond, NULL);
#ifdef _USE_POSIX_SEMAPHORES
m_worksem = NULL;
#elif defined (_USE_POSIX_LOCK)
m_workfd = -1;
#endif // _USE_POSIX_SEMAPHORES
}
work::~work()
{
pthread_mutex_destroy(&m_workmutex);
pthread_cond_destroy(&m_workcond);
}
void* work::working(void * pdata)
{
ostringstream msg;
work* pObject = reinterpret_cast<work *>(pdata);
//pthread_detach( pthread_self() );
#ifdef _DEBUG
cout << "work::working start - " << pthread_self() << endl;
#endif // _DEBUG
while(pObject->m_exit == false)
{
pthread_mutex_lock(&pObject->m_workmutex);
pObject->m_step = -1;
int err = pthread_cond_wait(&pObject->m_workcond, &pObject->m_workmutex);
pObject->m_step = 0;
#ifdef _DEBUG
cerr << "work::working - signal : " << pthread_self() << "," << pObject->m_exit << endl;
#endif // _DEBUG
if ( err == 0 && pObject->m_exit == false)
{
pObject->m_step = 1;
vector<string> input;
CSyncData syncdata;
StringSplit(pObject->m_rundata, "|", input, true);
if (input.size() == SYNCFILE_FIELD::MAX_FILED) {
// 서비스 간 동기화 경우 tran_id 제거된 uri 사용하므로
// 이 후 사용될 로직에서 편의성을 위해서 tran_id를 붙혀넣음
if (pObject->m_type == JOB_TYPE::COPY)
input[SYNCFILE_FIELD::uri] = "/" + input[SYNCFILE_FIELD::slave_tran_id] + input[SYNCFILE_FIELD::uri];
syncdata.push_back(input);
pObject->RunWork(syncdata);
}
else {
msg << "validation sync file string split caution : [" << pObject->m_rundata << "]";
if (pObject->m_nofi)
{
pObject->m_nofi(pObject->m_parm, -1);
}
CReportLog rlog;
if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
{
rlog.Write("NOT", "[%s] [%s]", PROG_NAME, msg.str().c_str());
}
LOGACERR(LERR, msg);
}
}
else
{
pObject->m_step = -3;
if(pObject->m_exit == false)
{
pObject->m_step = -4;
msg << "Work Thread Error.";
LOGACERR(LCRT, msg);
if (pObject->m_nofi)
{
pObject->m_nofi(pObject->m_parm, -1);
}
}
else
{
pObject->m_step = -5;
/* nothing -- signal exit */
}
}
workpool::getInstance()->ReleaseWork(pObject);
pObject->m_step = -6;
pthread_mutex_unlock(&pObject->m_workmutex);
}
#ifdef _DEBUG
cerr << "work::working end - " << pthread_self() << endl;
#endif // _DEBUG
return NULL;
}
bool work::init()
{
int nRet = pthread_create(&m_thread, 0, work::working, this);
if( nRet )
{
cerr << "Thread create failed.: errno: " << errno << endl;
return false;
}
srand(time(NULL));
solusleep(100);
return true;
}
void work::setexit(bool v)
{
m_exit = v;
pthread_mutex_lock(&m_workmutex);
pthread_cond_signal(&m_workcond);
pthread_mutex_unlock(&m_workmutex);
}
void work::settargethost(vector<string>& targethost)
{
m_vectargethost.clear();
m_vectargethost.resize(targethost.size());
copy( targethost.begin(), targethost.end(), m_vectargethost.begin() );
}
bool work::run(JOB_TYPE::JOB_TYPE type, string rundata, work_notifyfn nofi /* = NULL */, void * parm /* = NULL */)
{
m_type = type;
m_rundata = rundata;
m_nofi = nofi;
m_parm = parm;
ostringstream msg;
msg << "Work Run : Sync Data - " << m_rundata;
_LOGACOUT(LDBG, msg);
//spin lock
int64_t looptime = 0;
do
{
solusleep(SLEEP_TIME);
looptime += SLEEP_TIME;
if( looptime > (10 *1000*1000) )
{
msg << "Work Loop.... 10 sec over :" << m_rundata;
_LOGACOUT(LNOT, msg);
break;
}
} while (m_step != -1);
pthread_cond_signal(&m_workcond);
return true;
}
int work::RunWork(CSyncData &syncdata)
{
int r = 0;
short success = 0;
ostringstream msg;
msg << "RunWork Start : " << m_rundata;
_LOGACOUT(LDEV2, msg);
bool first = true;
while (m_exit == false && !syncdata.empty())
{
vector<string> input = syncdata.front();
syncdata.erase(syncdata.begin());
string workhash;
if (workpool::getInstance()->addworkuri(input, workhash, 180) == false)
{
msg << "Failed RunWork (add working uri) : " << m_rundata;
success = -100;
_LOGACOUT(LERR, msg);
break;
}
#ifdef _USE_POSIX_LOCK
string strlockhome = "/tmp/";
string strlock;
#endif // _USE_POSIX_LOCK
do
{
// 프로세스 간 동화 목적
#ifdef _USE_POSIX_SEMAPHORES
// lock
if ((m_worksem = sem_open(workhash.c_str(), O_CREAT, 0777, 1)) == SEM_FAILED)
{
success = -101;
sem_unlink(workhash.c_str());
msg << "Sem Open Error. [" << m_rundata << "]";
_LOGACOUT(LERR, msg);
break;
}
sem_unlink(workhash.c_str());
// KILL(-9) 로 프로세스 죽을 경우 block 걸림
sem_wait(m_worksem);
#elif defined(_USE_POSIX_LOCK)
strlock = strlockhome + workhash;
m_workfd = open( strlock.c_str(), O_RDWR | // open the file for both read and write access
O_CREAT // create file if it does not already exist
| O_CLOEXEC // close on execute
,S_IRUSR | // user permission: read
S_IWUSR ); // user permission: write
if (m_workfd < 0)
{
success = -102;
msg << "lockf open fail. [" << m_rundata << "] [" << strlock << "] errno [" << errno << "]";
_LOGACOUT(LERR, msg);
m_workfd = -1;
break;
}
// 2015.01.15 dadamin
// EDEADLK 발생으로 중복 파일 발생하기 때문에 에러시 실패 처리함
int l = lockf(m_workfd, F_TLOCK, 0);; // lock the "semaphore"
if (l == -1)
{
success = -102;
msg << "lockf fail. [" << m_rundata << "] [" << strlock << "] errno [" << errno << "]";
_LOGACOUT(LERR, msg);
break;
}
#endif // # _USE_POSIX_SEMAPHORES
// validation
m_step = 3;
CSyncData outsync;
success = validation(first, input, outsync);
if (success != 0)
break;
if (outsync.empty())
{
LOG(LINF, "There is no data to work with Synchronization.[%s]", m_rundata.c_str());
break;
}
// diff work uri & return uri
vector<string> verified = outsync.front();
if (verified.empty())
{
success = -101;
LOG(LCRT, "Empty Synchronization Data.[%s]", m_rundata.c_str());
break;
}
string reuri = verified[SYNCFILE_FIELD::uri];
if (input[SYNCFILE_FIELD::uri] != reuri)
{
if (first)
{
first = false;
syncdata.clear();
syncdata = outsync;
LOG(LDBG, "ReWork... [%s]", m_rundata.c_str());
}
else
{
LOG(LCRT, "The other uri returned by tried again.[%s]",
reuri.c_str());
}
break;
}
//synchronization
m_step = 4;
success = synchronization(verified);
if (success != 0)
break;
} while (false);
#ifdef _USE_POSIX_SEMAPHORES
if (m_worksem)
{
sem_post(m_worksem);
solusleep(SLEEP_TIME);
sem_close(m_worksem);
//sem_unlink(workhash.c_str());
m_worksem = NULL;
}
#elif defined(_USE_POSIX_LOCK)
if(m_workfd != -1)
{
if (lockf(m_workfd, F_TEST, 0) < 0) {
//unlink(strlock.c_str());
int eno = errno;
if (eno == EACCES || eno == EAGAIN) {
//lockf(m_workfd, F_ULOCK, 0);
}
} else {
if (success == 0) {
unlink(strlock.c_str());
}
}
close(m_workfd);
m_workfd = -1;
}
#endif // _USE_POSIX_SEMAPHORES
workpool::getInstance()->delworkuri(workhash);
if (success != 0)
break;
}
if (m_nofi)
{
m_step = 6;
#ifdef _DEBUG
cerr << "Work Thread Notify Call." << endl;
#endif //_DEBUG
m_nofi(m_parm, success);
}
m_step = 7;
msg << "RunWork End : " << m_rundata;
_LOGACOUT(LDEV2, msg);
return r;
}
int work::validation(bool first, vector<string> &input, CSyncData &syncdata)
{
ostringstream msg;
msg << "Valid Start :" << input[SYNCFILE_FIELD::uri];
_LOGACOUT(LDBG, msg);
CValidation validate(m_type, input);
validate.SetFHSMount(parameter::getInstance()->getfhsmount());
int r = validate.CheckData(first, syncdata);
return r;
}
int work::synchronization(vector<string>& verified)
{
ostringstream msg;
if (verified.size() != SYNCFILE_FIELD::MAX_FILED)
{
msg << "synchronization data string split caution : [" << m_rundata << "]";
LOGACERR(LERR, msg);
return -105;
}
CSynchronization sync(m_type, verified);
sync.SetTragetHost(m_vectargethost);
sync.SetEnable(m_enablesync.c_str());
sync.SetNetworkMode(m_networkmode);
sync.SetFHSMount(parameter::getInstance()->getfhsmount());
int r = sync.Execute();
return r;
}
// work pool
workpool::workpool()
{
pthread_mutex_init(&m_mutex, NULL);
pthread_mutex_init(&m_mutexuri, NULL);
pthread_mutex_init(&m_mutextry, NULL);
}
workpool::~workpool()
{
pthread_mutex_destroy(&m_mutex);
pthread_mutex_destroy(&m_mutexuri);
pthread_mutex_destroy(&m_mutextry);
}
workpool* workpool::getInstance()
{
if(workpool::m_inst == NULL)
{
workpool::m_inst = new workpool();
}
return workpool::m_inst;
}
void workpool::release()
{
if( workpool::m_inst != NULL)
{
m_inst->DestroyPool();
delete workpool::m_inst;
workpool::m_inst = NULL;
}
}
int workpool::CreatePool( int poolcnt /* = 10 */ )
{
// pool
for(int i=0 ; i < poolcnt ; i++)
{
srand ( time(NULL) );
work * w = new work();
if( w->init() == false)
{
delete w;
break;
}
//m_pool.insert(make_pair(w, workpool::NOTWORK));
m_pool.insert(pair<work *,short>(w, workpool::NOTWORK));
}
if( m_pool.size() < static_cast<unsigned int>(poolcnt) )
{
DestroyPool();
return -1;
}
return 0;
}
int workpool::DestroyPool()
{
map<work*, short>::iterator iter;
while(m_pool.size() > 0 )
//for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
{
iter = m_pool.begin();
if(iter->second == workpool::NOTWORK)
{
work *data = static_cast<work *>(iter->first);
data->setexit(true);
pthread_join(*data->getworkhandle(), NULL);
m_pool.erase(iter);
delete (work *) data;
}
//sleep(1);
}
//m_pool.clear();
return m_pool.size();
}
work* workpool::GetWorkPool(int timeout)
{
work * r = NULL;
int64_t usetime = 0;
int64_t out = timeout * 1000 * 1000;
do
{
pthread_mutex_lock(&m_mutex);
map<work*, short>::iterator iter;
for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
{
if(iter->second == workpool::NOTWORK)
{
iter->second = workpool::WORKING;
r = iter->first;
break;
}
}
if( r == NULL )
{
solusleep(SLEEP_TIME);
if( out > 0 )
{
usetime += SLEEP_TIME;
if( usetime > out)
{
ostringstream msg;
msg << "Get Work Pool Timeout.";
LOGACERR(LERR, msg);
pthread_mutex_unlock(&m_mutex);
break;
}
}
}
pthread_mutex_unlock(&m_mutex);
} while (r == NULL);
return r;
}
void workpool::ReleaseWork(work *w)
{
//pthread_mutex_lock(&m_mutex);
map<work*, short>::iterator iter = m_pool.find(w);
if( iter != m_pool.end() )
{
if(iter->second==workpool::WORKING)
iter->second=workpool::NOTWORK;
}
else
{
ostringstream msg;
msg << "unknown work pool.";
LOGACERR(LWAR, msg);
}
//pthread_mutex_unlock(&m_mutex);
}
void workpool::printstatus(string prefixed)
{
int w = 0, n = 0;
map<work*, short>::iterator iter;
for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
{
if(iter->second == workpool::NOTWORK)
{
++n;
}
else
{
++w;
}
}
ostringstream msg;
if( prefixed.empty() == false )
msg << "[" << prefixed << "]";
msg << "Work Pool - " <<"total : " << m_pool.size() << "(" << w <<
"/" << n << ")";
_LOGACOUT(LINF, msg);
}
void workpool::printstatusex(string prefixed)
{
ostringstream msg;
map<work*, short>::iterator iter;
for( iter = m_pool.begin(); !m_pool.empty()&& iter != m_pool.end(); iter++ )
{
if(iter->second == workpool::NOTWORK)
{
msg << "Work Pool(NOTWORK) - " << iter->first->getrundata() << "," <<
iter->first->getsetp();
}
else
{
msg << "Work Pool(WORKING) - " << iter->first->getrundata() << "," <<
iter->first->getsetp();
}
if( prefixed.empty() == false )
msg << "[" << prefixed << "]";
_LOGACOUT(LINF, msg);
}
}
bool workpool::addworkuri(vector<string>& syncdata, string &workkey, int timeout)
{
bool r = true;
string key;
ostringstream msg;
if (syncdata[SYNCFILE_FIELD::uri].empty() || syncdata[SYNCFILE_FIELD::slave_tran_id].empty() )
{
msg << "addworkuri uri(or thran_id) empty caution.";
LOGACERR(LERR, msg);
return false;
}
string shash;
if (syncdata[SYNCFILE_FIELD::resource_type] == TYPE_FILE)
{
if ( syncdata[SYNCFILE_FIELD::filename_hash].empty())
{
msg << "addworkuri filename_hash empty caution.";
LOGACERR(LERR, msg);
CReportLog rlog;
if (rlog.Init(parameter::getInstance()->getlogpath().c_str()))
{
rlog.Write("ERR", "[%s] [failed work filename_hash empty caution.[uri :%s]]", PROG_NAME, syncdata[SYNCFILE_FIELD::uri].c_str());
}
return false;
}
size_t found = syncdata[SYNCFILE_FIELD::filename_hash].find_last_of("/");
if (found != string::npos)
{
shash = syncdata[SYNCFILE_FIELD::filename_hash].substr(found + 1);
}
else
{
msg << "addworkuri not found '/'.[uri: " << syncdata[SYNCFILE_FIELD::uri] << "]";
LOGACOUT(LWAR, msg);
}
}
if (shash.empty())
{
ostringstream t;
size_t h = __stl_hash_string(syncdata[SYNCFILE_FIELD::uri].c_str());
t << h;
shash = t.str();
}
key = syncdata[SYNCFILE_FIELD::slave_tran_id] + "." + shash;
int64_t out = 0, usetime = 0;
out = timeout * 1000 * 1000;
TRY_ADD_WORK_URI:
pthread_mutex_lock(&m_mutexuri);
workurimap::iterator find = m_workurimap.find(key);
if (find != m_workurimap.end())
{
pthread_mutex_unlock(&m_mutexuri);
msg << "Work uri duplication occurred and to add work uri try again." << key;
LOGACOUT(LDEV2, msg);
// try
solusleep(SLEEP_TIME);
usetime += SLEEP_TIME;
if(timeout > 0 && usetime > out)
{
r = false;
msg << "Work adduri Timeout." << key;
LOGACERR(LERR, msg);
pthread_mutex_unlock(&m_mutexuri);
return false;
}
goto TRY_ADD_WORK_URI;
}
else
{
// add
workkey = key;
m_workurimap[key] = 1;
//pthread_mutex_unlock(&m_mutexuri);
msg << "Add Work. ######### " << key;
LOGACOUT(LDBG, msg);
}
pthread_mutex_unlock(&m_mutexuri);
return r;
}
bool workpool::delworkuri(string key)
{
pthread_mutex_lock(&m_mutexuri);
// deleted
m_workurimap.erase(key);
pthread_mutex_unlock(&m_mutexuri);
return true;
}
+135
View File
@@ -0,0 +1,135 @@
/***************************************************************************
Work Pool
-----------------------------------------
begin : 2012/05/13
copyright : (C) 2011 SolutionBox Inc.
author : Service 1 Team
email : svc1@solbox.com
version : 3.1.0
CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
Redistribution and use in source and binary forms, with or with out
modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#ifndef __WORK_POOL_H__
#define __WORK_POOL_H__
#include <semaphore.h>
# if __GNUC__ >= 3
# include <ext/hash_map>
using namespace __gnu_cxx;
# else
# include <hash_map>
# endif
typedef int (*work_notifyfn)(void *object, short success);
struct hash_key
{
size_t operator() (const string &k) const
{
return __stl_hash_string(k.c_str());
}
};
struct compare_key
{
bool operator () (const string s1, const string &s2) const
{
return s1 == s2;
}
};
typedef hash_map<string, short, hash_key, compare_key> workurimap;
class work
{
public:
work();
~work();
bool init();
bool run(JOB_TYPE::JOB_TYPE type, string rundata, work_notifyfn nofi = NULL, void * parm = NULL);
void setexit(bool v);
void setenablesync(const char* szOn) {m_enablesync = szOn;}
void setnetworkmode(int mode) {m_networkmode = mode;}
void settargethost(vector<string>& targethost);
pthread_t* getworkhandle() {return &m_thread;}
const char* getrundata() { return m_rundata.c_str(); }
int getsetp() { return m_step; }
private:
static void* working(void * pdata);
int RunWork(CSyncData &syncdata);
int validation(bool first, vector<string> &input, CSyncData &syncdata);
int synchronization(vector<string>& verified);
private:
int m_step;
bool m_exit;
JOB_TYPE::JOB_TYPE m_type;
string m_rundata;
work_notifyfn m_nofi;
void* m_parm;
string m_enablesync;
int m_networkmode;
vector<string> m_vectargethost;
pthread_t m_thread;
pthread_cond_t m_workcond;
pthread_mutex_t m_workmutex;
#ifdef _USE_POSIX_SEMAPHORES
sem_t *m_worksem;
#elif defined (_USE_POSIX_LOCK)
int m_workfd;
#endif // _USE_POSIX_SEMAPHORES
};
class workpool
{
public:
enum WORK_SATAUSE
{
WORKING = 0,
NOTWORK = 1
};
public:
static void init();
static workpool* getInstance();
static void release();
int CreatePool( int poolcnt = 10 );
int DestroyPool();
bool addworkuri(vector<string>& syncdata, string &hash, int timeout = 5);
bool delworkuri(string key);
void printstatus(string prefixed = "");
void printstatusex(string prefixed = "");
work* GetWorkPool(int timeout = 0);
void ReleaseWork(work *w);
private:
workpool();
~workpool();
private:
static workpool* m_inst;
pthread_mutex_t m_mutex;
pthread_mutex_t m_mutexuri;
pthread_mutex_t m_mutextry;
workurimap m_workurimap;
map<work*, short> m_pool;
};
#endif // __WORK_POOL_H__